raster pushed a commit to branch master. http://git.enlightenment.org/apps/terminology.git/commit/?id=125d4750683141395bb5de38e4c415d31c5ed8c9
commit 125d4750683141395bb5de38e4c415d31c5ed8c9 Author: Carsten Haitzler (Rasterman) <[email protected]> Date: Sun Dec 17 23:36:51 2017 +0900 add tysend cmdline and support in escapes for sending single files this allows you to send a file via escapes to terminology which will pop up a file save dialog and ask what to save it as and where (based on the original name). terminology will show a progress bar too. this is not useful locally but remotely (e.g. you ssh'd into another machine) it's a VERY handy way of fetching a file from the remote machine to the local machine with a display just with tysend FILE. you can send multiple in a sequence with tysend FILE1 FILE2 FILE3 ... ... and terminology will ask for a location and filename per file you send (just hit cancel if you don't want to do it). note - it needs new theme features to work. it'll fail without them. @feature --- README | 19 +++ data/themes/default.edc | 165 +++++++++++++++++++++++++ src/bin/meson.build | 6 + src/bin/termio.c | 196 ++++++++++++++++++++++++++++++ src/bin/termio.h | 3 + src/bin/tyalpha.c | 2 +- src/bin/tybg.c | 4 +- src/bin/tycat.c | 6 +- src/bin/tyls.c | 2 +- src/bin/typop.c | 2 +- src/bin/tyq.c | 2 +- src/bin/tysend.c | 149 +++++++++++++++++++++++ src/bin/win.c | 314 +++++++++++++++++++++++++++++++++++++++++++++++- 13 files changed, 860 insertions(+), 10 deletions(-) diff --git a/README b/README index 510f384..5e53487 100644 --- a/README +++ b/README @@ -299,3 +299,22 @@ ib ie = end media replace sequence run + +fr[PATH/FILE] + = begin file send for a file named PATH/FILE + +fs[SIZE_BYTES] + = set the size in bytes of a file send started with the above fr escape + +fd[CHECKSUM DATA] + = block of data for the current file transfer with checksum as a + string decimal which is the sum of every byte when taken as an + unsigned char per byte. the checksum is a signed 32bit integer. + the checksum is the sum of the data after escaping. data will be + escaped using a 0xff byte as the escape header. the escape sequence + of 0xff 0x01 represents a 0x00 (nul) bytes, and 0xff 0x02 represents + a 0xff byte. all other bytes are transitted as-is. + +fx + = exit file send mode (normally at the end of the file or when it's + complete) diff --git a/data/themes/default.edc b/data/themes/default.edc index c794f28..ba4e90d 100644 --- a/data/themes/default.edc +++ b/data/themes/default.edc @@ -652,6 +652,171 @@ collections { } //////////////////////////////////////////////////////////////////// + // sendfile request + part { name: "sendfile_request_clip"; type: RECT; + description { state: "default" 0.0; + color: 255 255 255 0; + visible: 0; + } + description { state: "on" 0.0; + inherit: "default" 0.0; + visible: 1; + color: 255 255 255 255; + } + } + part { name: "sendfile_request_shadow"; + mouse_events: 0; + clip_to: "sendfile_request_clip"; + description { state: "default" 0.0; + fixed: 1 1; + rel.to: "sendfile_request_bg"; + rel1.offset: -32 -32; + rel2.offset: 31 31; + image.normal: "pm_shadow.png"; + image.border: 64 64 64 64; + fill.smooth: 0; + } + } + part { name: "sendfile_request_bg"; type: RECT; + clip_to: "sendfile_request_clip"; + description { state: "default" 0.0; + color: 64 64 64 255; + rel1.relative: 0.0 -1.0; + rel2.relative: 1.0 0.0; + } + description { state: "on" 0.0; + inherit: "default" 0.0; + rel1.relative: 0.0 0.0; + rel2.relative: 1.0 1.0; + } + } + part { name: "terminology.sendfile.request"; type: SWALLOW; + clip_to: "sendfile_request_clip"; + scale: 1; + description { state: "default" 0.0; + rel.to: "sendfile_request_bg"; + rel1.offset: 4 4; + rel2.offset: -5 -5; + offscale; + } + description { state: "on" 0.0; + inherit: "default" 0.0; + rel1.relative: 0.0 0.0; + rel2.relative: 1.0 1.0; + } + } + program { + signal: "sendfile,request,on"; source: "terminology"; + action: ACTION_STOP; + target: "sendfile_request_on"; + target: "sendfile_request_off"; + } + program { + signal: "sendfile,request,off"; source: "terminology"; + action: ACTION_STOP; + target: "sendfile_request_on"; + target: "sendfile_request_off"; + } + program { name: "sendfile_request_on"; + signal: "sendfile,request,on"; source: "terminology"; + in: 0.5 0.0; + action: STATE_SET "on" 0.0; + transition: DECELERATE 0.5; + target: "sendfile_request_clip"; + target: "sendfile_request_bg"; + } + program { name: "sendfile_request_off"; + signal: "sendfile,request,off"; source: "terminology"; + action: STATE_SET "default" 0.0; + transition: DECELERATE 0.5; + target: "sendfile_request_clip"; + target: "sendfile_request_bg"; + } + + //////////////////////////////////////////////////////////////////// + // sendfile progress + part { name: "sendfile_progress_clip"; type: RECT; + description { state: "default" 0.0; + color: 255 255 255 0; + visible: 0; + } + description { state: "on" 0.0; + inherit: "default" 0.0; + visible: 1; + color: 255 255 255 255; + } + } + part { name: "sendfile_progress_shadow"; + mouse_events: 0; + clip_to: "sendfile_progress_clip"; + description { state: "default" 0.0; + fixed: 1 1; + rel.to: "sendfile_progress_bg"; + rel1.offset: -32 -32; + rel2.offset: 31 31; + image.normal: "pm_shadow.png"; + image.border: 64 64 64 64; + fill.smooth: 0; + } + } + part { name: "sendfile_progress_bg"; type: RECT; + clip_to: "sendfile_progress_clip"; + scale : 1; + description { state: "default" 0.0; + color: 64 64 64 255; + rel.to: "terminology.sendfile.progress"; + rel1.offset: -4 -4; + rel2.offset: 4 4; + offscale; + } + } + part { name: "terminology.sendfile.progress"; type: SWALLOW; + clip_to: "sendfile_progress_clip"; + scale : 1; + description { state: "default" 0.0; + rel1.relative: 0.0 0.0; + rel1.offset: 4 -5; + rel2.relative: 1.0 0.0; + rel2.offset: -5 -5; + align: 0.5 1.0; + offscale; + } + description { state: "on" 0.0; + inherit: "default" 0.0; + rel1.offset: 4 4; + rel2.offset: -5 4; + align: 0.5 0.0; + } + } + program { + signal: "sendfile,progress,on"; source: "terminology"; + action: ACTION_STOP; + target: "sendfile_progress_on"; + target: "sendfile_progress_off"; + } + program { + signal: "sendfile,progress,off"; source: "terminology"; + action: ACTION_STOP; + target: "sendfile_progress_on"; + target: "sendfile_progress_off"; + } + program { name: "sendfile_progress_on"; + signal: "sendfile,progress,on"; source: "terminology"; + in: 0.5 0.0; + action: STATE_SET "on" 0.0; + transition: DECELERATE 0.5; + target: "sendfile_progress_clip"; + target: "terminology.sendfile.progress"; + } + program { name: "sendfile_progress_off"; + signal: "sendfile,progress,off"; source: "terminology"; + action: STATE_SET "default" 0.0; + transition: DECELERATE 0.5; + target: "sendfile_progress_clip"; + target: "terminology.sendfile.progress"; + } + + //////////////////////////////////////////////////////////////////// // miniview part { name: "terminology.miniview"; type: SWALLOW; description { state: "default" 0.0; diff --git a/src/bin/meson.build b/src/bin/meson.build index 224470f..97b33bf 100644 --- a/src/bin/meson.build +++ b/src/bin/meson.build @@ -47,6 +47,7 @@ typop_sources = ['tycommon.c', 'tycommon.h', 'typop.c'] tyq_sources = ['tycommon.c', 'tycommon.h', 'tyq.c'] tycat_sources = ['tycommon.c', 'tycommon.h', 'tycat.c', 'extns.c', 'extns.h'] tyls_sources = ['extns.c', 'extns.h', 'tyls.c', 'tycommon.c', 'tycommon.h'] +tysend_sources = ['tycommon.c', 'tycommon.h', 'tysend.c'] tyfuzz_sources = ['termptyesc.c', 'termptyesc.h', 'termptysave.c', 'termptysave.h', 'termptyops.c', 'termptyops.h', @@ -94,6 +95,11 @@ executable('tyls', install: true, include_directories: config_dir, dependencies: terminology_dependencies) +executable('tysend', + tysend_sources, + install: true, + include_directories: config_dir, + dependencies: terminology_dependencies) if fuzzing executable('tyfuzz', diff --git a/src/bin/termio.c b/src/bin/termio.c index ca488b0..b5f60a8 100644 --- a/src/bin/termio.c +++ b/src/bin/termio.c @@ -62,6 +62,13 @@ struct _Termio unsigned char dndobjdel : 1; } down; } link; + struct { + const char *file; + FILE *f; + double progress; + unsigned long long total, size; + Eina_Bool active : 1; + } sendfile; Evas_Object *ctxpopup; int zoom_fontsize_start; int scroll; @@ -4729,6 +4736,70 @@ _smart_cb_gest_zoom_abort(void *data, void *_event EINA_UNUSED) } /* }}} */ + +Eina_Bool +termio_file_send_ok(const Evas_Object *obj, const char *file) +{ + Termio *sd = evas_object_smart_data_get(obj); + Termpty *ty; + + if (!sd) return EINA_FALSE; + if (!file) return EINA_FALSE; + ty = sd->pty; + sd->sendfile.f = fopen(file, "w"); + if (sd->sendfile.f) + { + if (sd->sendfile.file) eina_stringshare_del(sd->sendfile.file); + sd->sendfile.file = eina_stringshare_add(file); + sd->sendfile.active = EINA_TRUE; + termpty_write(ty, "k\n", 2); + return EINA_TRUE; + } + if (sd->sendfile.file) eina_stringshare_del(sd->sendfile.file); + sd->sendfile.file = NULL; + sd->sendfile.active = EINA_FALSE; + termpty_write(ty, "n\n", 2); + return EINA_FALSE; +} + +void +termio_file_send_cancel(const Evas_Object *obj) +{ + Termio *sd = evas_object_smart_data_get(obj); + Termpty *ty; + + if (!sd) return; + ty = sd->pty; + if (!sd->sendfile.active) goto done; + sd->sendfile.progress = 0.0; + sd->sendfile.total = 0; + sd->sendfile.size = 0; + if (sd->sendfile.file) + { + ecore_file_unlink(sd->sendfile.file); + eina_stringshare_del(sd->sendfile.file); + sd->sendfile.file = NULL; + } + if (sd->sendfile.f) + { + fclose(sd->sendfile.f); + sd->sendfile.f = NULL; + } + sd->sendfile.active = EINA_FALSE; +done: + termpty_write(ty, "n\n", 2); +} + +double +termio_file_send_progress_get(const Evas_Object *obj) +{ + Termio *sd = evas_object_smart_data_get(obj); + + if (!sd) return 0.0; + if (!sd->sendfile.active) return 0.0; + return sd->sendfile.progress; +} + /* {{{ Smart */ static void @@ -5431,6 +5502,21 @@ _smart_del(Evas_Object *obj) evas_object_del(o); } if (sd->link.down.dndobj) evas_object_del(sd->link.down.dndobj); + if (sd->sendfile.active) + { + if (sd->sendfile.file) + { + ecore_file_unlink(sd->sendfile.file); + eina_stringshare_del(sd->sendfile.file); + sd->sendfile.file = NULL; + } + if (sd->sendfile.f) + { + fclose(sd->sendfile.f); + sd->sendfile.f = NULL; + } + sd->sendfile.active = EINA_FALSE; + } keyin_compose_seq_reset(&sd->khdl); if (sd->sel_str) eina_stringshare_del(sd->sel_str); if (sd->preedit_str) eina_stringshare_del(sd->preedit_str); @@ -5927,6 +6013,116 @@ _smart_pty_command(void *data) return; } } + else if (ty->cur_cmd[0] == 'f') // file... + { + if (ty->cur_cmd[1] == 'r') // receive + { + sd->sendfile.progress = 0.0; + sd->sendfile.total = 0; + sd->sendfile.size = 0; + } + else if (ty->cur_cmd[1] == 's') // file size + { + sd->sendfile.total = 0; + sd->sendfile.size = atoll(&(ty->cur_cmd[2])); + } + else if (ty->cur_cmd[1] == 'd') // data packet + { + int pksum = atoi(&(ty->cur_cmd[2])); + int sum; + char *p = strchr(ty->cur_cmd, ' '); + Eina_Bool valid = EINA_TRUE; + + if (p) + { + Eina_Binbuf *bb = eina_binbuf_new(); + unsigned char v; + int inp = 0; + + if (bb) + { + p++; + sum = 0; + for (; *p; p++) + { + v = (unsigned char)(*p); + sum += v; + inp++; + if ((v == 0x1b) || (v == 0x07)) + { + p++; + v = *p; + inp++; + sum += (unsigned char)(*p); + if (*p == 0x01) v = 0x00; + else if (*p == 0x02) v = 0xff; + else valid = EINA_FALSE; + } + eina_binbuf_append_char(bb, v); + } + if ((valid) && (sum == pksum) && (sd->sendfile.active)) + { + // write "ok" (k) to term + size_t size = eina_binbuf_length_get(bb); + + sd->sendfile.total += size; + if (sd->sendfile.size > 0.0) + { + sd->sendfile.progress = + (double)sd->sendfile.total / + (double)sd->sendfile.size; + evas_object_smart_callback_call + (obj, "send,progress", NULL); + } + fwrite(eina_binbuf_string_get(bb), size, 1, + sd->sendfile.f); + termpty_write(ty, "k\n", 2); + } + else + { + // write "not valid" (n) to term + if (sd->sendfile.file) + { + ecore_file_unlink(sd->sendfile.file); + eina_stringshare_del(sd->sendfile.file); + sd->sendfile.file = NULL; + } + if (sd->sendfile.f) + { + fclose(sd->sendfile.f); + sd->sendfile.f = NULL; + } + sd->sendfile.active = EINA_FALSE; + termpty_write(ty, "n\n", 2); + evas_object_smart_callback_call + (obj, "send,end", NULL); + } + eina_binbuf_free(bb); + } + } + } + else if (ty->cur_cmd[1] == 'x') // exit data stream + { + if (sd->sendfile.active) + { + sd->sendfile.progress = 0.0; + sd->sendfile.size = 0; + if (sd->sendfile.file) + { + eina_stringshare_del(sd->sendfile.file); + sd->sendfile.file = NULL; + } + if (sd->sendfile.f) + { + fclose(sd->sendfile.f); + sd->sendfile.f = NULL; + } + sd->sendfile.active = EINA_FALSE; + evas_object_smart_callback_call + (obj, "send,end", NULL); + } + } + } evas_object_smart_callback_call(obj, "command", (void *)ty->cur_cmd); } diff --git a/src/bin/termio.h b/src/bin/termio.h index 32eb459..f930393 100644 --- a/src/bin/termio.h +++ b/src/bin/termio.h @@ -45,6 +45,9 @@ void termio_media_mute_set(Evas_Object *obj, Eina_Bool mute); void termio_media_visualize_set(Evas_Object *obj, Eina_Bool visualize); void termio_config_set(Evas_Object *obj, Config *config); Config *termio_config_get(const Evas_Object *obj); +Eina_Bool termio_file_send_ok(const Evas_Object *obj, const char *file); +void termio_file_send_cancel(const Evas_Object *obj); +double termio_file_send_progress_get(const Evas_Object *obj); Termpty *termio_pty_get(const Evas_Object *obj); Evas_Object * termio_miniview_get(const Evas_Object *obj); diff --git a/src/bin/tyalpha.c b/src/bin/tyalpha.c index 8b0223b..e3c4c83 100644 --- a/src/bin/tyalpha.c +++ b/src/bin/tyalpha.c @@ -46,7 +46,7 @@ main(int argc, char **argv) snprintf(tbuf, sizeof(tbuf), "%c}ap%s", 0x1b, argv[i]); else snprintf(tbuf, sizeof(tbuf), "%c}at%s", 0x1b, argv[i]); - if (write(0, tbuf, strlen(tbuf) + 1) != (signed)(strlen(tbuf) + 1)) perror("write"); + if (write(1, tbuf, strlen(tbuf) + 1) != (signed)(strlen(tbuf) + 1)) perror("write"); } return 0; } diff --git a/src/bin/tybg.c b/src/bin/tybg.c index 595d090..d2b7aaa 100644 --- a/src/bin/tybg.c +++ b/src/bin/tybg.c @@ -31,7 +31,7 @@ main(int argc, char **argv) { char tbuf[32]; snprintf(tbuf, sizeof(tbuf), "%c}bt", 0x1b); - if (write(0, tbuf, strlen(tbuf) + 1) != (signed)(strlen(tbuf) + 1)) perror("write"); + if (write(1, tbuf, strlen(tbuf) + 1) != (signed)(strlen(tbuf) + 1)) perror("write"); return 0; } for (i = 1; i < argc; i++) @@ -50,7 +50,7 @@ main(int argc, char **argv) snprintf(tbuf, sizeof(tbuf), "%c}bp%s", 0x1b, path); else snprintf(tbuf, sizeof(tbuf), "%c}bt%s", 0x1b, path); - if (write(0, tbuf, strlen(tbuf) + 1) != (signed)(strlen(tbuf) + 1)) perror("write"); + if (write(1, tbuf, strlen(tbuf) + 1) != (signed)(strlen(tbuf) + 1)) perror("write"); } return 0; } diff --git a/src/bin/tycat.c b/src/bin/tycat.c index 690650b..988c141 100644 --- a/src/bin/tycat.c +++ b/src/bin/tycat.c @@ -97,7 +97,7 @@ prnt(const char *path, int w, int h, int mode) snprintf(buf, sizeof(buf), "%c}if#%i;%i;%s", 0x1b, w, h, path); else snprintf(buf, sizeof(buf), "%c}is#%i;%i;%s", 0x1b, w, h, path); - if (write(0, buf, strlen(buf) + 1) < 0) perror("write"); + if (write(1, buf, strlen(buf) + 1) < 0) perror("write"); i = 0; line[i++] = 0x1b; line[i++] = '}'; @@ -113,7 +113,7 @@ prnt(const char *path, int w, int h, int mode) line[i++] = '\n'; for (y = 0; y < h; y++) { - if (write(0, line, i) < 0) perror("write"); + if (write(1, line, i) < 0) perror("write"); } free(line); } @@ -336,7 +336,7 @@ main(int argc, char **argv) evas = ecore_evas_get(ee); echo_off(); snprintf(buf, sizeof(buf), "%c}qs", 0x1b); - if (write(0, buf, strlen(buf) + 1) < 0) perror("write"); + if (write(1, buf, strlen(buf) + 1) < 0) perror("write"); if (scanf("%i;%i;%i;%i", &tw, &th, &cw, &ch) != 4 || ((tw <= 0) || (th <= 0) || (cw <= 1) || (ch <= 1))) { diff --git a/src/bin/tyls.c b/src/bin/tyls.c index 0ec6809..6f15813 100644 --- a/src/bin/tyls.c +++ b/src/bin/tyls.c @@ -765,7 +765,7 @@ main(int argc, char **argv) echo_off(); snprintf(buf, sizeof(buf), "%c}qs", 0x1b); len = strlen(buf); - if (write(0, buf, len + 1) < (signed)len + 1) perror("write"); + if (write(1, buf, len + 1) < (signed)len + 1) perror("write"); if ((scanf("%i;%i;%i;%i", &tw, &th, &cw, &ch) != 4) || (tw <= 0) || (th <= 0) || (cw <= 1) || (ch <= 1)) { diff --git a/src/bin/typop.c b/src/bin/typop.c index 0466d1d..f314c91 100644 --- a/src/bin/typop.c +++ b/src/bin/typop.c @@ -39,7 +39,7 @@ main(int argc, char **argv) path = argv[i]; if (realpath(path, buf)) path = buf; snprintf(tbuf, sizeof(tbuf), "%c}pn%s", 0x1b, path); - if (write(0, tbuf, strlen(tbuf) + 1) != (signed)(strlen(tbuf) + 1)) perror("write"); + if (write(1, tbuf, strlen(tbuf) + 1) != (signed)(strlen(tbuf) + 1)) perror("write"); } return 0; } diff --git a/src/bin/tyq.c b/src/bin/tyq.c index 95ca8a7..aeae097 100644 --- a/src/bin/tyq.c +++ b/src/bin/tyq.c @@ -39,7 +39,7 @@ main(int argc, char **argv) path = argv[i]; if (realpath(path, buf)) path = buf; snprintf(tbuf, sizeof(tbuf), "%c}pq%s", 0x1b, path); - if (write(0, tbuf, strlen(tbuf) + 1) != (signed)(strlen(tbuf) + 1)) perror("write"); + if (write(1, tbuf, strlen(tbuf) + 1) != (signed)(strlen(tbuf) + 1)) perror("write"); } return 0; } diff --git a/src/bin/tysend.c b/src/bin/tysend.c new file mode 100644 index 0000000..1bb2d78 --- /dev/null +++ b/src/bin/tysend.c @@ -0,0 +1,149 @@ +#include "private.h" +#include <stdio.h> +#include <limits.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <termios.h> + +#include <Eina.h> +#include "tycommon.h" + +static void +print_usage(const char *argv0) +{ + printf("Usage: %s"HELP_ARGUMENT_SHORT" FILE1 [FILE2 ...]\n" + " Send file(s) to the terminal to save\n" + HELP_ARGUMENT_DOC"\n" + "\n", + argv0); +} + +static struct termios told, tnew; + +static int +echo_off(void) +{ + if (tcgetattr(0, &told) != 0) return -1; + tnew = told; + tnew.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); + tnew.c_oflag &= ~(OPOST); + tnew.c_lflag &= ~(ISIG | ICANON | ECHO | IEXTEN); + tnew.c_cflag &= ~(CSIZE | PARENB); + tnew.c_cflag |= CS8; + tnew.c_cc[VMIN] = 1; + tnew.c_cc[VTIME] = 0; + if (tcsetattr(0, TCSAFLUSH, &tnew) != 0) return -1; + return 0; +} + +static int +echo_on(void) +{ + return tcsetattr(0, TCSAFLUSH, &told); +} + +int +main(int argc, char **argv) +{ + int i; + + ON_NOT_RUNNING_IN_TERMINOLOGY_EXIT_1(); + ARGUMENT_ENTRY_CHECK(argc, argv, print_usage); + + if (argc <= 1) + { + print_usage(argv[0]); + return 0; + } + + echo_off(); + for (i = 1; i < argc; i++) + { + char *path, buf[8192], tbuf[PATH_MAX * 3]; + unsigned char rawbuf[8192 + 128], rawbuf2[8192 + 128]; + int file_fd, pksize, pksum, bin, bout; + + path = argv[i]; + snprintf(tbuf, sizeof(tbuf), "%c}fr%s", 0x1b, path); + if (write(1, tbuf, strlen(tbuf) + 1) != (signed)(strlen(tbuf) + 1)) + goto err; + file_fd = open(path, O_RDONLY); + if (file_fd >= 0) + { + off_t off; + + off = lseek(file_fd, 0, SEEK_END); + lseek(file_fd, 0, SEEK_SET); + snprintf(tbuf, sizeof(tbuf), "%c}fs%llu", 0x1b, (unsigned long long)off); + if (write(1, tbuf, strlen(tbuf) + 1) != (signed)(strlen(tbuf) + 1)) + goto err; + for (;;) + { + if (read(0, buf, 2) == 2) + { + if (buf[0] == 'k') + { + pksize = read(file_fd, rawbuf, 8192); + + if (pksize > 0) + { + bout = 0; + for (bin = 0; bin < pksize; bin++) + { + if (rawbuf[bin] == 0x00) + { + rawbuf2[bout++] = 0xff; + rawbuf2[bout++] = 0x01; + } + else if (rawbuf[bin] == 0xff) + { + rawbuf2[bout++] = 0xff; + rawbuf2[bout++] = 0x02; + } + else + { + rawbuf2[bout++] = rawbuf[bin]; + } + } + rawbuf2[bout] = 0; + pksum = 0; + for (bin = 0; bin < bout; bin++) + { + pksum += rawbuf2[bin]; + } + snprintf(tbuf, sizeof(tbuf), "%c}fd%i ", 0x1b, pksum); + if (write(1, tbuf, strlen(tbuf)) != (signed)(strlen(tbuf))) + goto err; + if (write(1, rawbuf2, bout + 1) != bout + 1) + goto err; + } + else break; + } + else + { + echo_on(); + fprintf(stderr, "Send Fail\n"); + goto err; + } + } + else goto err; + } + close(file_fd); + } + snprintf(tbuf, sizeof(tbuf), "%c}fx", 0x1b); + if (write(1, tbuf, strlen(tbuf) + 1) != (signed)(strlen(tbuf) + 1)) + goto err; + tbuf[0] = 0; + if (write(1, tbuf, 1) != 1) + goto err; + } + echo_on(); + return 0; +err: + echo_on(); + return -1; +} diff --git a/src/bin/win.c b/src/bin/win.c index 610f8b7..65a41b2 100644 --- a/src/bin/win.c +++ b/src/bin/win.c @@ -88,11 +88,17 @@ struct _Term Evas_Object *popmedia; Evas_Object *miniview; Evas_Object *sel; + Evas_Object *sendfile_request; + Evas_Object *sendfile_progress; + Evas_Object *sendfile_progress_bar; Evas_Object *tabcount_spacer; Evas_Object *tab_spacer; Evas_Object *tab_region_base; Evas_Object *tab_region_bg; Eina_List *popmedia_queue; + Ecore_Timer *sendfile_request_hide_timer; + Ecore_Timer *sendfile_progress_hide_timer; + const char *sendfile_dir; Media_Type poptype, mediatype; Tabbar tabbar; int step_x, step_y, min_w, min_h, req_w, req_h; @@ -105,6 +111,9 @@ struct _Term unsigned char missed_bell : 1; unsigned char miniview_shown : 1; unsigned char popmedia_deleted : 1; + + Eina_Bool sendfile_request_enabled : 1; + Eina_Bool sendfile_progress_enabled : 1; }; typedef struct _Solo Solo; @@ -3734,6 +3743,247 @@ _set_alpha(Config *config, const char *val, Eina_Bool save) } static void +_sendfile_progress_del(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj, void *info EINA_UNUSED) +{ + Evas_Object *o = obj; + Term *term = evas_object_data_get(o, "sendfile-progress-term"); + Ecore_Timer *t; + + evas_object_data_del(o, "sendfile-progress-term"); + if (term) + { + term->sendfile_progress = NULL; + term->sendfile_progress_bar = NULL; + } + t = evas_object_data_get(o, "sendfile-progress-timer"); + evas_object_data_del(o, "sendfile-progress-term"); + if (t) ecore_timer_del(t); +} + +static Eina_Bool +_sendfile_progress_reset(void *data) +{ + Evas_Object *o = data; + Term *term = evas_object_data_get(o, "sendfile-progress-term"); + + if (term) + { + term->sendfile_progress = NULL; + term->sendfile_progress_bar = NULL; + } + evas_object_data_del(o, "sendfile-progress-timer"); + evas_object_data_del(o, "sendfile-progress-term"); + evas_object_del(o); + return EINA_FALSE; +} + +static Eina_Bool +_sendfile_progress_hide_delay(void *data) +{ + Term *term = data; + Ecore_Timer *t; + + term->sendfile_progress_hide_timer = NULL; + if (!term->sendfile_progress_enabled) return EINA_FALSE; + term->sendfile_progress_enabled = EINA_FALSE; + edje_object_signal_emit(term->bg, "sendfile,progress,off", "terminology"); + t = evas_object_data_get(term->sendfile_progress, "sendfile-progress-timer"); + if (t) ecore_timer_del(t); + t = ecore_timer_add(10.0, _sendfile_progress_reset, term->sendfile_progress); + evas_object_data_set(term->sendfile_progress, "sendfile-progress-timer", t); + return EINA_FALSE; +} + +static void +_sendfile_progress_hide(Term *term) +{ + if (!term->sendfile_progress_enabled) return; + if (term->sendfile_progress_hide_timer) + ecore_timer_del(term->sendfile_progress_hide_timer); + term->sendfile_progress_hide_timer = + ecore_timer_add(0.5, _sendfile_progress_hide_delay, term); +} + +static void +_sendfile_progress_cancel(void *data, Evas_Object *obj EINA_UNUSED, void *info EINA_UNUSED) +{ + Term *term = data; + + if (!term->sendfile_progress) return; + termio_file_send_cancel(term->termio); + _sendfile_progress_hide(term); +} + +static void +_sendfile_progress(Term *term) +{ + Evas_Object *o, *base; + + if (term->sendfile_progress) + { + evas_object_del(term->sendfile_progress); + term->sendfile_progress = NULL; + } + if (!edje_object_part_exists(term->bg, "terminology.sendfile.progress")) + { + return; + } + if (term->sendfile_progress_hide_timer) + { + ecore_timer_del(term->sendfile_progress_hide_timer); + term->sendfile_progress_hide_timer = NULL; + } + o = elm_box_add(term->wn->win); + evas_object_data_set(o, "sendfile-progress-term", term); + base = o; + term->sendfile_progress = o; + evas_object_event_callback_add(o, EVAS_CALLBACK_DEL, _sendfile_progress_del, NULL); + elm_box_horizontal_set(o, EINA_TRUE); + + o = elm_button_add(term->wn->win); + elm_object_text_set(o, "Cancel"); + evas_object_smart_callback_add(o, "clicked", _sendfile_progress_cancel, term); + evas_object_size_hint_align_set(o, EVAS_HINT_FILL, EVAS_HINT_FILL); + elm_box_pack_end(base, o); + evas_object_show(o); + + o = elm_progressbar_add(term->wn->win); + term->sendfile_progress_bar = o; + elm_progressbar_unit_format_set(o, "%1.0f%%"); + evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(o, EVAS_HINT_FILL, EVAS_HINT_FILL); + elm_box_pack_end(base, o); + evas_object_show(o); + + term->sendfile_progress_enabled = EINA_TRUE; + edje_object_part_swallow(term->bg, "terminology.sendfile.progress", base); + evas_object_show(base); + edje_object_signal_emit(term->bg, "sendfile,progress,on", "terminology"); +} + +static void +_sendfile_request_del(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj, void *info EINA_UNUSED) +{ + Evas_Object *o = obj; + Term *term = evas_object_data_get(o, "sendfile-request-term"); + Ecore_Timer *t; + + evas_object_data_del(o, "sendfile-request-term"); + if (term) term->sendfile_request = NULL; + t = evas_object_data_get(o, "sendfile-request-timer"); + evas_object_data_del(o, "sendfile-request-term"); + if (t) ecore_timer_del(t); +} + +static Eina_Bool +_sendfile_request_reset(void *data) +{ + Evas_Object *o = data; + Term *term = evas_object_data_get(o, "sendfile-request-term"); + + if (term) term->sendfile_request = NULL; + evas_object_data_del(o, "sendfile-request-timer"); + evas_object_data_del(o, "sendfile-request-term"); + evas_object_del(o); + return EINA_FALSE; +} + +static Eina_Bool +_sendfile_request_hide_delay(void *data) +{ + Term *term = data; + Ecore_Timer *t; + + term->sendfile_request_hide_timer = NULL; + if (!term->sendfile_request_enabled) return EINA_FALSE; + term->sendfile_request_enabled = EINA_FALSE; + edje_object_signal_emit(term->bg, "sendfile,request,off", "terminology"); + t = evas_object_data_get(term->sendfile_request, "sendfile-request-timer"); + if (t) ecore_timer_del(t); + t = ecore_timer_add(10.0, _sendfile_request_reset, term->sendfile_request); + evas_object_data_set(term->sendfile_request, "sendfile-request-timer", t); + elm_object_focus_set(term->sendfile_request, EINA_FALSE); + _term_focus(term); + return EINA_FALSE; +} + +static void +_sendfile_request_hide(Term *term) +{ + if (!term->sendfile_request_enabled) return; + if (term->sendfile_request_hide_timer) + ecore_timer_del(term->sendfile_request_hide_timer); + term->sendfile_request_hide_timer = + ecore_timer_add(0.2, _sendfile_request_hide_delay, term); +} + +static void +_sendfile_request_done(void *data, Evas_Object *obj EINA_UNUSED, void *info) +{ + Term *term = data; + const char *path, *selpath = info; + + if (!term->sendfile_request) return; + + path = elm_fileselector_path_get(term->sendfile_request); + eina_stringshare_replace(&term->sendfile_dir, path); + + if (selpath) + { + _sendfile_progress(term); + termio_file_send_ok(term->termio, selpath); + } + else termio_file_send_cancel(term->termio); + _sendfile_request_hide(term); +} + +static void +_sendfile_request(Term *term, const char *path) +{ + Evas_Object *o; + const char *p; + + if (term->sendfile_request) + { + evas_object_del(term->sendfile_request); + term->sendfile_request = NULL; + } + if (!edje_object_part_exists(term->bg, "terminology.sendfile.request")) + { + termio_file_send_cancel(term->termio); + return; + } + if (term->sendfile_request_hide_timer) + { + ecore_timer_del(term->sendfile_request_hide_timer); + term->sendfile_request_hide_timer = NULL; + } + o = elm_fileselector_add(term->wn->win); + evas_object_data_set(o, "sendfile-request-term", term); + term->sendfile_request = o; + evas_object_event_callback_add(o, EVAS_CALLBACK_DEL, _sendfile_request_del, NULL); + elm_fileselector_is_save_set(o, EINA_TRUE); + elm_fileselector_expandable_set(o, EINA_FALSE); + if (!term->sendfile_dir) + { + const char *dir = eina_environment_home_get(); + + if (dir) term->sendfile_dir = eina_stringshare_add(dir); + } + if (term->sendfile_dir) elm_fileselector_path_set(o, term->sendfile_dir); + p = strrchr(path, '/'); + if (p) elm_fileselector_current_name_set(o, p + 1); + else elm_fileselector_current_name_set(o, path); + evas_object_smart_callback_add(o, "done", _sendfile_request_done, term); + term->sendfile_request_enabled = EINA_TRUE; + edje_object_part_swallow(term->bg, "terminology.sendfile.request", o); + evas_object_show(o); + edje_object_signal_emit(term->bg, "sendfile,request,on", "terminology"); + elm_object_focus_set(term->termio, EINA_FALSE); + elm_object_focus_set(o, EINA_TRUE); +} + +static void _cb_command(void *data, Evas_Object *_obj EINA_UNUSED, void *event) @@ -3749,7 +3999,7 @@ _cb_command(void *data, } else if (cmd[1] == 'q') // queue it to display after current one { - _popmedia_queue_add(term, cmd + 2); + _popmedia_queue_add(term, cmd + 2); } } else if (cmd[0] == 'b') // set background @@ -3793,6 +4043,19 @@ _cb_command(void *data, else if (cmd[1] == 'p') // permanent _set_alpha(termio_config_get(term->termio), cmd + 2, EINA_TRUE); } + else if (cmd[0] == 'f') // file... + { + if (cmd[1] == 'r') // receive + { + _sendfile_request(term, cmd + 2); + } + else if (cmd[1] == 'd') // data packet + { + } + else if (cmd[1] == 'x') // exit data stream + { + } + } } static void @@ -3872,6 +4135,28 @@ _cb_icon(void *data, elm_win_icon_name_set(term->wn->win, termio_icon_name_get(term->termio)); } +static void +_cb_send_progress(void *data, + Evas_Object *_obj EINA_UNUSED, + void *_event EINA_UNUSED) +{ + Term *term = data; + + elm_progressbar_value_set(term->sendfile_progress_bar, + termio_file_send_progress_get(term->termio)); +} + +static void +_cb_send_end(void *data, + Evas_Object *_obj EINA_UNUSED, + void *_event EINA_UNUSED) +{ + Term *term = data; + if (!term->sendfile_progress) return; + _sendfile_request_hide(term); + _sendfile_progress_hide(term); +} + static Eina_Bool _cb_cmd_focus(void *data) { @@ -4227,6 +4512,31 @@ _term_free(Term *term) { const char *s; + if (term->sendfile_request) + { + evas_object_del(term->sendfile_request); + term->sendfile_request = NULL; + } + if (term->sendfile_progress) + { + evas_object_del(term->sendfile_progress); + term->sendfile_progress = NULL; + } + if (term->sendfile_request_hide_timer) + { + ecore_timer_del(term->sendfile_request_hide_timer); + term->sendfile_request_hide_timer = NULL; + } + if (term->sendfile_progress_hide_timer) + { + ecore_timer_del(term->sendfile_progress_hide_timer); + term->sendfile_progress_hide_timer = NULL; + } + if (term->sendfile_dir) + { + eina_stringshare_del(term->sendfile_dir); + term->sendfile_dir = NULL; + } EINA_LIST_FREE(term->popmedia_queue, s) { eina_stringshare_del(s); @@ -4616,6 +4926,8 @@ term_new(Win *wn, Config *config, const char *cmd, evas_object_smart_callback_add(o, "split,v", _cb_split_v, term); evas_object_smart_callback_add(o, "title,change", _cb_title, term); evas_object_smart_callback_add(o, "icon,change", _cb_icon, term); + evas_object_smart_callback_add(o, "send,progress", _cb_send_progress, term); + evas_object_smart_callback_add(o, "send,end", _cb_send_end, term); evas_object_show(o); evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_DOWN, --
