PageRenderTime 53ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 1ms

/src/gui/gui-chat.c

#
C | 966 lines | 732 code | 115 blank | 119 comment | 165 complexity | 3045ee933daa1bc52122b54e62724459 MD5 | raw file
Possible License(s): GPL-3.0
  1. /*
  2. * Copyright (C) 2003-2012 Sebastien Helleu <flashcode@flashtux.org>
  3. *
  4. * This file is part of WeeChat, the extensible chat client.
  5. *
  6. * WeeChat is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * WeeChat is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with WeeChat. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. /*
  20. * gui-chat.c: chat functions (used by all GUI)
  21. */
  22. #ifdef HAVE_CONFIG_H
  23. #include "config.h"
  24. #endif
  25. #include <stdlib.h>
  26. #include <string.h>
  27. #include <stdarg.h>
  28. #include <ctype.h>
  29. #include <time.h>
  30. #include <regex.h>
  31. #include "../core/weechat.h"
  32. #include "../core/wee-config.h"
  33. #include "../core/wee-hashtable.h"
  34. #include "../core/wee-hook.h"
  35. #include "../core/wee-string.h"
  36. #include "../core/wee-utf8.h"
  37. #include "../plugins/plugin.h"
  38. #include "gui-chat.h"
  39. #include "gui-buffer.h"
  40. #include "gui-color.h"
  41. #include "gui-filter.h"
  42. #include "gui-input.h"
  43. #include "gui-line.h"
  44. #include "gui-main.h"
  45. #include "gui-window.h"
  46. char *gui_chat_prefix[GUI_CHAT_NUM_PREFIXES]; /* prefixes */
  47. char gui_chat_prefix_empty[] = ""; /* empty prefix */
  48. int gui_chat_time_length = 0; /* length of time for each line (in chars) */
  49. int gui_chat_mute = GUI_CHAT_MUTE_DISABLED; /* mute mode */
  50. struct t_gui_buffer *gui_chat_mute_buffer = NULL; /* mute buffer */
  51. int gui_chat_display_tags = 0; /* display tags? */
  52. char *gui_chat_lines_waiting_buffer = NULL; /* lines waiting for core */
  53. /* buffer */
  54. /*
  55. * gui_chat_init: init some variables for chat area
  56. * (called before reading WeeChat config file)
  57. */
  58. void
  59. gui_chat_init ()
  60. {
  61. /* build empty prefixes */
  62. gui_chat_prefix[GUI_CHAT_PREFIX_ERROR] = strdup (gui_chat_prefix_empty);
  63. gui_chat_prefix[GUI_CHAT_PREFIX_NETWORK] = strdup (gui_chat_prefix_empty);
  64. gui_chat_prefix[GUI_CHAT_PREFIX_ACTION] = strdup (gui_chat_prefix_empty);
  65. gui_chat_prefix[GUI_CHAT_PREFIX_JOIN] = strdup (gui_chat_prefix_empty);
  66. gui_chat_prefix[GUI_CHAT_PREFIX_QUIT] = strdup (gui_chat_prefix_empty);
  67. /* some hsignals */
  68. hook_hsignal (NULL, "chat_quote_time_prefix_message",
  69. &gui_chat_hsignal_quote_line_cb, NULL);
  70. hook_hsignal (NULL, "chat_quote_prefix_message",
  71. &gui_chat_hsignal_quote_line_cb, NULL);
  72. hook_hsignal (NULL, "chat_quote_message",
  73. &gui_chat_hsignal_quote_line_cb, NULL);
  74. }
  75. /*
  76. * gui_chat_prefix_build: build prefix with colors
  77. * (called after reading WeeChat config file)
  78. */
  79. void
  80. gui_chat_prefix_build ()
  81. {
  82. char prefix[128];
  83. int i;
  84. for (i = 0; i < GUI_CHAT_NUM_PREFIXES; i++)
  85. {
  86. if (gui_chat_prefix[i])
  87. {
  88. free (gui_chat_prefix[i]);
  89. gui_chat_prefix[i] = NULL;
  90. }
  91. }
  92. snprintf (prefix, sizeof (prefix), "%s%s\t",
  93. GUI_COLOR(GUI_COLOR_CHAT_PREFIX_ERROR),
  94. CONFIG_STRING(config_look_prefix[GUI_CHAT_PREFIX_ERROR]));
  95. gui_chat_prefix[GUI_CHAT_PREFIX_ERROR] = strdup (prefix);
  96. snprintf (prefix, sizeof (prefix), "%s%s\t",
  97. GUI_COLOR(GUI_COLOR_CHAT_PREFIX_NETWORK),
  98. CONFIG_STRING(config_look_prefix[GUI_CHAT_PREFIX_NETWORK]));
  99. gui_chat_prefix[GUI_CHAT_PREFIX_NETWORK] = strdup (prefix);
  100. snprintf (prefix, sizeof (prefix), "%s%s\t",
  101. GUI_COLOR(GUI_COLOR_CHAT_PREFIX_ACTION),
  102. CONFIG_STRING(config_look_prefix[GUI_CHAT_PREFIX_ACTION]));
  103. gui_chat_prefix[GUI_CHAT_PREFIX_ACTION] = strdup (prefix);
  104. snprintf (prefix, sizeof (prefix), "%s%s\t",
  105. GUI_COLOR(GUI_COLOR_CHAT_PREFIX_JOIN),
  106. CONFIG_STRING(config_look_prefix[GUI_CHAT_PREFIX_JOIN]));
  107. gui_chat_prefix[GUI_CHAT_PREFIX_JOIN] = strdup (prefix);
  108. snprintf (prefix, sizeof (prefix), "%s%s\t",
  109. GUI_COLOR(GUI_COLOR_CHAT_PREFIX_QUIT),
  110. CONFIG_STRING(config_look_prefix[GUI_CHAT_PREFIX_QUIT]));
  111. gui_chat_prefix[GUI_CHAT_PREFIX_QUIT] = strdup (prefix);
  112. }
  113. /*
  114. * gui_chat_utf_char_valid: return 1 if utf char is valid for screen
  115. * otherwise return 0
  116. */
  117. int
  118. gui_chat_utf_char_valid (const char *utf_char)
  119. {
  120. /* chars below 32 are not valid */
  121. if ((unsigned char)utf_char[0] < 32)
  122. return 0;
  123. /* 146 or 0x7F are not valid */
  124. if ((((unsigned char)(utf_char[0]) == 146)
  125. || ((unsigned char)(utf_char[0]) == 0x7F))
  126. && (!utf_char[1]))
  127. return 0;
  128. /* any other char is valid */
  129. return 1;
  130. }
  131. /*
  132. * gui_chat_strlen_screen: returns number of char needed on sreen to display a
  133. * word special chars like color, bold, .. are ignored
  134. */
  135. int
  136. gui_chat_strlen_screen (const char *string)
  137. {
  138. int length, size_on_screen;
  139. length = 0;
  140. while (string && string[0])
  141. {
  142. string = gui_chat_string_next_char (NULL, NULL,
  143. (unsigned char *)string, 0, 0);
  144. if (string)
  145. {
  146. size_on_screen = (gui_chat_utf_char_valid (string)) ? utf8_char_size_screen (string) : 1;
  147. if (size_on_screen > 0)
  148. length += size_on_screen;
  149. string = utf8_next_char (string);
  150. }
  151. }
  152. return length;
  153. }
  154. /*
  155. * gui_chat_string_add_offset: move forward N chars in a string, skipping all
  156. * formatting chars (like colors,..)
  157. */
  158. char *
  159. gui_chat_string_add_offset (const char *string, int offset)
  160. {
  161. while (string && string[0] && (offset > 0))
  162. {
  163. string = gui_chat_string_next_char (NULL, NULL,
  164. (unsigned char *)string,
  165. 0, 0);
  166. if (string)
  167. {
  168. string = utf8_next_char (string);
  169. offset--;
  170. }
  171. }
  172. return (char *)string;
  173. }
  174. /*
  175. * gui_chat_string_add_offset_screen: move forward N chars (using size on screen)
  176. * in a string, skipping all formatting chars
  177. * (like colors,..)
  178. */
  179. char *
  180. gui_chat_string_add_offset_screen (const char *string, int offset_screen)
  181. {
  182. int size_on_screen;
  183. while (string && string[0] && (offset_screen > 0))
  184. {
  185. string = gui_chat_string_next_char (NULL, NULL,
  186. (unsigned char *)string,
  187. 0, 0);
  188. if (string)
  189. {
  190. size_on_screen = (gui_chat_utf_char_valid (string)) ? utf8_char_size_screen (string) : 1;
  191. offset_screen -= size_on_screen;
  192. string = utf8_next_char (string);
  193. }
  194. }
  195. return (char *)string;
  196. }
  197. /*
  198. * gui_chat_string_real_pos: get real position in string
  199. * (ignoring color/bold/.. chars)
  200. */
  201. int
  202. gui_chat_string_real_pos (const char *string, int pos)
  203. {
  204. const char *real_pos, *real_pos_prev, *ptr_string;
  205. int size_on_screen;
  206. if (pos <= 0)
  207. return 0;
  208. real_pos = string;
  209. real_pos_prev = string;
  210. ptr_string = string;
  211. while (ptr_string && ptr_string[0] && (pos > 0))
  212. {
  213. ptr_string = gui_chat_string_next_char (NULL, NULL,
  214. (unsigned char *)ptr_string,
  215. 0, 0);
  216. if (ptr_string)
  217. {
  218. size_on_screen = (((unsigned char)ptr_string[0]) < 32) ? 1 : utf8_char_size_screen (ptr_string);
  219. if (size_on_screen > 0)
  220. pos -= size_on_screen;
  221. ptr_string = utf8_next_char (ptr_string);
  222. real_pos_prev = real_pos;
  223. real_pos = ptr_string;
  224. }
  225. }
  226. if (pos < 0)
  227. real_pos = real_pos_prev;
  228. return 0 + (real_pos - string);
  229. }
  230. /*
  231. * gui_chat_get_word_info: returns info about next word: beginning, end, length
  232. */
  233. void
  234. gui_chat_get_word_info (struct t_gui_window *window,
  235. const char *data,
  236. int *word_start_offset, int *word_end_offset,
  237. int *word_length_with_spaces, int *word_length)
  238. {
  239. const char *start_data;
  240. char *next_char, *next_char2;
  241. int leading_spaces, char_size;
  242. *word_start_offset = 0;
  243. *word_end_offset = 0;
  244. *word_length_with_spaces = 0;
  245. *word_length = 0;
  246. start_data = data;
  247. leading_spaces = 1;
  248. while (data && data[0])
  249. {
  250. next_char = gui_chat_string_next_char (window, NULL,
  251. (unsigned char *)data, 0, 0);
  252. if (next_char)
  253. {
  254. next_char2 = utf8_next_char (next_char);
  255. if (next_char2)
  256. {
  257. if (next_char[0] != ' ')
  258. {
  259. if (leading_spaces)
  260. *word_start_offset = next_char - start_data;
  261. leading_spaces = 0;
  262. char_size = next_char2 - next_char;
  263. *word_end_offset = next_char2 - start_data - 1;
  264. (*word_length_with_spaces) += char_size;
  265. (*word_length) += char_size;
  266. }
  267. else
  268. {
  269. if (leading_spaces)
  270. (*word_length_with_spaces)++;
  271. else
  272. {
  273. *word_end_offset = next_char - start_data - 1;
  274. return;
  275. }
  276. }
  277. data = next_char2;
  278. }
  279. }
  280. else
  281. {
  282. *word_end_offset = data + strlen (data) - start_data - 1;
  283. return;
  284. }
  285. }
  286. }
  287. /*
  288. * gu_chat_get_time_string: get time string, for display (with colors)
  289. */
  290. char *
  291. gui_chat_get_time_string (time_t date)
  292. {
  293. char text_time[128], text_time2[(128*3)+16], text_time_char[2];
  294. char *text_with_color;
  295. int i, time_first_digit, time_last_digit, last_color;
  296. struct tm *local_time;
  297. if (!CONFIG_STRING(config_look_buffer_time_format)
  298. || !CONFIG_STRING(config_look_buffer_time_format)[0])
  299. return NULL;
  300. local_time = localtime (&date);
  301. if (!local_time)
  302. return NULL;
  303. if (strftime (text_time, sizeof (text_time),
  304. CONFIG_STRING(config_look_buffer_time_format),
  305. local_time) == 0)
  306. return NULL;
  307. if (strstr (text_time, "${"))
  308. {
  309. text_with_color = gui_color_string_replace_colors (text_time);
  310. if (text_with_color)
  311. {
  312. if (strcmp (text_time, text_with_color) != 0)
  313. return text_with_color;
  314. free (text_with_color);
  315. }
  316. }
  317. time_first_digit = -1;
  318. time_last_digit = -1;
  319. i = 0;
  320. while (text_time[i])
  321. {
  322. if (isdigit ((unsigned char)text_time[i]))
  323. {
  324. if (time_first_digit == -1)
  325. time_first_digit = i;
  326. time_last_digit = i;
  327. }
  328. i++;
  329. }
  330. text_time2[0] = '\0';
  331. text_time_char[1] = '\0';
  332. last_color = -1;
  333. i = 0;
  334. while (text_time[i])
  335. {
  336. text_time_char[0] = text_time[i];
  337. if (time_first_digit < 0)
  338. {
  339. if (last_color != GUI_COLOR_CHAT_TIME)
  340. {
  341. strcat (text_time2, GUI_COLOR(GUI_COLOR_CHAT_TIME));
  342. last_color = GUI_COLOR_CHAT_TIME;
  343. }
  344. strcat (text_time2, text_time_char);
  345. }
  346. else
  347. {
  348. if ((i < time_first_digit) || (i > time_last_digit))
  349. {
  350. if (last_color != GUI_COLOR_CHAT_DELIMITERS)
  351. {
  352. strcat (text_time2, GUI_COLOR(GUI_COLOR_CHAT_DELIMITERS));
  353. last_color = GUI_COLOR_CHAT_DELIMITERS;
  354. }
  355. strcat (text_time2, text_time_char);
  356. }
  357. else
  358. {
  359. if (isdigit ((unsigned char)text_time[i]))
  360. {
  361. if (last_color != GUI_COLOR_CHAT_TIME)
  362. {
  363. strcat (text_time2, GUI_COLOR(GUI_COLOR_CHAT_TIME));
  364. last_color = GUI_COLOR_CHAT_TIME;
  365. }
  366. strcat (text_time2, text_time_char);
  367. }
  368. else
  369. {
  370. if (last_color != GUI_COLOR_CHAT_TIME_DELIMITERS)
  371. {
  372. strcat (text_time2,
  373. GUI_COLOR(GUI_COLOR_CHAT_TIME_DELIMITERS));
  374. last_color = GUI_COLOR_CHAT_TIME_DELIMITERS;
  375. }
  376. strcat (text_time2, text_time_char);
  377. }
  378. }
  379. }
  380. i++;
  381. }
  382. return strdup (text_time2);
  383. }
  384. /*
  385. * gui_chat_get_time_length: calculates time length with a time format
  386. * (format can include color codes with format ${name})
  387. */
  388. int
  389. gui_chat_get_time_length ()
  390. {
  391. time_t date;
  392. char *text_time;
  393. int length;
  394. if (!CONFIG_STRING(config_look_buffer_time_format)
  395. || !CONFIG_STRING(config_look_buffer_time_format)[0])
  396. return 0;
  397. length = 0;
  398. date = time (NULL);
  399. text_time = gui_chat_get_time_string (date);
  400. if (text_time)
  401. {
  402. length = gui_chat_strlen_screen (text_time);
  403. free (text_time);
  404. }
  405. return length;
  406. }
  407. /*
  408. * gui_chat_change_time_format: change time format for all lines of all buffers
  409. */
  410. void
  411. gui_chat_change_time_format ()
  412. {
  413. struct t_gui_buffer *ptr_buffer;
  414. struct t_gui_line *ptr_line;
  415. for (ptr_buffer = gui_buffers; ptr_buffer;
  416. ptr_buffer = ptr_buffer->next_buffer)
  417. {
  418. for (ptr_line = ptr_buffer->lines->first_line; ptr_line;
  419. ptr_line = ptr_line->next_line)
  420. {
  421. if (ptr_line->data->date != 0)
  422. {
  423. if (ptr_line->data->str_time)
  424. free (ptr_line->data->str_time);
  425. ptr_line->data->str_time = gui_chat_get_time_string (ptr_line->data->date);
  426. }
  427. }
  428. }
  429. }
  430. /*
  431. * gui_chat_build_string_prefix_message: build a string with prefix and message
  432. */
  433. char *
  434. gui_chat_build_string_prefix_message (struct t_gui_line *line)
  435. {
  436. char *string, *string_without_colors;
  437. int length;
  438. length = 0;
  439. if (line->data->prefix)
  440. length += strlen (line->data->prefix);
  441. length++;
  442. if (line->data->message)
  443. length += strlen (line->data->message);
  444. length++;
  445. string = malloc (length);
  446. if (string)
  447. {
  448. string[0] = '\0';
  449. if (line->data->prefix)
  450. strcat (string, line->data->prefix);
  451. strcat (string, "\t");
  452. if (line->data->message)
  453. strcat (string, line->data->message);
  454. }
  455. if (string)
  456. {
  457. string_without_colors = gui_color_decode (string, NULL);
  458. if (string_without_colors)
  459. {
  460. free (string);
  461. string = string_without_colors;
  462. }
  463. }
  464. return string;
  465. }
  466. /*
  467. * gui_chat_build_string_prefix_message: build a string with message and tags
  468. */
  469. char *
  470. gui_chat_build_string_message_tags (struct t_gui_line *line)
  471. {
  472. int i, length;
  473. char *buf;
  474. length = 64 + 2;
  475. if (line->data->message)
  476. length += strlen (line->data->message);
  477. for (i = 0; i < line->data->tags_count; i++)
  478. {
  479. length += strlen (line->data->tags_array[i]) + 1;
  480. }
  481. length += 2;
  482. buf = malloc (length);
  483. buf[0] = '\0';
  484. if (line->data->message)
  485. strcat (buf, line->data->message);
  486. strcat (buf, GUI_COLOR(GUI_COLOR_CHAT_DELIMITERS));
  487. strcat (buf, " [");
  488. strcat (buf, GUI_COLOR(GUI_COLOR_CHAT_TAGS));
  489. for (i = 0; i < line->data->tags_count; i++)
  490. {
  491. strcat (buf, line->data->tags_array[i]);
  492. if (i < line->data->tags_count - 1)
  493. strcat (buf, ",");
  494. }
  495. strcat (buf, GUI_COLOR(GUI_COLOR_CHAT_DELIMITERS));
  496. strcat (buf, "]");
  497. return buf;
  498. }
  499. /*
  500. * gui_chat_printf_date_tags: display a message in a buffer with optional
  501. * date and tags
  502. * Info: this function works only with formatted
  503. * buffers (not buffers with free content)
  504. */
  505. void
  506. gui_chat_printf_date_tags (struct t_gui_buffer *buffer, time_t date,
  507. const char *tags, const char *message, ...)
  508. {
  509. time_t date_printed;
  510. int display_time, length, at_least_one_message_printed;
  511. char *pos, *pos_prefix, *pos_tab, *pos_end, *pos_lines;
  512. char *modifier_data, *new_msg, *ptr_msg, *lines_waiting;
  513. struct t_gui_line *ptr_line;
  514. if (!gui_buffer_valid (buffer))
  515. return;
  516. if (!message)
  517. return;
  518. if (gui_init_ok)
  519. {
  520. if (!buffer)
  521. buffer = gui_buffer_search_main ();
  522. if (!buffer)
  523. return;
  524. if (buffer->type != GUI_BUFFER_TYPE_FORMATTED)
  525. buffer = gui_buffers;
  526. if (buffer->type != GUI_BUFFER_TYPE_FORMATTED)
  527. return;
  528. }
  529. /* if mute is enabled for buffer (or all buffers), then just return */
  530. if ((gui_chat_mute == GUI_CHAT_MUTE_ALL_BUFFERS)
  531. || ((gui_chat_mute == GUI_CHAT_MUTE_BUFFER)
  532. && (gui_chat_mute_buffer == buffer)))
  533. return;
  534. weechat_va_format (message);
  535. if (!vbuffer)
  536. return;
  537. utf8_normalize (vbuffer, '?');
  538. date_printed = time (NULL);
  539. if (date <= 0)
  540. date = date_printed;
  541. at_least_one_message_printed = 0;
  542. pos = vbuffer;
  543. while (pos)
  544. {
  545. /* display until next end of line */
  546. pos_end = strchr (pos, '\n');
  547. if (pos_end)
  548. pos_end[0] = '\0';
  549. /* call modifier for message printed ("weechat_print") */
  550. new_msg = NULL;
  551. if (buffer)
  552. {
  553. length = strlen (gui_buffer_get_plugin_name (buffer)) + 1 +
  554. strlen (buffer->name) + 1 + ((tags) ? strlen (tags) : 0) + 1;
  555. modifier_data = malloc (length);
  556. if (modifier_data)
  557. {
  558. snprintf (modifier_data, length, "%s;%s;%s",
  559. gui_buffer_get_plugin_name (buffer),
  560. buffer->name,
  561. (tags) ? tags : "");
  562. new_msg = hook_modifier_exec (NULL,
  563. "weechat_print",
  564. modifier_data,
  565. pos);
  566. free (modifier_data);
  567. if (new_msg)
  568. {
  569. if (!new_msg[0] && pos[0])
  570. {
  571. /*
  572. * modifier returned empty message, then we'll not
  573. * print anything
  574. */
  575. free (new_msg);
  576. goto end;
  577. }
  578. if (strcmp (message, new_msg) == 0)
  579. {
  580. /* no changes in new message */
  581. free (new_msg);
  582. new_msg = NULL;
  583. }
  584. }
  585. }
  586. }
  587. pos_prefix = NULL;
  588. display_time = 1;
  589. ptr_msg = (new_msg) ? new_msg : pos;
  590. /* space followed by tab => prefix ignored */
  591. if ((ptr_msg[0] == ' ') && (ptr_msg[1] == '\t'))
  592. {
  593. ptr_msg += 2;
  594. }
  595. else
  596. {
  597. /* if two first chars are tab, then do not display time */
  598. if ((ptr_msg[0] == '\t') && (ptr_msg[1] == '\t'))
  599. {
  600. display_time = 0;
  601. ptr_msg += 2;
  602. }
  603. else
  604. {
  605. /* if tab found, use prefix (before tab) */
  606. pos_tab = strchr (ptr_msg, '\t');
  607. if (pos_tab)
  608. {
  609. pos_tab[0] = '\0';
  610. pos_prefix = ptr_msg;
  611. ptr_msg = pos_tab + 1;
  612. }
  613. }
  614. }
  615. if (gui_init_ok)
  616. {
  617. ptr_line = gui_line_add (buffer, (display_time) ? date : 0,
  618. (display_time) ? date_printed : 0,
  619. tags, pos_prefix, ptr_msg);
  620. if (ptr_line)
  621. {
  622. if (buffer && buffer->print_hooks_enabled)
  623. hook_print_exec (buffer, ptr_line);
  624. if (ptr_line->data->displayed)
  625. at_least_one_message_printed = 1;
  626. }
  627. }
  628. else
  629. {
  630. length = ((pos_prefix) ? strlen (pos_prefix) + 1 : 0) +
  631. strlen (ptr_msg) + 1;
  632. if (gui_chat_lines_waiting_buffer)
  633. {
  634. length += strlen (gui_chat_lines_waiting_buffer) + 1;
  635. lines_waiting = realloc (gui_chat_lines_waiting_buffer, length);
  636. if (lines_waiting)
  637. {
  638. gui_chat_lines_waiting_buffer = lines_waiting;
  639. }
  640. else
  641. {
  642. free (gui_chat_lines_waiting_buffer);
  643. gui_chat_lines_waiting_buffer = NULL;
  644. }
  645. }
  646. else
  647. {
  648. gui_chat_lines_waiting_buffer = malloc (length);
  649. if (gui_chat_lines_waiting_buffer)
  650. gui_chat_lines_waiting_buffer[0] = '\0';
  651. }
  652. if (gui_chat_lines_waiting_buffer)
  653. {
  654. pos_lines = gui_chat_lines_waiting_buffer +
  655. strlen (gui_chat_lines_waiting_buffer);
  656. if (pos_lines > gui_chat_lines_waiting_buffer)
  657. {
  658. pos_lines[0] = '\n';
  659. pos_lines++;
  660. }
  661. if (pos_prefix)
  662. {
  663. memcpy (pos_lines, pos_prefix, strlen (pos_prefix));
  664. pos_lines += strlen (pos_prefix);
  665. pos_lines[0] = '\t';
  666. pos_lines++;
  667. }
  668. memcpy (pos_lines, ptr_msg, strlen (ptr_msg) + 1);
  669. }
  670. }
  671. if (new_msg)
  672. free (new_msg);
  673. pos = (pos_end && pos_end[1]) ? pos_end + 1 : NULL;
  674. }
  675. if (gui_init_ok && at_least_one_message_printed)
  676. gui_buffer_ask_chat_refresh (buffer, 1);
  677. end:
  678. free (vbuffer);
  679. }
  680. /*
  681. * gui_chat_printf_y: display a message on a line in a buffer with free content
  682. * Info: this function works only with free content
  683. * buffers (not formatted buffers)
  684. */
  685. void
  686. gui_chat_printf_y (struct t_gui_buffer *buffer, int y, const char *message, ...)
  687. {
  688. struct t_gui_line *ptr_line;
  689. int i, num_lines_to_add;
  690. if (gui_init_ok)
  691. {
  692. if (!buffer)
  693. buffer = gui_buffer_search_main ();
  694. if (buffer->type != GUI_BUFFER_TYPE_FREE)
  695. buffer = gui_buffers;
  696. if (buffer->type != GUI_BUFFER_TYPE_FREE)
  697. return;
  698. }
  699. weechat_va_format (message);
  700. if (!vbuffer)
  701. return;
  702. utf8_normalize (vbuffer, '?');
  703. /* no message: delete line */
  704. if (!vbuffer[0])
  705. {
  706. if (gui_init_ok)
  707. {
  708. for (ptr_line = buffer->own_lines->first_line; ptr_line;
  709. ptr_line = ptr_line->next_line)
  710. {
  711. if (ptr_line->data->y >= y)
  712. break;
  713. }
  714. if (ptr_line && (ptr_line->data->y == y))
  715. {
  716. if (ptr_line->next_line)
  717. gui_line_clear (ptr_line);
  718. else
  719. gui_line_free (buffer, ptr_line);
  720. gui_buffer_ask_chat_refresh (buffer, 2);
  721. }
  722. }
  723. }
  724. else
  725. {
  726. if (gui_init_ok)
  727. {
  728. num_lines_to_add = 0;
  729. if (buffer->own_lines && buffer->own_lines->last_line)
  730. num_lines_to_add = y - buffer->own_lines->last_line->data->y - 1;
  731. else
  732. num_lines_to_add = y;
  733. if (num_lines_to_add > 0)
  734. {
  735. /*
  736. * add empty line(s) before asked line, to ensure there is at
  737. * least "y" lines in buffer, and then be able to scroll
  738. * properly buffer page by page
  739. */
  740. for (i = y - num_lines_to_add; i < y; i++)
  741. {
  742. gui_line_add_y (buffer, i, "");
  743. }
  744. }
  745. gui_line_add_y (buffer, y, vbuffer);
  746. gui_buffer_ask_chat_refresh (buffer, 1);
  747. }
  748. else
  749. string_iconv_fprintf (stdout, "%s\n", vbuffer);
  750. }
  751. free (vbuffer);
  752. }
  753. /*
  754. * gui_chat_print_lines_waiting_buffer: print lines waiting for buffer
  755. */
  756. void
  757. gui_chat_print_lines_waiting_buffer ()
  758. {
  759. char **lines;
  760. int num_lines, i;
  761. if (gui_chat_lines_waiting_buffer)
  762. {
  763. lines = string_split (gui_chat_lines_waiting_buffer, "\n", 0, 0,
  764. &num_lines);
  765. if (lines)
  766. {
  767. for (i = 0; i < num_lines; i++)
  768. {
  769. gui_chat_printf (NULL, lines[i]);
  770. }
  771. string_free_split (lines);
  772. }
  773. /*
  774. * gui_chat_lines_waiting_buffer may be NULL after call to
  775. * gui_chat_printf (if not enough memory)
  776. */
  777. }
  778. if (gui_chat_lines_waiting_buffer)
  779. {
  780. free (gui_chat_lines_waiting_buffer);
  781. gui_chat_lines_waiting_buffer = NULL;
  782. }
  783. }
  784. /*
  785. * gui_chat_hsignal_chat_quote_line_cb: quote a line
  786. */
  787. int
  788. gui_chat_hsignal_quote_line_cb (void *data, const char *signal,
  789. struct t_hashtable *hashtable)
  790. {
  791. const char *time, *prefix, *message;
  792. int length_time, length_prefix, length_message, length;
  793. char *str;
  794. /* make C compiler happy */
  795. (void) data;
  796. if (!gui_current_window->buffer->input)
  797. return WEECHAT_RC_OK;
  798. time = (strstr (signal, "time")) ?
  799. hashtable_get (hashtable, "_chat_line_time") : NULL;
  800. prefix = (strstr (signal, "prefix")) ?
  801. hashtable_get (hashtable, "_chat_line_prefix") : NULL;
  802. message = hashtable_get (hashtable, "_chat_line_message");
  803. if (!message)
  804. return WEECHAT_RC_OK;
  805. length_time = (time) ? strlen (time) : 0;
  806. length_prefix = (prefix) ? strlen (prefix) : 0;
  807. length_message = strlen (message);
  808. length = length_time + 1 + length_prefix + 1 +
  809. strlen (CONFIG_STRING(config_look_prefix_suffix)) + 1 +
  810. length_message + 1 + 1;
  811. str = malloc (length);
  812. if (str)
  813. {
  814. snprintf (str, length, "%s%s%s%s%s%s%s ",
  815. (time) ? time : "",
  816. (time) ? " " : "",
  817. (prefix) ? prefix : "",
  818. (prefix) ? " " : "",
  819. (time || prefix) ? CONFIG_STRING(config_look_prefix_suffix) : "",
  820. ((time || prefix) && CONFIG_STRING(config_look_prefix_suffix)
  821. && CONFIG_STRING(config_look_prefix_suffix)[0]) ? " " : "",
  822. message);
  823. gui_input_insert_string (gui_current_window->buffer, str, -1);
  824. gui_input_text_changed_modifier_and_signal (gui_current_window->buffer, 1);
  825. free (str);
  826. }
  827. return WEECHAT_RC_OK;
  828. }
  829. /*
  830. * gui_chat_end: free some variables allocated for chat area
  831. */
  832. void
  833. gui_chat_end ()
  834. {
  835. int i;
  836. /* free prefixes */
  837. for (i = 0; i < GUI_CHAT_NUM_PREFIXES; i++)
  838. {
  839. if (gui_chat_prefix[i])
  840. {
  841. free (gui_chat_prefix[i]);
  842. gui_chat_prefix[i] = NULL;
  843. }
  844. }
  845. /* free lines waiting for buffer (should always be NULL here) */
  846. if (gui_chat_lines_waiting_buffer)
  847. {
  848. free (gui_chat_lines_waiting_buffer);
  849. gui_chat_lines_waiting_buffer = NULL;
  850. }
  851. }