+static void paste_buffer_join_lines(GArray *buf)
+{
+#define IS_WHITE(c) ((c) == ' ' || (c) == '\t')
+ unsigned int i, count, indent, line_len;
+ unichar *arr, *dest, *last_lf_pos;
+ int last_lf;
+
+ /* first check if we actually want to join anything. This is assuming
+ that we only want to join lines if
+
+ a) first line doesn't begin with whitespace
+ b) subsequent lines begin with same amount of whitespace
+ c) whenever there's no whitespace, goto a)
+
+ For example:
+
+ line 1
+ line 2
+ line 3
+ line 4
+ line 5
+ line 6
+
+ ->
+
+ line1 line2 line 3
+ line4
+ line5 line 6
+ */
+ if (buf->len == 0)
+ return;
+
+ arr = (unichar *) paste_buffer->data;
+
+ /* first line */
+ if (IS_WHITE(arr[0]))
+ return;
+
+ /* find the first beginning of indented line */
+ for (i = 1; i < buf->len; i++) {
+ if (arr[i-1] == '\n' && IS_WHITE(arr[i]))
+ break;
+ }
+ if (i == buf->len)
+ return;
+
+ /* get how much indentation we have.. */
+ for (indent = 0; i < buf->len; i++, indent++) {
+ if (!IS_WHITE(arr[i]))
+ break;
+ }
+ if (i == buf->len)
+ return;
+
+ /* now, enforce these to all subsequent lines */
+ count = indent; last_lf = TRUE;
+ for (; i < buf->len; i++) {
+ if (last_lf) {
+ if (IS_WHITE(arr[i]))
+ count++;
+ else {
+ last_lf = FALSE;
+ if (count != 0 && count != indent)
+ return;
+ count = 0;
+ }
+ }
+ if (arr[i] == '\n')
+ last_lf = TRUE;
+ }
+
+ /* all looks fine - now remove the whitespace, but don't let lines
+ get longer than 400 chars */
+ dest = arr; last_lf = TRUE; last_lf_pos = NULL; line_len = 0;
+ for (i = 0; i < buf->len; i++) {
+ if (last_lf && IS_WHITE(arr[i])) {
+ /* whitespace, ignore */
+ } else if (arr[i] == '\n') {
+ if (!last_lf && i+1 != buf->len &&
+ IS_WHITE(arr[i+1])) {
+ last_lf_pos = dest;
+ *dest++ = ' ';
+ } else {
+ *dest++ = '\n'; /* double-LF */
+ line_len = 0;
+ last_lf_pos = NULL;
+ }
+ last_lf = TRUE;
+ } else {
+ last_lf = FALSE;
+ if (++line_len >= 400 && last_lf_pos != NULL) {
+ memmove(last_lf_pos+1, last_lf_pos,
+ dest - last_lf_pos);
+ *last_lf_pos = '\n'; last_lf_pos = NULL;
+ line_len = 0;
+ dest++;
+ }
+ *dest++ = arr[i];
+ }
+ }
+ g_array_set_size(buf, dest - arr);
+}
+
+static void paste_send(void)
+{
+ HISTORY_REC *history;
+ unichar *arr;
+ GString *str;
+ char out[10], *text;
+ unsigned int i;
+
+ if (paste_join_multiline)
+ paste_buffer_join_lines(paste_buffer);
+
+ arr = (unichar *) paste_buffer->data;
+ if (active_entry->text_len == 0)
+ i = 0;
+ else {
+ /* first line has to be kludged kind of to get pasting in the
+ middle of line right.. */
+ for (i = 0; i < paste_buffer->len; i++) {
+ if (arr[i] == '\r' || arr[i] == '\n') {
+ i++;
+ break;
+ }
+
+ gui_entry_insert_char(active_entry, arr[i]);
+ }
+
+ text = gui_entry_get_text(active_entry);
+ history = command_history_current(active_win);
+ command_history_add(history, text);
+
+ translate_output(text);
+ signal_emit("send command", 3, text,
+ active_win->active_server, active_win->active);
+ g_free(text);
+ }
+
+ /* rest of the lines */
+ str = g_string_new(NULL);
+ for (; i < paste_buffer->len; i++) {
+ if (arr[i] == '\r' || arr[i] == '\n') {
+ history = command_history_current(active_win);
+ command_history_add(history, str->str);
+
+ translate_output(str->str);
+ signal_emit("send command", 3, str->str,
+ active_win->active_server,
+ active_win->active);
+ g_string_truncate(str, 0);
+ } else if (active_entry->utf8) {
+ out[utf16_char_to_utf8(arr[i], out)] = '\0';
+ g_string_append(str, out);
+ } else if (term_type == TERM_TYPE_BIG5) {
+ if (arr[i] > 0xff)
+ g_string_append_c(str, (arr[i] >> 8) & 0xff);
+ g_string_append_c(str, arr[i] & 0xff);
+ } else {
+ g_string_append_c(str, arr[i]);
+ }
+ }
+
+ gui_entry_set_text(active_entry, str->str);
+ g_string_free(str, TRUE);
+}
+
+static void paste_flush(int send)
+{
+ gui_entry_set_text(active_entry, paste_entry);
+ gui_entry_set_pos(active_entry, paste_entry_pos);
+
+ if (send)
+ paste_send();
+ g_array_set_size(paste_buffer, 0);
+
+ gui_entry_set_prompt(active_entry,
+ paste_old_prompt == NULL ? "" : paste_old_prompt);
+ g_free(paste_old_prompt); paste_old_prompt = NULL;
+ paste_prompt = FALSE;
+
+ paste_line_count = 0;
+ paste_state = 0;
+ paste_keycount = 0;
+
+ gui_entry_redraw(active_entry);
+}
+
+static gboolean paste_timeout(gpointer data)
+{
+ GTimeVal now;
+ char *str;
+ int diff;
+
+ if (paste_state == 0) {
+ /* gone already */
+ return FALSE;
+ }
+
+ g_get_current_time(&now);
+ diff = (now.tv_sec - last_keypress.tv_sec) * 1000 +
+ (now.tv_usec - last_keypress.tv_usec)/1000;
+
+ if (diff < paste_detect_time) {
+ /* still pasting */
+ return TRUE;
+ }
+
+ if (paste_line_count < paste_verify_line_count ||
+ active_win->active == NULL) {
+ /* paste without asking */
+ paste_flush(TRUE);
+ } else if (!paste_prompt) {
+ paste_prompt = TRUE;
+ paste_old_prompt = g_strdup(active_entry->prompt);
+ printformat_window(active_win, MSGLEVEL_CLIENTNOTICE,
+ TXT_PASTE_WARNING,
+ paste_line_count,
+ active_win->active == NULL ? "window" :
+ active_win->active->visible_name);
+
+ str = format_get_text(MODULE_NAME, active_win, NULL, NULL,
+ TXT_PASTE_PROMPT, 0, 0);
+ gui_entry_set_prompt(active_entry, str);
+ gui_entry_set_text(active_entry, "");
+ g_free(str);
+ }
+ return TRUE;
+}
+
+static int check_pasting(unichar key, int diff)
+{
+ if (paste_state < 0)
+ return FALSE;
+
+ if (paste_state == 0) {
+ /* two keys hit together quick. possibly pasting */
+ if (diff > paste_detect_time)
+ return FALSE;
+
+ g_free(paste_entry);
+ paste_entry = g_strdup(prev_entry);
+ paste_entry_pos = prev_entry_pos;
+
+ paste_state++;
+ paste_line_count = 0;
+ paste_keycount = 0;
+ g_array_set_size(paste_buffer, 0);
+ if (prev_key != '\r' && prev_key != '\n')
+ g_array_append_val(paste_buffer, prev_key);
+ } else if (paste_state > 0 && diff > paste_detect_time &&
+ paste_line_count == 0) {
+ /* reset paste state */
+ paste_state = 0;
+ paste_keycount = 0;
+ return FALSE;
+ }
+
+ /* continuing quick hits */
+ if ((key == 11 || key == 3) && paste_prompt) {
+ paste_flush(key == 11);
+ return TRUE;
+ }
+
+ g_array_append_val(paste_buffer, key);
+ if (key == '\r' || key == '\n') {
+ if (paste_state == 1 &&
+ paste_keycount < paste_detect_keycount) {
+ /* not enough keypresses to determine if this is
+ pasting or not. don't reset paste keycount, but
+ send this line as non-pasted */
+ g_array_set_size(paste_buffer, 0);
+ return FALSE;
+ }
+
+ /* newline - assume this line was pasted */
+ if (paste_state == 1) {
+ paste_state = 2;
+ gui_entry_set_text(active_entry, paste_entry);
+ gui_entry_set_pos(active_entry, paste_entry_pos);
+ if (paste_verify_line_count > 0)
+ g_timeout_add(100, paste_timeout, NULL);
+ }
+
+ if (paste_verify_line_count <= 0) {
+ /* paste previous line */
+ paste_send();
+ g_array_set_size(paste_buffer, 0);
+ } else {
+ paste_line_count++;
+ }
+ }
+
+ return paste_state == 2;
+}
+