PageRenderTime 71ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 1ms

/src/common/outbound.cpp

https://bitbucket.org/ZachThibeau/pchat-irc
C++ | 4323 lines | 3628 code | 531 blank | 164 comment | 772 complexity | a58c9f02e7870bf087ca9704557a5602 MD5 | raw file
Possible License(s): GPL-2.0

Large files files are truncated, but you can click here to view the full file

  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. #ifdef __GNUC__
  32. #include <unistd.h>
  33. #endif
  34. #include <time.h>
  35. #include <signal.h>
  36. #include <sys/stat.h>
  37. #include <fcntl.h>
  38. #include "xchat.h"
  39. #include "xchatc.h"
  40. #include "outbound.h"
  41. #include "cfgfiles.h" // xchat_fopen_file()
  42. #include "chanopt.h"
  43. #include "dcc.h"
  44. #include "fe.h"
  45. #include "ignore.h"
  46. #include "inbound.h"
  47. #include "modes.h"
  48. #include "network.h" // net_ip()
  49. #include "notify.h"
  50. #include "plugin.h"
  51. #include "server.h"
  52. #include "servlist.h"
  53. #include "text.h"
  54. #include "tree.h"
  55. #include "userlist.h"
  56. #include "util.h"
  57. #ifdef USE_DEBUG
  58. extern int current_mem_usage;
  59. #endif
  60. #define TBUFSIZE 4096
  61. static void help(session *sess, char *tbuf, char *helpcmd, int quiet);
  62. static int cmd_server(session *sess, char *tbuf, char *word[], char *word_eol[]);
  63. static void handle_say(session *sess, char *text, int check_spch);
  64. static void notj_msg(session *sess)
  65. {
  66. PrintText(sess, _("No channel joined. Try /join #<channel>\n"));
  67. }
  68. void notc_msg(session *sess)
  69. {
  70. PrintText(sess, _("Not connected. Try /server <host> [<port>]\n"));
  71. }
  72. static char* random_line(char *file_name)
  73. {
  74. FILE *fh;
  75. char buf[512];
  76. int lines, ran;
  77. if (!file_name[0])
  78. goto nofile;
  79. fh = xchat_fopen_file(file_name, "r", 0);
  80. if (!fh)
  81. {
  82. nofile:
  83. // reason is not a file, an actual reason!
  84. return strdup(file_name);
  85. }
  86. // count number of lines in file
  87. lines = 0;
  88. while (fgets(buf, sizeof(buf), fh))
  89. lines++;
  90. if (lines < 1)
  91. goto nofile;
  92. // go down a random number
  93. rewind(fh);
  94. ran = RAND_INT(lines);
  95. do
  96. {
  97. fgets(buf, sizeof(buf), fh);
  98. lines--;
  99. }
  100. while (lines > ran);
  101. fclose(fh);
  102. buf[strlen(buf) - 1] = 0; // remove the trailing '\n'
  103. return strdup(buf);
  104. }
  105. void server_sendpart(server* serv, char *channel, char *reason)
  106. {
  107. if (!reason)
  108. {
  109. reason = random_line(prefs.partreason);
  110. serv->p_part(serv, channel, reason);
  111. free(reason);
  112. }
  113. else
  114. {
  115. // reason set by /quit, /close argument
  116. serv->p_part(serv, channel, reason);
  117. }
  118. }
  119. void server_sendquit(session* sess)
  120. {
  121. char *rea, *colrea;
  122. if (!sess->quitreason)
  123. {
  124. colrea = strdup(prefs.quitreason);
  125. check_special_chars(colrea, FALSE);
  126. rea = random_line(colrea);
  127. free(colrea);
  128. sess->server->p_quit(sess->server, rea);
  129. free(rea);
  130. }
  131. else
  132. {
  133. // reason set by /quit, /close argument
  134. sess->server->p_quit(sess->server, sess->quitreason);
  135. }
  136. }
  137. void process_data_init(char *buf, char *cmd, char *word[],
  138. char *word_eol[], bool handle_quotes,
  139. bool allow_escape_quotes)
  140. {
  141. int wordcount = 2;
  142. int space = FALSE;
  143. int quote = FALSE;
  144. int j = 0;
  145. int len;
  146. word[0] = "\000\000";
  147. word_eol[0] = "\000\000";
  148. word[1] = buf;
  149. word_eol[1] = cmd;
  150. while (1)
  151. {
  152. switch (*cmd)
  153. {
  154. case 0:
  155. buf[j] = 0;
  156. for (j = wordcount; j < PDIWORDS; j++)
  157. {
  158. word[j] = "\000\000";
  159. word_eol[j] = "\000\000";
  160. }
  161. return;
  162. case '\042':
  163. if (!handle_quotes)
  164. goto def;
  165. // two quotes turn into 1
  166. if (allow_escape_quotes && cmd[1] == '\042')
  167. {
  168. cmd++;
  169. goto def;
  170. }
  171. if (quote)
  172. {
  173. quote = FALSE;
  174. space = FALSE;
  175. } else
  176. quote = TRUE;
  177. cmd++;
  178. break;
  179. case ' ':
  180. if (!quote)
  181. {
  182. if (!space)
  183. {
  184. buf[j] = 0;
  185. j++;
  186. if (wordcount < PDIWORDS)
  187. {
  188. word[wordcount] = &buf[j];
  189. word_eol[wordcount] = cmd + 1;
  190. wordcount++;
  191. }
  192. space = TRUE;
  193. }
  194. cmd++;
  195. break;
  196. }
  197. default:
  198. def:
  199. space = FALSE;
  200. len = g_utf8_skip[((unsigned char*)cmd)[0]];
  201. if (len == 1)
  202. {
  203. buf[j] = *cmd;
  204. j++;
  205. cmd++;
  206. }
  207. else
  208. {
  209. // skip past a multi-byte utf8 char
  210. memcpy(buf + j, cmd, len);
  211. j += len;
  212. cmd += len;
  213. }
  214. }
  215. }
  216. }
  217. static int cmd_addbutton(session *sess, char *tbuf, char *word[], 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. }
  226. else
  227. {
  228. list_addentry(&button_list, word_eol[3], word[2]);
  229. fe_buttons_update(sess);
  230. }
  231. return TRUE;
  232. }
  233. return FALSE;
  234. }
  235. static int 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 = (session*)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 cmd_allchannelslocal(session *sess, char *tbuf, char *word[], char *word_eol[])
  252. {
  253. GSList *list = sess_list;
  254. server *serv = sess->server;
  255. if (!*word_eol[2])
  256. return FALSE;
  257. while (list)
  258. {
  259. sess = (session*)list->data;
  260. if (sess->type == SESS_CHANNEL && sess->channel[0] &&
  261. sess->server->connected && sess->server == serv)
  262. {
  263. handle_command(sess, word_eol[2], FALSE);
  264. }
  265. list = list->next;
  266. }
  267. return TRUE;
  268. }
  269. static int cmd_allservers(session *sess, char *tbuf, char *word[], char *word_eol[])
  270. {
  271. GSList *list;
  272. server *serv;
  273. if (!*word_eol[2])
  274. return FALSE;
  275. list = serv_list;
  276. while (list)
  277. {
  278. serv = (server*)list->data;
  279. if (serv->connected)
  280. handle_command(serv->front_session, word_eol[2], FALSE);
  281. list = list->next;
  282. }
  283. return TRUE;
  284. }
  285. static int cmd_away(session *sess, char *tbuf, char *word[], char *word_eol[])
  286. {
  287. GSList *list;
  288. char *reason = word_eol[2];
  289. if (!(*reason))
  290. {
  291. if (sess->server->is_away)
  292. {
  293. if (sess->server->last_away_reason)
  294. PrintTextf(sess, _("Already marked away: %s\n"), sess->server->last_away_reason);
  295. return FALSE;
  296. }
  297. if (sess->server->reconnect_away)
  298. reason = sess->server->last_away_reason;
  299. else
  300. // must manage memory pointed to by random_line()
  301. reason = random_line(prefs.awayreason);
  302. }
  303. sess->server->p_set_away(sess->server, reason);
  304. if (prefs.show_away_message)
  305. {
  306. snprintf(tbuf, TBUFSIZE, "me is away: %s", reason);
  307. for (list = sess_list; list; list = list->next)
  308. {
  309. // am I the right server and not a dialog box
  310. if (((session*)list->data)->server == sess->server
  311. && ((session*)list->data)->type == SESS_CHANNEL
  312. && ((session*)list->data)->channel[0])
  313. {
  314. handle_command((session*)list->data, tbuf, TRUE);
  315. }
  316. }
  317. }
  318. if (sess->server->last_away_reason != reason)
  319. {
  320. if (sess->server->last_away_reason)
  321. free(sess->server->last_away_reason);
  322. if (reason == word_eol[2])
  323. sess->server->last_away_reason = strdup(reason);
  324. else
  325. sess->server->last_away_reason = reason;
  326. }
  327. if (!sess->server->connected)
  328. sess->server->reconnect_away = 1;
  329. return TRUE;
  330. }
  331. static int cmd_back(session *sess, char *tbuf, char *word[], char *word_eol[])
  332. {
  333. GSList *list;
  334. unsigned int gone;
  335. if (sess->server->is_away)
  336. {
  337. sess->server->p_set_back(sess->server);
  338. if (prefs.show_away_message)
  339. {
  340. gone = time(NULL) - sess->server->away_time;
  341. sprintf(tbuf, "me is back (gone %.2d:%.2d:%.2d)", gone / 3600,
  342. (gone / 60) % 60, gone % 60);
  343. for (list = sess_list; list; list = list->next)
  344. {
  345. // am I the right server and not a dialog box
  346. if (((session*)list->data)->server == sess->server
  347. && ((session*)list->data)->type == SESS_CHANNEL
  348. && ((session*)list->data)->channel[0])
  349. {
  350. handle_command((session*)list->data, tbuf, TRUE);
  351. }
  352. }
  353. }
  354. }
  355. else
  356. {
  357. PrintText(sess, _("Already marked back.\n"));
  358. }
  359. if (sess->server->last_away_reason)
  360. free(sess->server->last_away_reason);
  361. sess->server->last_away_reason = NULL;
  362. return TRUE;
  363. }
  364. static void ban(session* sess, char *tbuf, char *mask, char *bantypestr, int deop)
  365. {
  366. int bantype;
  367. User *user;
  368. char *at, *dot, *lastdot;
  369. char username[64], fullhost[128], domain[128], *mode, *p2;
  370. server *serv = sess->server;
  371. user = userlist_find(sess, mask);
  372. if (user && user->hostname) // it's a nickname, let's find a proper ban mask
  373. {
  374. if (deop)
  375. {
  376. mode = "-o+b ";
  377. p2 = user->nick;
  378. }
  379. else
  380. {
  381. mode = "+b";
  382. p2 = "";
  383. }
  384. mask = user->hostname;
  385. at = strchr(mask, '@'); // FIXME: utf8
  386. if (!at)
  387. return; // can't happen?
  388. *at = 0;
  389. if (mask[0] == '~' || mask[0] == '+' ||
  390. mask[0] == '=' || mask[0] == '^' || mask[0] == '-')
  391. {
  392. // the ident is prefixed with something, we replace that sign with a *
  393. safe_strcpy(username+1, mask+1, sizeof(username)-1);
  394. username[0] = '*';
  395. }
  396. else if (at - mask < USERNAMELEN)
  397. {
  398. // we just add an * in the begining of the ident
  399. safe_strcpy(username+1, mask, sizeof(username)-1);
  400. username[0] = '*';
  401. }
  402. else
  403. {
  404. // ident might be too long, we just ban what it gives and add an * in the end
  405. safe_strcpy(username, mask, sizeof(username));
  406. }
  407. *at = '@';
  408. safe_strcpy(fullhost, at + 1, sizeof(fullhost));
  409. dot = strchr(fullhost, '.');
  410. if (dot)
  411. {
  412. safe_strcpy(domain, dot, sizeof(domain));
  413. }
  414. else
  415. {
  416. safe_strcpy(domain, fullhost, sizeof(domain));
  417. }
  418. if (*bantypestr)
  419. bantype = atoi(bantypestr);
  420. else
  421. bantype = prefs.bantype;
  422. tbuf[0] = 0;
  423. if (inet_addr(fullhost) != -1) // "fullhost" is really an IP number
  424. {
  425. lastdot = strrchr(fullhost, '.');
  426. if (!lastdot)
  427. return; // can't happen?
  428. *lastdot = 0;
  429. strcpy(domain, fullhost);
  430. *lastdot = '.';
  431. switch (bantype)
  432. {
  433. case 0:
  434. snprintf(tbuf, TBUFSIZE, "%s%s *!*@%s.*", mode, p2, domain);
  435. break;
  436. case 1:
  437. snprintf(tbuf, TBUFSIZE, "%s%s *!*@%s", mode, p2, fullhost);
  438. break;
  439. case 2:
  440. snprintf(tbuf, TBUFSIZE, "%s%s *!%s@%s.*", mode, p2, username, domain);
  441. break;
  442. case 3:
  443. snprintf(tbuf, TBUFSIZE, "%s%s *!%s@%s", mode, p2, username, fullhost);
  444. break;
  445. }
  446. }
  447. else
  448. {
  449. switch (bantype)
  450. {
  451. case 0:
  452. snprintf(tbuf, TBUFSIZE, "%s%s *!*@*%s", mode, p2, domain);
  453. break;
  454. case 1:
  455. snprintf(tbuf, TBUFSIZE, "%s%s *!*@%s", mode, p2, fullhost);
  456. break;
  457. case 2:
  458. snprintf(tbuf, TBUFSIZE, "%s%s *!%s@*%s", mode, p2, username, domain);
  459. break;
  460. case 3:
  461. snprintf(tbuf, TBUFSIZE, "%s%s *!%s@%s", mode, p2, username, fullhost);
  462. break;
  463. }
  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 cmd_ban(session *sess, char *tbuf, char *word[], char *word_eol[])
  473. {
  474. char *mask = word[2];
  475. if (*mask)
  476. {
  477. ban(sess, tbuf, mask, word[3], 0);
  478. }
  479. else
  480. {
  481. sess->server->p_mode(sess->server, sess->channel, "+b"); // banlist
  482. }
  483. return TRUE;
  484. }
  485. static int cmd_unban(session *sess, char *tbuf, char *word[], char *word_eol[])
  486. {
  487. // Allow more than one mask in /unban -- tvk
  488. int i = 2;
  489. while (1)
  490. {
  491. if (!*word[i])
  492. {
  493. if (i == 2)
  494. return FALSE;
  495. send_channel_modes(sess, tbuf, word, 2, i, '-', 'b', 0);
  496. return TRUE;
  497. }
  498. i++;
  499. }
  500. }
  501. static int cmd_chanopt(session *sess, char *tbuf, char *word[], char *word_eol[])
  502. {
  503. // chanopt.c
  504. return chanopt_command(sess, tbuf, word, word_eol);
  505. }
  506. static int cmd_charset(session *sess, char *tbuf, char *word[], char *word_eol[])
  507. {
  508. server *serv = sess->server;
  509. const char *locale = NULL;
  510. int offset = 0;
  511. if (strcmp(word[2], "-quiet") == 0)
  512. offset++;
  513. if (!word[2 + offset][0])
  514. {
  515. g_get_charset(&locale);
  516. PrintTextf(sess, "Current charset: %s\n",
  517. serv->encoding ? serv->encoding : locale);
  518. return TRUE;
  519. }
  520. if (servlist_check_encoding(word[2 + offset]))
  521. {
  522. server_set_encoding(serv, word[2 + offset]);
  523. if (offset < 1)
  524. PrintTextf(sess, "Charset changed to: %s\n", word[2 + offset]);
  525. }
  526. else
  527. {
  528. PrintTextf(sess, "\0034Unknown charset:\017 %s\n", word[2 + offset]);
  529. }
  530. return TRUE;
  531. }
  532. static int cmd_clear(session *sess, char *tbuf, char *word[], char *word_eol[])
  533. {
  534. GSList *list = sess_list;
  535. char *reason = word_eol[2];
  536. if (strcasecmp(reason, "HISTORY") == 0)
  537. {
  538. history_free(&sess->history);
  539. return TRUE;
  540. }
  541. if (strncasecmp(reason, "all", 3) == 0)
  542. {
  543. while (list)
  544. {
  545. sess = (session*)list->data;
  546. if (!sess->nick_said)
  547. fe_text_clear((session*)list->data, 0);
  548. list = list->next;
  549. }
  550. return TRUE;
  551. }
  552. if (reason[0] != '-' && !isdigit(reason[0]) && reason[0] != 0)
  553. return FALSE;
  554. fe_text_clear(sess, atoi(reason));
  555. return TRUE;
  556. }
  557. static int cmd_close(session *sess, char *tbuf, char *word[], char *word_eol[])
  558. {
  559. GSList *list;
  560. if (strcmp(word[2], "-m") == 0)
  561. {
  562. list = sess_list;
  563. while (list)
  564. {
  565. sess = (session*)list->data;
  566. list = list->next;
  567. if (sess->type == SESS_DIALOG)
  568. fe_close_window(sess);
  569. }
  570. }
  571. else
  572. {
  573. if (*word_eol[2])
  574. sess->quitreason = word_eol[2];
  575. fe_close_window(sess);
  576. }
  577. return TRUE;
  578. }
  579. static int cmd_ctcp(session *sess, char *tbuf, char *word[], char *word_eol[])
  580. {
  581. int mbl;
  582. char *to = word[2];
  583. if (*to)
  584. {
  585. char *msg = word_eol[3];
  586. if (*msg)
  587. {
  588. unsigned char *cmd = (unsigned char*)msg;
  589. // make the first word upper case (as per RFC)
  590. while (1)
  591. {
  592. if (*cmd == ' ' || *cmd == 0)
  593. break;
  594. mbl = g_utf8_skip[*cmd];
  595. if (mbl == 1)
  596. *cmd = toupper(*cmd);
  597. cmd += mbl;
  598. }
  599. sess->server->p_ctcp(sess->server, to, msg);
  600. EMIT_SIGNAL(XP_TE_CTCPSEND, sess, to, msg, NULL, NULL, 0);
  601. return TRUE;
  602. }
  603. }
  604. return FALSE;
  605. }
  606. typedef void (*print)(void*, char*, ...);
  607. static int cmd_country(session *sess, char *tbuf, char *word[], char *word_eol[])
  608. {
  609. char *code = word[2];
  610. if (*code)
  611. {
  612. // search?
  613. if (strcmp(code, "-s") == 0)
  614. {
  615. country_search(word[3], sess, (print)PrintTextf);
  616. return TRUE;
  617. }
  618. // search, but forgot the -s
  619. if (strchr(code, '*'))
  620. {
  621. country_search(code, sess, (print)PrintTextf);
  622. return TRUE;
  623. }
  624. sprintf(tbuf, "%s = %s\n", code, country(code));
  625. PrintText(sess, tbuf);
  626. return TRUE;
  627. }
  628. return FALSE;
  629. }
  630. static int cmd_cycle(session *sess, char *tbuf, char *word[], char *word_eol[])
  631. {
  632. char *key = sess->channelkey;
  633. char *chan = word[2];
  634. if (!*chan)
  635. chan = sess->channel;
  636. if (*chan && sess->type == SESS_CHANNEL)
  637. {
  638. sess->server->p_cycle(sess->server, chan, key);
  639. return TRUE;
  640. }
  641. return FALSE;
  642. }
  643. static int cmd_dcc(session *sess, char *tbuf, char *word[], char *word_eol[])
  644. {
  645. int goodtype;
  646. DCC *dcc = 0;
  647. char *type = word[2];
  648. if (*type)
  649. {
  650. if (!strcasecmp(type, "HELP"))
  651. return FALSE;
  652. if (!strcasecmp(type, "CLOSE"))
  653. {
  654. if (*word[3] && *word[4])
  655. {
  656. goodtype = 0;
  657. if (!strcasecmp(word[3], "SEND"))
  658. {
  659. dcc = find_dcc(word[4], word[5], TYPE_SEND);
  660. dcc_abort(sess, dcc);
  661. goodtype = TRUE;
  662. }
  663. if (!strcasecmp(word[3], "GET"))
  664. {
  665. dcc = find_dcc(word[4], word[5], TYPE_RECV);
  666. dcc_abort(sess, dcc);
  667. goodtype = TRUE;
  668. }
  669. if (!strcasecmp(word[3], "CHAT"))
  670. {
  671. dcc = find_dcc(word[4], "", TYPE_CHATRECV);
  672. if (!dcc)
  673. dcc = find_dcc(word[4], "", TYPE_CHATSEND);
  674. dcc_abort(sess, dcc);
  675. goodtype = TRUE;
  676. }
  677. if (!goodtype)
  678. return FALSE;
  679. if (!dcc)
  680. EMIT_SIGNAL(XP_TE_NODCC, sess, NULL, NULL, NULL, NULL, 0);
  681. return TRUE;
  682. }
  683. return FALSE;
  684. }
  685. if ((!strcasecmp(type, "CHAT")) || (!strcasecmp(type, "PCHAT")))
  686. {
  687. char *nick = word[3];
  688. int passive = (!strcasecmp(type, "PCHAT")) ? 1 : 0;
  689. if (*nick)
  690. dcc_chat(sess, nick, passive);
  691. return TRUE;
  692. }
  693. if (!strcasecmp(type, "LIST"))
  694. {
  695. dcc_show_list(sess);
  696. return TRUE;
  697. }
  698. if (!strcasecmp(type, "GET"))
  699. {
  700. char *nick = word[3];
  701. char *file = word[4];
  702. if (!*file)
  703. {
  704. if (*nick)
  705. dcc_get_nick(sess, nick);
  706. }
  707. else
  708. {
  709. dcc = find_dcc(nick, file, TYPE_RECV);
  710. if (dcc)
  711. dcc_get(dcc);
  712. else
  713. EMIT_SIGNAL(XP_TE_NODCC, sess, NULL, NULL, NULL, NULL, 0);
  714. }
  715. return TRUE;
  716. }
  717. if ((!strcasecmp(type, "SEND")) || (!strcasecmp(type, "PSEND")))
  718. {
  719. int i = 3, maxcps;
  720. char *nick, *file;
  721. int passive = (!strcasecmp(type, "PSEND")) ? 1 : 0;
  722. nick = word[i];
  723. if (!*nick)
  724. return FALSE;
  725. maxcps = prefs.dcc_max_send_cps;
  726. if (!strncasecmp(nick, "-maxcps=", 8))
  727. {
  728. maxcps = atoi(nick + 8);
  729. i++;
  730. nick = word[i];
  731. if (!*nick)
  732. return FALSE;
  733. }
  734. i++;
  735. file = word[i];
  736. if (!*file)
  737. {
  738. fe_dcc_send_filereq(sess, nick, maxcps, passive);
  739. return TRUE;
  740. }
  741. do
  742. {
  743. dcc_send(sess, nick, file, maxcps, passive);
  744. i++;
  745. file = word[i];
  746. }
  747. while (*file);
  748. return TRUE;
  749. }
  750. return FALSE;
  751. }
  752. dcc_show_list(sess);
  753. return TRUE;
  754. }
  755. static int cmd_debug(session *sess, char *tbuf, char *word[], char *word_eol[])
  756. {
  757. session *s;
  758. server *v;
  759. GSList *list = sess_list;
  760. PrintText(sess, "Session T Channel WaitChan WillChan Server\n");
  761. while (list)
  762. {
  763. s = (session*)list->data;
  764. sprintf(tbuf, "%p %1x %-10.10s %-10.10s %-10.10s %p\n",
  765. s, s->type, s->channel, s->waitchannel,
  766. s->willjoinchannel, s->server);
  767. PrintText(sess, tbuf);
  768. list = list->next;
  769. }
  770. list = serv_list;
  771. PrintText(sess, "Server Sock Name\n");
  772. while (list)
  773. {
  774. v = (server*)list->data;
  775. sprintf(tbuf, "%p %-5d %s\n",
  776. v, v->sok, v->servername);
  777. PrintText(sess, tbuf);
  778. list = list->next;
  779. }
  780. sprintf(tbuf,
  781. "\nfront_session: %p\n"
  782. "current_tab: %p\n\n",
  783. sess->server->front_session, current_tab);
  784. PrintText(sess, tbuf);
  785. #ifdef USE_DEBUG
  786. sprintf(tbuf, "current mem: %d\n\n", current_mem_usage);
  787. PrintText(sess, tbuf);
  788. #endif /* !MEMORY_DEBUG */
  789. return TRUE;
  790. }
  791. static int cmd_delbutton(session *sess, char *tbuf, char *word[], char *word_eol[])
  792. {
  793. if (*word[2])
  794. {
  795. if (sess->type == SESS_DIALOG)
  796. {
  797. if (list_delentry(&dlgbutton_list, word[2]))
  798. fe_dlgbuttons_update(sess);
  799. }
  800. else
  801. {
  802. if (list_delentry(&button_list, word[2]))
  803. fe_buttons_update(sess);
  804. }
  805. return TRUE;
  806. }
  807. return FALSE;
  808. }
  809. static int cmd_dehop(session *sess, char *tbuf, char *word[], char *word_eol[])
  810. {
  811. int i = 2;
  812. while (1)
  813. {
  814. if (!*word[i])
  815. {
  816. if (i == 2)
  817. return FALSE;
  818. send_channel_modes(sess, tbuf, word, 2, i, '-', 'h', 0);
  819. return TRUE;
  820. }
  821. i++;
  822. }
  823. }
  824. static int cmd_deop(session *sess, char *tbuf, char *word[], char *word_eol[])
  825. {
  826. int i = 2;
  827. while (1)
  828. {
  829. if (!*word[i])
  830. {
  831. if (i == 2)
  832. return FALSE;
  833. send_channel_modes(sess, tbuf, word, 2, i, '-', 'o', 0);
  834. return TRUE;
  835. }
  836. i++;
  837. }
  838. }
  839. typedef struct
  840. {
  841. char **nicks;
  842. int i;
  843. session *sess;
  844. char *reason;
  845. char *tbuf;
  846. } multidata;
  847. static int mdehop_cb(User *user, multidata *data)
  848. {
  849. if (user->hop && !user->me)
  850. {
  851. data->nicks[data->i] = user->nick;
  852. data->i++;
  853. }
  854. return TRUE;
  855. }
  856. static int cmd_mdehop(session *sess, char *tbuf, char *word[], char *word_eol[])
  857. {
  858. char **nicks = (char**)malloc(sizeof(char*) * sess->hops);
  859. multidata data;
  860. data.nicks = nicks;
  861. data.i = 0;
  862. tree_foreach((tree*)sess->usertree, (tree_traverse_func*)mdehop_cb, &data);
  863. send_channel_modes(sess, tbuf, nicks, 0, data.i, '-', 'h', 0);
  864. free(nicks);
  865. return TRUE;
  866. }
  867. static int mdeop_cb(User *user, multidata *data)
  868. {
  869. if (user->op && !user->me)
  870. {
  871. data->nicks[data->i] = user->nick;
  872. data->i++;
  873. }
  874. return TRUE;
  875. }
  876. static int cmd_mdeop(session *sess, char *tbuf, char *word[], char *word_eol[])
  877. {
  878. char **nicks = (char**)malloc(sizeof(char*) * sess->ops);
  879. multidata data;
  880. data.nicks = nicks;
  881. data.i = 0;
  882. tree_foreach((tree*)sess->usertree, (tree_traverse_func*)mdeop_cb, &data);
  883. send_channel_modes(sess, tbuf, nicks, 0, data.i, '-', 'o', 0);
  884. free(nicks);
  885. return TRUE;
  886. }
  887. GSList *menu_list = NULL;
  888. static void
  889. menu_free (menu_entry *me)
  890. {
  891. free (me->path);
  892. if (me->label)
  893. free (me->label);
  894. if (me->cmd)
  895. free (me->cmd);
  896. if (me->ucmd)
  897. free (me->ucmd);
  898. if (me->group)
  899. free (me->group);
  900. if (me->icon)
  901. free (me->icon);
  902. free (me);
  903. }
  904. /* strings equal? but ignore underscores */
  905. int
  906. menu_streq (const char *s1, const char *s2, int def)
  907. {
  908. /* for separators */
  909. if (s1 == NULL && s2 == NULL)
  910. return 0;
  911. if (s1 == NULL || s2 == NULL)
  912. return 1;
  913. while (*s1)
  914. {
  915. if (*s1 == '_')
  916. s1++;
  917. if (*s2 == '_')
  918. s2++;
  919. if (*s1 != *s2)
  920. return 1;
  921. s1++;
  922. s2++;
  923. }
  924. if (!*s2)
  925. return 0;
  926. return def;
  927. }
  928. static menu_entry *
  929. menu_entry_find (char *path, char *label)
  930. {
  931. GSList *list;
  932. menu_entry *me;
  933. list = menu_list;
  934. while (list)
  935. {
  936. me = (menu_entry*)list->data;
  937. if (!strcmp (path, me->path))
  938. {
  939. if (me->label && label && !strcmp (label, me->label))
  940. return me;
  941. }
  942. list = list->next;
  943. }
  944. return NULL;
  945. }
  946. static void
  947. menu_del_children (char *path, char *label)
  948. {
  949. GSList *list, *next;
  950. menu_entry *me;
  951. char buf[512];
  952. if (!label)
  953. label = "";
  954. if (path[0])
  955. snprintf (buf, sizeof (buf), "%s/%s", path, label);
  956. else
  957. snprintf (buf, sizeof (buf), "%s", label);
  958. list = menu_list;
  959. while (list)
  960. {
  961. me = (menu_entry*)list->data;
  962. next = list->next;
  963. if (!menu_streq (buf, me->path, 0))
  964. {
  965. menu_list = g_slist_remove (menu_list, me);
  966. menu_free (me);
  967. }
  968. list = next;
  969. }
  970. }
  971. static int
  972. menu_del (char *path, char *label)
  973. {
  974. GSList *list;
  975. menu_entry *me;
  976. list = menu_list;
  977. while (list)
  978. {
  979. me = (menu_entry*)list->data;
  980. if (!menu_streq (me->label, label, 1) && !menu_streq (me->path, path, 1))
  981. {
  982. menu_list = g_slist_remove (menu_list, me);
  983. fe_menu_del (me);
  984. menu_free (me);
  985. /* delete this item's children, if any */
  986. menu_del_children (path, label);
  987. return 1;
  988. }
  989. list = list->next;
  990. }
  991. return 0;
  992. }
  993. static char menu_is_mainmenu_root(char *path, short *offset)
  994. {
  995. static const char *menus[] = {"\x4$TAB","\x5$TRAY","\x4$URL","\x5$NICK","\x5$CHAN"};
  996. int i;
  997. for (i = 0; i < 5; i++)
  998. {
  999. if (!strncmp(path, menus[i] + 1, menus[i][0]))
  1000. {
  1001. *offset = menus[i][0] + 1; // number of bytes to offset the root
  1002. return 0; // is not main menu
  1003. }
  1004. }
  1005. *offset = 0;
  1006. return 1; // is main menu
  1007. }
  1008. static void
  1009. 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)
  1010. {
  1011. menu_entry *me;
  1012. /* already exists? */
  1013. me = menu_entry_find (path, label);
  1014. if (me)
  1015. {
  1016. /* update only */
  1017. me->state = state;
  1018. me->enable = enable;
  1019. fe_menu_update (me);
  1020. return;
  1021. }
  1022. me = (menu_entry*)malloc(sizeof(menu_entry));
  1023. me->pos = pos;
  1024. me->modifier = mod;
  1025. me->is_main = menu_is_mainmenu_root (path, &me->root_offset);
  1026. me->state = state;
  1027. me->markup = markup;
  1028. me->enable = enable;
  1029. me->key = key;
  1030. me->path = strdup (path);
  1031. me->label = NULL;
  1032. me->cmd = NULL;
  1033. me->ucmd = NULL;
  1034. me->group = NULL;
  1035. me->icon = NULL;
  1036. if (label)
  1037. me->label = strdup (label);
  1038. if (cmd)
  1039. me->cmd = strdup (cmd);
  1040. if (ucmd)
  1041. me->ucmd = strdup (ucmd);
  1042. if (group)
  1043. me->group = strdup (group);
  1044. if (icon)
  1045. me->icon = strdup (icon);
  1046. menu_list = g_slist_append (menu_list, me);
  1047. label = fe_menu_add (me);
  1048. if (label)
  1049. {
  1050. /* FE has given us a stripped label */
  1051. free (me->label);
  1052. me->label = strdup (label);
  1053. g_free (label); /* this is from pango */
  1054. }
  1055. }
  1056. static int cmd_menu(session *sess, char *tbuf, char *word[], char *word_eol[])
  1057. {
  1058. int idx = 2;
  1059. int len;
  1060. int pos = 0xffff;
  1061. int state;
  1062. int toggle = FALSE;
  1063. int enable = TRUE;
  1064. int markup = FALSE;
  1065. int key = 0;
  1066. int mod = 0;
  1067. char *label;
  1068. char *group = NULL;
  1069. char *icon = NULL;
  1070. if (!word[2][0] || !word[3][0])
  1071. return FALSE;
  1072. // -eX enabled or not?
  1073. if (word[idx][0] == '-' && word[idx][1] == 'e')
  1074. {
  1075. enable = atoi(word[idx] + 2);
  1076. idx++;
  1077. }
  1078. // -i<ICONFILE>
  1079. if (word[idx][0] == '-' && word[idx][1] == 'i')
  1080. {
  1081. icon = word[idx] + 2;
  1082. idx++;
  1083. }
  1084. // -k<mod>,<key> key binding
  1085. if (word[idx][0] == '-' && word[idx][1] == 'k')
  1086. {
  1087. char *comma = strchr(word[idx], ',');
  1088. if (!comma)
  1089. return FALSE;
  1090. mod = atoi(word[idx] + 2);
  1091. key = atoi(comma + 1);
  1092. idx++;
  1093. }
  1094. // -m to specify PangoMarkup language
  1095. if (word[idx][0] == '-' && word[idx][1] == 'm')
  1096. {
  1097. markup = TRUE;
  1098. idx++;
  1099. }
  1100. // -pX to specify menu position
  1101. if (word[idx][0] == '-' && word[idx][1] == 'p')
  1102. {
  1103. pos = atoi(word[idx] + 2);
  1104. idx++;
  1105. }
  1106. // -rSTATE,GROUP to specify a radio item
  1107. if (word[idx][0] == '-' && word[idx][1] == 'r')
  1108. {
  1109. state = atoi(word[idx] + 2);
  1110. group = word[idx] + 4;
  1111. idx++;
  1112. }
  1113. // -tX to specify toggle item with default state
  1114. if (word[idx][0] == '-' && word[idx][1] == 't')
  1115. {
  1116. state = atoi(word[idx] + 2);
  1117. idx++;
  1118. toggle = TRUE;
  1119. }
  1120. if (word[idx+1][0] == 0)
  1121. return FALSE;
  1122. // the path
  1123. path_part(word[idx+1], tbuf, 512);
  1124. len = strlen(tbuf);
  1125. if (len)
  1126. tbuf[len - 1] = 0;
  1127. // the name of the item
  1128. label = file_part(word[idx + 1]);
  1129. if (label[0] == '-' && label[1] == 0)
  1130. label = NULL; // separator
  1131. if (markup)
  1132. {
  1133. char *p; // to force pango closing tags through
  1134. for (p = label; *p; p++)
  1135. if (*p == 3)
  1136. *p = '/';
  1137. }
  1138. if (!strcasecmp(word[idx], "ADD"))
  1139. {
  1140. if (toggle)
  1141. {
  1142. menu_add(tbuf, label, word[idx + 2], word[idx + 3], pos, state, markup, enable, mod, key, NULL, NULL);
  1143. }
  1144. else
  1145. {
  1146. if (word[idx + 2][0])
  1147. menu_add(tbuf, label, word[idx + 2], NULL, pos, state, markup, enable, mod, key, group, icon);
  1148. else
  1149. menu_add(tbuf, label, NULL, NULL, pos, state, markup, enable, mod, key, group, icon);
  1150. }
  1151. return TRUE;
  1152. }
  1153. if (!strcasecmp(word[idx], "DEL"))
  1154. {
  1155. menu_del(tbuf, label);
  1156. return TRUE;
  1157. }
  1158. return FALSE;
  1159. }
  1160. static int mkick_cb(User *user, multidata *data)
  1161. {
  1162. if (!user->op && !user->me)
  1163. data->sess->server->p_kick(data->sess->server, data->sess->channel, user->nick, data->reason);
  1164. return TRUE;
  1165. }
  1166. static int mkickops_cb(User *user, multidata *data)
  1167. {
  1168. if (user->op && !user->me)
  1169. data->sess->server->p_kick(data->sess->server, data->sess->channel, user->nick, data->reason);
  1170. return TRUE;
  1171. }
  1172. static int cmd_mkick(session *sess, char *tbuf, char *word[], char *word_eol[])
  1173. {
  1174. multidata data;
  1175. data.sess = sess;
  1176. data.reason = word_eol[2];
  1177. tree_foreach((tree*)sess->usertree, (tree_traverse_func*)mkickops_cb, &data);
  1178. tree_foreach((tree*)sess->usertree, (tree_traverse_func*)mkick_cb, &data);
  1179. return TRUE;
  1180. }
  1181. static int cmd_devoice(session *sess, char *tbuf, char *word[], char *word_eol[])
  1182. {
  1183. int i = 2;
  1184. while (1)
  1185. {
  1186. if (!*word[i])
  1187. {
  1188. if (i == 2)
  1189. return FALSE;
  1190. send_channel_modes(sess, tbuf, word, 2, i, '-', 'v', 0);
  1191. return TRUE;
  1192. }
  1193. i++;
  1194. }
  1195. }
  1196. static int cmd_discon(session *sess, char *tbuf, char *word[], char *word_eol[])
  1197. {
  1198. sess->server->disconnect(sess, TRUE, -1);
  1199. return TRUE;
  1200. }
  1201. static int cmd_dns(session *sess, char *tbuf, char *word[], char *word_eol[])
  1202. {
  1203. #ifdef WIN32
  1204. PrintText(sess, "DNS is not implemented in Windows.\n");
  1205. return TRUE;
  1206. #else
  1207. char *nick = word[2];
  1208. User *user;
  1209. if (*nick)
  1210. {
  1211. if (strchr(nick, '.') == NULL)
  1212. {
  1213. user = userlist_find(sess, nick);
  1214. if (user && user->hostname)
  1215. {
  1216. do_dns(sess, user->nick, user->hostname);
  1217. }
  1218. else
  1219. {
  1220. sess->server->p_get_ip(sess->server, nick);
  1221. sess->server->doing_dns = TRUE;
  1222. }
  1223. }
  1224. else
  1225. {
  1226. snprintf(tbuf, TBUFSIZE, "exec -d %s %s", prefs.dnsprogram, nick);
  1227. handle_command(sess, tbuf, FALSE);
  1228. }
  1229. return TRUE;
  1230. }
  1231. return FALSE;
  1232. #endif
  1233. }
  1234. static int cmd_echo(session *sess, char *tbuf, char *word[], char *word_eol[])
  1235. {
  1236. PrintText(sess, word_eol[2]);
  1237. return TRUE;
  1238. }
  1239. #ifndef WIN32
  1240. static void exec_check_process(session *sess)
  1241. {
  1242. int val;
  1243. if (sess->running_exec == NULL)
  1244. return;
  1245. val = waitpid(sess->running_exec->childpid, NULL, WNOHANG);
  1246. if (val == -1 || val > 0)
  1247. {
  1248. close(sess->running_exec->myfd);
  1249. fe_input_remove(sess->running_exec->iotag);
  1250. free(sess->running_exec);
  1251. sess->running_exec = NULL;
  1252. }
  1253. }
  1254. #ifndef __EMX__
  1255. static int cmd_execs(session *sess, char *tbuf, char *word[], char *word_eol[])
  1256. {
  1257. int r;
  1258. exec_check_process(sess);
  1259. if (sess->running_exec == NULL)
  1260. {
  1261. EMIT_SIGNAL(XP_TE_NOCHILD, sess, NULL, NULL, NULL, NULL, 0);
  1262. return FALSE;
  1263. }
  1264. r = kill(sess->running_exec->childpid, SIGSTOP);
  1265. if (r == -1)
  1266. PrintText(sess, "Error in kill(2)\n");
  1267. return TRUE;
  1268. }
  1269. static int cmd_execc(session *sess, char *tbuf, char *word[], char *word_eol[])
  1270. {
  1271. int r;
  1272. exec_check_process(sess);
  1273. if (sess->running_exec == NULL)
  1274. {
  1275. EMIT_SIGNAL(XP_TE_NOCHILD, sess, NULL, NULL, NULL, NULL, 0);
  1276. return FALSE;
  1277. }
  1278. r = kill(sess->running_exec->childpid, SIGCONT);
  1279. if (r == -1)
  1280. PrintText(sess, "Error in kill(2)\n");
  1281. return TRUE;
  1282. }
  1283. static int cmd_execk(session *sess, char *tbuf, char *word[], char *word_eol[])
  1284. {
  1285. int r;
  1286. exec_check_process(sess);
  1287. if (sess->running_exec == NULL)
  1288. {
  1289. EMIT_SIGNAL(XP_TE_NOCHILD, sess, NULL, NULL, NULL, NULL, 0);
  1290. return FALSE;
  1291. }
  1292. if (strcmp(word[2], "-9") == 0)
  1293. r = kill(sess->running_exec->childpid, SIGKILL);
  1294. else
  1295. r = kill(sess->running_exec->childpid, SIGTERM);
  1296. if (r == -1)
  1297. PrintText(sess, "Error in kill(2)\n");
  1298. return TRUE;
  1299. }
  1300. /* OS/2 Can't have the /EXECW command because it uses pipe(2) not socketpair
  1301. and thus it is simplex --AGL*/
  1302. static int cmd_execw(session *sess, char *tbuf, char *word[], char *word_eol[])
  1303. {
  1304. int len;
  1305. char *temp;
  1306. exec_check_process(sess);
  1307. if (sess->running_exec == NULL)
  1308. {
  1309. EMIT_SIGNAL(XP_TE_NOCHILD, sess, NULL, NULL, NULL, NULL, 0);
  1310. return FALSE;
  1311. }
  1312. len = strlen(word_eol[2]);
  1313. temp = (char*)malloc(len + 2);
  1314. sprintf(temp, "%s\n", word_eol[2]);
  1315. PrintText(sess, temp);
  1316. write(sess->running_exec->myfd, temp, len + 1);
  1317. free(temp);
  1318. return TRUE;
  1319. }
  1320. #endif /* !__EMX__ */
  1321. // convert ANSI escape color codes to mIRC codes
  1322. static short escconv[] =
  1323. // 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
  1324. { 1,4,3,5,2,10,6,1, 1,7,9,8,12,11,13,1 };
  1325. static void exec_handle_colors(char *buf, int len)
  1326. {
  1327. char numb[16];
  1328. char *nbuf;
  1329. int i = 0, j = 0, k = 0, firstn = 0, col, colf = 0, colb = 0;
  1330. int esc = FALSE, backc = FALSE, bold = FALSE;
  1331. // any escape codes in this text?
  1332. if (strchr(buf, 27) == 0)
  1333. return;
  1334. nbuf = (char*)malloc(len + 1);
  1335. while (i < len)
  1336. {
  1337. switch (buf[i])
  1338. {
  1339. case '\r':
  1340. break;
  1341. case 27:
  1342. esc = TRUE;
  1343. break;
  1344. case ';':
  1345. if (!esc)
  1346. goto norm;
  1347. backc = TRUE;
  1348. numb[k] = 0;
  1349. firstn = atoi(numb);
  1350. k = 0;
  1351. break;
  1352. case '[':
  1353. if (!esc)
  1354. goto norm;
  1355. break;
  1356. default:
  1357. if (esc)
  1358. {
  1359. if (buf[i] >= 'A' && buf[i] <= 'z')
  1360. {
  1361. if (buf[i] == 'm')
  1362. {
  1363. // ^[[0m
  1364. if (k == 0 || (numb[0] == '0' && k == 1))
  1365. {
  1366. nbuf[j] = '\017';
  1367. j++;
  1368. bold = FALSE;
  1369. goto cont;
  1370. }
  1371. numb[k] = 0;
  1372. col = atoi(numb);
  1373. backc = FALSE;
  1374. if (firstn == 1)
  1375. bold = TRUE;
  1376. if (firstn >= 30 && firstn <= 37)
  1377. colf = firstn - 30;
  1378. if (col >= 40)
  1379. {
  1380. colb = col - 40;
  1381. backc = TRUE;
  1382. }
  1383. if (col >= 30 && col <= 37)
  1384. colf = col - 30;
  1385. if (bold)
  1386. colf += 8;
  1387. if (backc)
  1388. {
  1389. colb = escconv[colb % 14];
  1390. colf = escconv[colf % 14];
  1391. j += sprintf(&nbuf[j], "\003%d,%02d", colf, colb);
  1392. }
  1393. else
  1394. {
  1395. colf = escconv[colf % 14];
  1396. j += sprintf(&nbuf[j], "\003%02d", colf);
  1397. }
  1398. }
  1399. cont: esc = FALSE;
  1400. backc = FALSE;
  1401. k = 0;
  1402. }
  1403. else
  1404. {
  1405. if (isdigit((unsigned char)buf[i]) && k < (sizeof(numb) - 1))
  1406. {
  1407. numb[k] = buf[i];
  1408. k++;
  1409. }
  1410. }
  1411. }
  1412. else
  1413. {
  1414. norm: nbuf[j] = buf[i];
  1415. j++;
  1416. }
  1417. }
  1418. i++;
  1419. }
  1420. nbuf[j] = 0;
  1421. memcpy(buf, nbuf, j + 1);
  1422. free(nbuf);
  1423. }
  1424. #ifndef HAVE_MEMRCHR
  1425. static void* memrchr(const void *block, int c, size_t size)
  1426. {
  1427. unsigned char *p;
  1428. for (p = (unsigned char*)block + size; p != block; p--)
  1429. if (*p == c)
  1430. return p;
  1431. return 0;
  1432. }
  1433. #endif
  1434. static bool exec_data(GIOChannel *source, GIOCondition condition, nbexec *s)
  1435. {
  1436. char *buf, *readpos, *rest;
  1437. int rd, len;
  1438. int sok = s->myfd;
  1439. len = s->buffill;
  1440. if (len) {
  1441. // append new data to buffered incomplete line
  1442. buf = (char*)malloc(len + 2050);
  1443. memcpy(buf, s->linebuf, len);
  1444. readpos = buf + len;
  1445. free(s->linebuf);
  1446. s->linebuf = NULL;
  1447. }
  1448. else
  1449. readpos = buf = (char*)malloc(2050);
  1450. rd = read(sok, readpos, 2048);
  1451. if (rd < 1)
  1452. {
  1453. // The process has died
  1454. kill(s->childpid, SIGKILL);
  1455. if (len) {
  1456. buf[len] = '\0';
  1457. exec_handle_colors(buf, len);
  1458. if (s->tochannel)
  1459. {
  1460. // must turn off auto-completion temporarily
  1461. unsigned int old = prefs.nickcompletion;
  1462. prefs.nickcompletion = 0;
  1463. handle_multiline(s->sess, buf, FALSE, TRUE);
  1464. prefs.nickcompletion = old;
  1465. }
  1466. else
  1467. PrintText(s->sess, buf);
  1468. }
  1469. free(buf);
  1470. waitpid(s->childpid, NULL, 0);
  1471. s->sess->running_exec = NULL;
  1472. fe_input_remove(s->iotag);
  1473. close(sok);
  1474. free(s);
  1475. return TRUE;
  1476. }
  1477. len += rd;
  1478. buf[len] = '\0';
  1479. rest = (char*)memrchr(buf, '\n', len);
  1480. if (rest)
  1481. rest++;
  1482. else
  1483. rest = buf;
  1484. if (*rest) {
  1485. s->buffill = len - (rest - buf); // = strlen(rest)
  1486. s->linebuf = (char*)malloc(s->buffill);
  1487. memcpy(s->linebuf, rest, s->buffill);
  1488. *rest = '\0';
  1489. len -= s->buffill; // possibly 0
  1490. }
  1491. else
  1492. s->buffill = 0;
  1493. if (len) {
  1494. exec_handle_colors(buf, len);
  1495. if (s->tochannel)
  1496. handle_multiline(s->sess, buf, FALSE, TRUE);
  1497. else
  1498. PrintText(s->sess, buf);
  1499. }
  1500. free(buf);
  1501. return TRUE;
  1502. }
  1503. static int cmd_exec(session *sess, char *tbuf, char *word[], char *word_eol[])
  1504. {
  1505. int tochannel = FALSE;
  1506. char *cmd = word_eol[2];
  1507. int fds[2], pid = 0;
  1508. nbexec *s;
  1509. int shell = TRUE;
  1510. int fd;
  1511. if (*cmd)
  1512. {
  1513. exec_check_process(sess);
  1514. if (sess->running_exec != NULL)
  1515. {
  1516. EMIT_SIGNAL(XP_TE_ALREADYPROCESS, sess, NULL, NULL, NULL, NULL, 0);
  1517. return TRUE;
  1518. }
  1519. if (!strcmp(word[2], "-d"))
  1520. {
  1521. if (!*word[3])
  1522. return FALSE;
  1523. cmd = word_eol[3];
  1524. shell = FALSE;
  1525. }
  1526. else if (!strcmp(word[2], "-o"))
  1527. {
  1528. if (!*word[3])
  1529. return FALSE;
  1530. cmd = word_eol[3];
  1531. tochannel = TRUE;
  1532. }
  1533. if (shell)
  1534. {
  1535. if (access("/bin/sh", X_OK) != 0)
  1536. {
  1537. fe_message(_("I need /bin/sh to run!\n"), FE_MSG_ERROR);
  1538. return TRUE;
  1539. }
  1540. }
  1541. #ifdef __EMX__ /* if os/2 */
  1542. if (pipe(fds) < 0)
  1543. {
  1544. PrintText(sess, "Pipe create error\n");
  1545. return FALSE;
  1546. }
  1547. setmode(fds[0], O_BINARY);
  1548. setmode(fds[1], O_BINARY);
  1549. #else
  1550. if (socketpair(PF_UNIX, SOCK_STREAM, 0, fds) == -1)
  1551. {
  1552. PrintText(sess, "socketpair(2) failed\n");
  1553. return FALSE;
  1554. }
  1555. #endif
  1556. s = (nbexec*)malloc(sizeof(nbexec));
  1557. memset(s, 0, sizeof(*s));
  1558. s->myfd = fds[0];
  1559. s->tochannel = tochannel;
  1560. s->sess = sess;
  1561. pid = fork();
  1562. if (pid == 0)
  1563. {
  1564. // This is the child's context
  1565. close(0);
  1566. close(1);
  1567. close(2);
  1568. // Close parent's end of pipe
  1569. close(s->myfd);
  1570. // Copy the child end of the pipe to stdout and stderr
  1571. dup2(fds[1], 1);
  1572. dup2(fds[1], 2);
  1573. // Also copy it to stdin so we can write to it
  1574. dup2(fds[1], 0);
  1575. // Now close all open file descriptors except stdin, stdout and stderr
  1576. for (fd = 3; fd < 1024; fd++)
  1577. close(fd);
  1578. // Now we call /bin/sh to run our cmd ; made it more friendly -DC1
  1579. if (shell)
  1580. {
  1581. execl("/bin/sh", "sh", "-c", cmd, NULL);
  1582. }
  1583. else
  1584. {
  1585. char **argv;
  1586. int argc;
  1587. my_poptParseArgvString(cmd, &argc, &argv);
  1588. execvp(argv[0], argv);
  1589. }
  1590. // not reached unless error
  1591. //printf("exec error\n");
  1592. fflush(stdout);
  1593. fflush(stdin);
  1594. _exit(0);
  1595. }
  1596. if (pid == -1)
  1597. {
  1598. // Parent context, fork() failed
  1599. PrintText(sess, "Error in fork(2)\n");
  1600. close(fds[0]);
  1601. close(fds[1]);
  1602. }
  1603. else
  1604. {
  1605. // Parent path
  1606. close(fds[1]);
  1607. s->childpid = pid;
  1608. s->iotag = fe_input_add(s->myfd, FIA_READ|FIA_EX, (void*)exec_data, s);
  1609. sess->running_exec = s;
  1610. return TRUE;
  1611. }
  1612. }
  1613. return FALSE;
  1614. }
  1615. #endif
  1616. static int cmd_flushq(session *sess, char *tbuf, char *word[], char *word_eol[])
  1617. {
  1618. sprintf(tbuf, "Flushing server send queue, %d bytes.\n", sess->server->sendq_len);
  1619. PrintText(sess, tbuf);
  1620. sess->server->flush_queue(sess->server);
  1621. return TRUE;
  1622. }
  1623. static int cmd_quit(session *sess, char *tbuf, char *word[], char *word_eol[])
  1624. {
  1625. if (*word_eol[2])
  1626. sess->quitreason = word_eol[2];
  1627. sess->server->disconnect(sess, TRUE, -1);
  1628. sess->quitreason = NULL;
  1629. return 2;
  1630. }
  1631. static int cmd_gate(session *sess, char *tbuf, char *word[], char *word_eol[])
  1632. {
  1633. char *server_name = word[2];
  1634. server *serv = sess->server;
  1635. if (*server_name)
  1636. {
  1637. char *port = word[3];
  1638. #ifdef USE_OPENSSL
  1639. serv->use_ssl = FALSE;
  1640. #endif
  1641. server_fill_her_up(serv);
  1642. if (*port)
  1643. serv->connect(serv, server_name, atoi(port), TRUE);
  1644. else
  1645. serv->connect(serv, server_name, 23, TRUE);
  1646. return TRUE;
  1647. }
  1648. return FALSE;
  1649. }
  1650. typedef struct
  1651. {
  1652. char *cmd;
  1653. session *sess;
  1654. } getvalinfo;
  1655. static void get_int_cb(int cancel, int val, getvalinfo *info)
  1656. {
  1657. char buf[512];
  1658. if (!cancel)
  1659. {
  1660. snprintf(buf, sizeof(buf), "%s %d", info->cmd, val);
  1661. if (is_session(info->sess))
  1662. handle_command(info->sess, buf, FALSE);
  1663. }
  1664. free(info->cmd);
  1665. free(info);
  1666. }
  1667. static int cmd_getint(session *sess, char *tbuf, char *word[], char *word_eol[])
  1668. {
  1669. getvalinfo *info;
  1670. if (!word[4][0])
  1671. return FALSE;
  1672. info = (getvalinfo*)malloc(sizeof(*info));
  1673. info->cmd = strdup(word[3]);
  1674. info->sess = sess;
  1675. fe_get_int(word[4], atoi(word[2]), (void*)get_int_cb, info);
  1676. return TRUE;
  1677. }
  1678. static void get_file_cb(char *cmd, char *file)
  1679. {
  1680. char buf[1024 + 128];
  1681. /* execute the command once per file, then once more with
  1682. no args*/
  1683. if (file)
  1684. {
  1685. snprintf(buf, sizeof(buf), "%s %s", cmd, file);
  1686. handle_command(current_sess, buf, FALSE);
  1687. }
  1688. else
  1689. {
  1690. handle_command(current_sess, cmd, FALSE);
  1691. free(cmd);
  1692. }
  1693. }
  1694. typedef void (*callback)(void*, char*);
  1695. static int cmd_getfile(session *sess, char *tbuf, char *word[], char *word_eol[])
  1696. {
  1697. int idx = 2;
  1698. int flags = 0;
  1699. if (!word[3][0])
  1700. return FALSE;
  1701. if (!strcmp(word[2], "-folder"))
  1702. {
  1703. flags |= FRF_CHOOSEFOLDER;
  1704. idx++;
  1705. }
  1706. if (!strcmp(word[idx], "-multi"))
  1707. {
  1708. flags |= FRF_MULTIPLE;
  1709. idx++;
  1710. }
  1711. if (!strcmp(word[idx], "-save"))
  1712. {
  1713. flags |= FRF_WRITE;
  1714. idx++;
  1715. }
  1716. fe_get_file(word[idx+1], word[idx+2], (callback)get_file_cb, strdup(word[idx]), flags);
  1717. return TRUE;
  1718. }
  1719. static void get_str_cb(int cancel, char *val, getvalinfo *info)
  1720. {
  1721. char buf[512];
  1722. if (!cancel)
  1723. {
  1724. snprintf(buf, sizeof(buf), "%s %s", info->cmd, val);
  1725. if (is_session(info->sess))
  1726. handle_command(info->sess, buf, FALSE);
  1727. }
  1728. free(info->cmd);
  1729. free(info);
  1730. }
  1731. static int cmd_getstr(session *sess, char *tbuf, char *word[], char *word_eol[])
  1732. {
  1733. getvalinfo *info;
  1734. if (!word[4][0])
  1735. return FALSE;
  1736. info = (getvalinfo*)malloc(sizeof(*info));
  1737. info->cmd = strdup(word[3]);
  1738. info->sess = sess;
  1739. fe_get_str(word[4], word[2], (void*)get_str_cb, info);
  1740. return TRUE;
  1741. }
  1742. static int cmd_ghost(session *sess, char *tbuf, char *word[], char *word_eol[])
  1743. {
  1744. if (!word[2][0])
  1745. return FALSE;
  1746. sess->server->p_ns_ghost(sess->server, word[2], word[3]);
  1747. return TRUE;
  1748. }
  1749. static int cmd_gui(session *sess, char *tbuf, char *word[], char *word_eol[])
  1750. {
  1751. switch (str_ihash((const unsigned char*)word[2]))
  1752. {
  1753. case 0x058b836e: fe_ctrl_gui(sess, FE_GUI_APPLY, 0); break; // APPLY
  1754. case 0xac1eee45: fe_ctrl_gui(sess, FE_GUI_ATTACH, 2); break; // ATTACH
  1755. case 0x05a72f63: fe_ctrl_gui(sess, FE_GUI_COLOR, atoi(word[3])); break; // COLOR
  1756. case 0xb06a1793: fe_ctrl_gui(sess, FE_GUI_ATTACH, 1); break; // DETACH
  1757. case 0x05cfeff0: fe_ctrl_gui(sess, FE_GUI_FLASH, 0); break; // FLASH
  1758. case 0x05d154d8: fe_ctrl_gui(sess, FE_GUI_FOCUS, 0); break; // FOCUS
  1759. case 0x0030dd42: fe_ctrl_gui(sess, FE_GUI_HIDE, 0); break; // HIDE
  1760. case 0x61addbe3: fe_ctrl_gui(sess, FE_GUI_ICONIFY, 0); break; // ICONIFY
  1761. case 0xc0851aaa: fe_message(word[3], FE_MSG_INFO|FE_MSG_MARKUP); break; // MSGBOX
  1762. case 0x0035dafd: fe_ctrl_gui(sess, FE_GUI_SHOW, 0); break; // SHOW
  1763. case 0x0033155f: // MENU
  1764. if (!strcasecmp(word[3], "TOGGLE"))
  1765. fe_ctrl_gui(sess, FE_GUI_MENU, 0);
  1766. else
  1767. return FALSE;
  1768. break;
  1769. default:
  1770. return FALSE;
  1771. }
  1772. return TRUE;
  1773. }
  1774. typedef struct
  1775. {
  1776. int longfmt;
  1777. int i, t;
  1778. char *buf;
  1779. } help_list;
  1780. static void show_help_line(session *sess, help_list *hl, char *name, char *usage)
  1781. {
  1782. int j, len, max;
  1783. char *p;
  1784. if (name[0] == '.') // hidden command?
  1785. return;
  1786. if (hl->longfmt) // long format for /HELP -l
  1787. {
  1788. if (!usage || usage[0] == 0)
  1789. PrintTextf(sess, " \0034%s\003 :\n", name);
  1790. else
  1791. PrintTextf(sess, " \0034%s\003 : %s\n", name, _(usage));
  1792. return;
  1793. }
  1794. // append the name into buffer, but convert to uppercase
  1795. len = strlen(hl->buf);
  1796. p = name;
  1797. while (*p)
  1798. {
  1799. hl->buf[len] = toupper((unsigned char)*p);
  1800. len++;
  1801. p++;
  1802. }
  1803. hl->buf[len] = 0;
  1804. hl->t++;
  1805. if (hl->t == 5)
  1806. {
  1807. hl->t = 0;
  1808. strcat(hl->buf, "\n");
  1809. PrintText(sess, hl->buf);
  1810. hl->buf[0] = ' ';
  1811. hl->buf[1] = ' ';
  1812. hl->buf[2] = 0;
  1813. }
  1814. else
  1815. {
  1816. // append some spaces after the command name
  1817. max = strlen(name);
  1818. if (max < 10)
  1819. {
  1820. max = 10 - max;
  1821. for (j = 0; j < max; j++)
  1822. {
  1823. hl->buf[len] = ' ';
  1824. len++;
  1825. hl->buf[len] = 0;
  1826. }
  1827. }
  1828. }
  1829. }
  1830. typedef void (*cb)(session*, void*, char*, char*);
  1831. static int cmd_help(session *sess, char *tbuf, char *word[], char *word_eol[])
  1832. {
  1833. int i = 0, longfmt = 0;
  1834. char *helpcmd = 0;
  1835. GSList *list;
  1836. if (tbuf)
  1837. helpcmd = word[2];
  1838. if (*helpcmd && strcmp(helpcmd, "-l") == 0)
  1839. longfmt = 1;
  1840. if (*helpcmd && !longfmt)
  1841. {
  1842. help(sess, tbuf, helpcmd, FALSE);
  1843. }
  1844. else
  1845. {
  1846. popup *pop;
  1847. char *buf = (char*)malloc(4096);
  1848. help_list hl;
  1849. hl.longfmt = longfmt;
  1850. hl.buf = buf;
  1851. PrintTextf(sess, "\n%s\n\n", _("Commands Available:"));
  1852. buf[0] = ' ';
  1853. buf[1] = ' ';
  1854. buf[2] = 0;
  1855. hl.t = 0;
  1856. hl.i = 0;
  1857. while (xc_cmds[i].name)
  1858. {
  1859. show_help_line(sess, &hl, xc_cmds[i].name, xc_cmds[i].help);
  1860. i++;
  1861. }
  1862. strcat(buf, "\n");
  1863. PrintText(sess, buf);
  1864. PrintTextf(sess, "\n%s\n\n", _("User defined commands:"));
  1865. buf[0] = ' ';
  1866. buf[1] = ' ';
  1867. buf[2] = 0;
  1868. hl.t = 0;
  1869. hl.i = 0;
  1870. list = command_list;
  1871. while (list)
  1872. {
  1873. pop = (popup*)list->data;
  1874. show_help_line(sess, &hl, pop->name, pop->cmd);
  1875. list = list->next;
  1876. }
  1877. strcat(buf, "\n");
  1878. PrintText(sess, buf);
  1879. PrintTextf(sess, "\n%s\n\n", _("Plugin defined commands:"));
  1880. buf[0] = ' ';
  1881. buf[1] = ' ';
  1882. buf[2] = 0;
  1883. hl.t = 0;
  1884. hl.i = 0;
  1885. plugin_command_foreach(sess, &hl, (cb)show_help_line);
  1886. strcat(buf, "\n");
  1887. PrintText(sess, buf);
  1888. free(buf);
  1889. PrintTextf(sess, "\n%s\n\n", _("Type /HELP <command> for more information, or /HELP -l"));
  1890. }
  1891. return TRUE;
  1892. }
  1893. static int cmd_id(session *sess, char *tbuf, char *word[], char *word_eol[])
  1894. {
  1895. if (word[2][0])
  1896. {
  1897. sess->server->p_ns_identify(sess->server, word[2]);
  1898. return TRUE;
  1899. }
  1900. return FALSE;
  1901. }
  1902. static int cmd_ignore(session *sess, char *tbuf, char *word[], char *word_eol[])
  1903. {
  1904. int i;
  1905. int type = 0;
  1906. int quiet = 0;
  1907. char *mask;
  1908. if (!*word[2])
  1909. {
  1910. ignore_showlist(sess);
  1911. return TRUE;
  1912. }
  1913. if (!*word[3])
  1914. return FALSE;
  1915. i = 3;
  1916. while (1)
  1917. {
  1918. if (!*word[i])
  1919. {
  1920. if (type == 0)
  1921. return FALSE;
  1922. mask = word[2];
  1923. if (strchr(mask, '?') == NULL &&
  1924. strchr(mask, '*') == NULL &&
  1925. userlist_find(sess, mask))
  1926. {
  1927. mask = tbuf;
  1928. snprintf(tbuf, TBUFSIZE, "%s!*@*", word[2]);
  1929. }
  1930. i = ignore_add(mask, type);
  1931. if (quiet)
  1932. return TRUE;
  1933. switch (i)
  1934. {
  1935. case 1:
  1936. EMIT_SIGNAL(XP_TE_IGNOREADD, sess, mask, NULL, NULL, NULL, 0);
  1937. break;
  1938. case 2: // old ignore changed
  1939. EMIT_SIGNAL(XP_TE_IGNORECHANGE, sess, mask, NULL, NULL, NULL, 0);
  1940. }
  1941. return TRUE;
  1942. }
  1943. if (!strcasecmp(word[i], "UNIGNORE"))
  1944. type |= IG_UNIG;
  1945. else if (!strcasecmp(word[i], "ALL"))
  1946. type |= IG_PRIV | IG_NOTI | IG_CHAN | IG_CTCP | IG_INVI | IG_DCC;
  1947. else if (!strcasecmp(word[i], "PRIV"))
  1948. type |= IG_PRIV;
  1949. else if (!strcasecmp(word[i], "NOTI"))
  1950. type |= IG_NOTI;
  1951. else if (!strcasecmp(word[i], "CHAN"))
  1952. type |= IG_CHAN;
  1953. else if (!strcasecmp(word[i], "CTCP"))
  1954. type |= IG_CTCP;
  1955. else if (!strcasecmp(word[i], "INVI"))
  1956. type |= IG_INVI;
  1957. else if (!strcasecmp(word[i], "QUIET"))
  1958. quiet = 1;
  1959. else if (!strcasecmp(word[i], "NOSAVE"))
  1960. type |= IG_NOSAVE;
  1961. else if (!strcasecmp(word[i], "DCC"))
  1962. type |= IG_DCC;
  1963. else
  1964. {
  1965. sprintf(tbuf, _("Unknown arg '%s' ignored."), word[i]);
  1966. PrintText(sess, tbuf);
  1967. }
  1968. i++;
  1969. }
  1970. }
  1971. static int cmd_invite(session *sess, char *tbuf, char *word[], char *word_eol[])
  1972. {
  1973. if (!*word[2])
  1974. return FALSE;
  1975. if (*word[3])
  1976. sess->server->p_invite(sess->server, word[3], word[2]);
  1977. else
  1978. sess->server->p_invite(sess->server, sess->channel, word[2]);
  1979. return TRUE;
  1980. }
  1981. static int cmd_join(session *sess, char *tbuf, char *word[], char *word_eol[])
  1982. {
  1983. char *chan = word[2];
  1984. if (*chan)
  1985. {
  1986. char *po, *pass = word[3];
  1987. sess->server->p_join(sess->server, chan, pass);
  1988. if (sess->channel[0] == 0 && sess->waitchannel[0])
  1989. {
  1990. po = strchr(chan, ',');
  1991. if (po)
  1992. *po = 0;
  1993. safe_strcpy(sess->waitchannel, chan, CHANLEN);
  1994. }
  1995. return TRUE;
  1996. }
  1997. return FALSE;
  1998. }
  1999. static int cmd_kick(session *sess, char *tbuf, char *word[], char *word_eol[])
  2000. {
  2001. char *nick = word[2];
  2002. char *reason = word_eol[3];
  2003. if (*nick)
  2004. {
  2005. sess->server->p_kick(sess->server, sess->channel, nick, reason);
  2006. return TRUE;
  2007. }
  2008. return FALSE;
  2009. }
  2010. static int cmd_kickban(session *sess, char *tbuf, char *word[], char *word_eol[])
  2011. {
  2012. char *nick = word[2];
  2013. char *reason = word_eol[3];
  2014. User *user;
  2015. if (*nick)
  2016. {
  2017. // if the reason is a 1 digit number, treat it as a bantype
  2018. user = userlist_find(sess, nick);
  2019. if (isdigit((unsigned char)reason[0]) && reason[1] == 0)
  2020. {
  2021. ban(sess, tbuf, nick, reason, user && user->op);
  2022. reason[0] = 0;
  2023. } else
  2024. ban(sess, tbuf, nick, "", user && user->op);
  2025. sess->server->p_kick(sess->server, sess->channel, nick, reason);
  2026. return TRUE;
  2027. }
  2028. return FALSE;
  2029. }
  2030. static int cmd_killall(session *sess, char *tbuf, char *word[], char *word_eol[])
  2031. {
  2032. xchat_exit();
  2033. return 2;
  2034. }
  2035. static int cmd_lagcheck(session *sess, char *tbuf, char *word[], char *word_eol[])
  2036. {
  2037. lag_check();
  2038. return TRUE;
  2039. }
  2040. static void lastlog(session *sess, char *search, bool regexp)
  2041. {
  2042. session *lastlog_sess;
  2043. if (!is_session(sess))
  2044. return;
  2045. lastlog_sess = find_dialog(sess->server, "(lastlog)");
  2046. if (!lastlog_sess)
  2047. lastlog_sess = new_ircwindow(sess->server, "(lastlog)", SESS_DIALOG, 0);
  2048. lastlog_sess->lastlog_sess = sess;
  2049. lastlog_sess->lastlog_regexp = regexp; // remember the search type
  2050. fe_text_clear(lastlog_sess, 0);
  2051. fe_lastlog(sess, lastlog_sess, search, regexp);
  2052. }
  2053. static int cmd_lastlog(session *sess, char *tbuf, char *word[], char *word_eol[])
  2054. {
  2055. if (*word_eol[2])
  2056. {
  2057. if (!strcmp(word[2], "-r"))
  2058. lastlog(sess, word_eol[3], TRUE);
  2059. else
  2060. lastlog(sess, word_eol[2], FALSE);
  2061. return TRUE;
  2062. }
  2063. return FALSE;
  2064. }
  2065. static int cmd_list(session *sess, char *tbuf, char *word[], char *word_eol[])
  2066. {
  2067. sess->server->p_list_channels(sess->server, word_eol[2], 1);
  2068. return TRUE;
  2069. }
  2070. bool load_perform_file(session *sess, char *file)
  2071. {
  2072. char tbuf[1024 + 4];
  2073. char *nl;
  2074. FILE *fp;
  2075. fp = xchat_fopen_file(file, "r", XOF_FULLPATH);
  2076. if (!fp)
  2077. return FALSE;
  2078. tbuf[1024] = 0;
  2079. while (fgets(tbuf, 1024, fp))
  2080. {
  2081. nl = strchr(tbuf, '\n');
  2082. if (nl == tbuf) // skip empty commands
  2083. continue;
  2084. if (nl)
  2085. *nl = 0;
  2086. if (tbuf[0] == prefs.cmdchar[0])
  2087. handle_command(sess, tbuf + 1, TRUE);
  2088. else
  2089. handle_command(sess, tbuf, TRUE);
  2090. }
  2091. fclose(fp);
  2092. return TRUE;
  2093. }
  2094. static int cmd_load(session *sess, char *tbuf, char *word[], char *word_eol[])
  2095. {
  2096. char *error, *arg, *file;
  2097. int len;
  2098. if (!word[2][0])
  2099. return FALSE;
  2100. if (strcmp (word[2], "-e") == 0)
  2101. {
  2102. file = expand_homedir(word[3]);
  2103. if (!load

Large files files are truncated, but you can click here to view the full file