summaryrefslogtreecommitdiffstats
path: root/call/call.c
diff options
context:
space:
mode:
Diffstat (limited to 'call/call.c')
-rw-r--r--call/call.c1010
1 files changed, 745 insertions, 265 deletions
diff --git a/call/call.c b/call/call.c
index 89d3264..f9fe6eb 100644
--- a/call/call.c
+++ b/call/call.c
@@ -36,7 +36,14 @@
#include <sys/wait.h>
#include <termios.h>
#include <unistd.h>
-#include <curses.h>
+#define __USE_XOPEN
+#include <wchar.h>
+#include <wctype.h>
+#define _XOPEN_SOURCE_EXTENDED 1
+#include <ncursesw/ncurses.h>
+#include <locale.h>
+#include <iconv.h>
+#include <sys/ioctl.h>
#include <netax25/ax25.h>
#include <netrom/netrom.h>
@@ -79,10 +86,13 @@ static char *port;
static char *mycall;
static int stdin_is_tty = 1;
+static iconv_t ibm850toutf8 = 0, wcharttoibm850 = 0, wcharttoutf8 = 0, utf8towchart = 0;
volatile int interrupted = FALSE;
+static int sigwinchsignal = FALSE;
int paclen;
int fd;
+int curson = 1;
int wait_for_remote_disconnect = FALSE;
static struct timespec inactivity_timeout;
@@ -104,7 +114,7 @@ typedef struct {
WINDOW *ptr;
int max_y;
int max_x;
- char string[MAX_BUFLEN];
+ wchar_t string[MAX_BUFLEN];
unsigned long bytes;
int curs_pos;
} t_win;
@@ -113,10 +123,233 @@ typedef struct {
#define SLAVEMODE 002 /* Menu mode */
#define RAWMODE 004 /* mode used by earlier versions */
+#define ORIGINALENCODING 0
+#define UTF8ENCODING 1
+
+#define SCROLLBACKSIZE 5000
+
+typedef struct {
+ char *str;int len;
+}scrollbackstruct;
+
+
+static scrollbackstruct scrollback[SCROLLBACKSIZE];
+static int topscroll=0, lastscroll = 0, scrolledup=0, eatchar = 0;
+static char inbuf[MAX_BUFLEN];static int inbuflen = 0, inbufwid = 0;
+static char incharbuf[6];static int incharbuflen = 0;
+void statline(int mode, char *s);
+
+void addscrollline(char *s, int len)
+{
+ scrollback[lastscroll].str = malloc(len);
+ memcpy(scrollback[lastscroll].str, s, len);
+ scrollback[lastscroll].len = len;
+ if (++lastscroll >= SCROLLBACKSIZE)lastscroll = 0;
+ if (lastscroll == topscroll){
+ free(scrollback[topscroll].str);
+ if (++topscroll >= SCROLLBACKSIZE)topscroll = 0;
+ }
+}
+
+// Notes: Japanese, Chinese and Korean characters mostly take up two
+// characters in width. These characters return 2 via
+// wcwidth to let the code know that they require two
+// spaces. Mono-space fonts/ncurses seems to work correctly with
+// East Asian characters.
+//
+// There are also some characters that return a wcwidth of 0. I'm
+// not sure about all of them, but some of the 0 width characters
+// add a mark above or below a character. In order for these marks
+// to appear correctly, the previous character and the overstrike
+// must be drawn together. using wmove and drawing the accent doesn't
+// work.
+//
+// There are some other characters that have functions, and these
+// are not supported using a print to the screen. South Asian
+// fonts are complicated. I don't believe south asian fonts work
+// correctly from the Linux command line (as of late 2009). They
+// print but don't combine. The result is distorted.
+//
+// Many characters, as of 12/09, are too wide for a single space
+// in the font, although they return a wcwidth of 1. I suspect
+// this is due to these characters not being part of the mono-spaced
+// font and are instead pulled from an alternate font. These
+// characters also glitch in xterm, vim and other ncurses
+// software. I suspect this is actually a font bug, and any character
+// that returns wcwidth=1 in a monospaced font should be
+// monospaced.
+//
+
+
+int widthchar(char *s, size_t bytes, int xpos)
+{
+ wchar_t c;int width;
+ char *outbuf=(char *) &c;
+ size_t outsize = sizeof(wchar_t);
+ // Note: Actually need to check if bad UTF8 characters show as ?
+ if (iconv(utf8towchart, &s, &bytes, &outbuf, &outsize)< 0)return 0;
+ if (c == 9){
+ return 8 - (xpos & 7);
+ }
+ width = wcwidth(c);
+ if (width < 0)return 0;
+ return width;
+}
+
+
+int completecharlen(char *s)
+{
+ unsigned ut = (unsigned char)s[0];int clen;
+ if (ut <= 0x80)clen = 1;
+ else if ((ut >= 192) && (ut < 192+32))clen = 2;
+ else if ((ut >= 224) && (ut < 224+16))clen = 3;
+ else if ((ut >= 240) && (ut < 240+8))clen = 4;
+ else if ((ut >= 248) && (ut < 248+4))clen = 5;
+ else if ((ut >= 252) && (ut < 252+2))clen = 6;
+ else clen = 1; // bad
+ return clen;
+}
+
+
+// Must check for COLS while redrawing from history. Or otherwise the text
+// wraps around and does strange things.
+int waddnstrcolcheck(WINDOW *win, char *s, int len, int twidth)
+{
+ int n;
+ for (twidth = 0,n=0;n<len;){
+ int cwidth = completecharlen(&s[n]), width;
+ if (n + cwidth > len)return twidth; // Error condition
+ width = widthchar(&s[n], cwidth, twidth);
+ if (twidth+width > COLS)return twidth; //
+ waddnstr(win, &s[n], cwidth);
+ n += cwidth;
+ twidth += width;
+ }
+ return twidth;
+}
+
+// Update a line on the screen from the backscroll buffer.
+void updateline(int screeny, int yfrom, t_win *win_in, int mode, t_win *win_out)
+{
+ wmove(win_in->ptr, screeny, 0);
+ if (yfrom == lastscroll){
+ int twidth = 0;
+ if (inbuflen > 0)
+ twidth = waddnstrcolcheck(win_in->ptr, inbuf, inbuflen, 0);
+ if (mode == SLAVEMODE){
+ char obuf[MAX_BUFLEN];
+ char *inbuf = (char *)win_out->string, *outbuf = obuf;
+ size_t insize = win_out->bytes * sizeof(wchar_t), outsize = MAX_BUFLEN;
+ iconv(wcharttoutf8, &inbuf, &insize, &outbuf, &outsize);
+ waddnstrcolcheck(win_in->ptr, obuf, MAX_BUFLEN - outsize, twidth);
+ win_out->curs_pos = win_out->bytes;
+ }
+ }
+ else {
+ waddnstrcolcheck(win_in->ptr, scrollback[yfrom].str, scrollback[yfrom].len, 0);
+ }
+}
+
+// Cursor in SLAVE mode while scrolling looks broken.
+// Cursor in TALK mode is always good, because it's on the bottom window
+void checkcursor(int mode)
+{
+ int newcursor;
+ if ((mode == SLAVEMODE) && scrolledup)newcursor = 0;
+ else newcursor = 1;
+ if (curson != newcursor){
+ curs_set(newcursor);
+ curson = newcursor;
+ }
+}
+
+/* For CJK, it's important to keep the cursor always on the input
+ * window. Otherwise the display is confused */
+static void restorecursor(int mode, t_win *win_out)
+{
+ checkcursor(mode);
+ if (mode != RAWMODE){
+ int x,y;
+ getyx(win_out->ptr, y, x);// Must restore input cursor location.
+ wmove(win_out->ptr,y, x);
+ wrefresh(win_out->ptr);
+ }
+}
+
+void redrawscreen(t_win *win_in, int mode, t_win *win_out)
+{
+ int y, storedlines;
+ if (lastscroll >= topscroll) storedlines = lastscroll - topscroll;
+ else storedlines = lastscroll + SCROLLBACKSIZE - topscroll;
+ // Note it's stored lines + 1 extra line for text input.
+ for (y=0;(y<=win_in->max_y) && (y <= storedlines);y++){
+ int linefrom;
+ if (storedlines <= win_in->max_y){// This is a little confusing.
+ linefrom = topscroll + y;// The screen scrolls top down at start
+ }
+ else linefrom = lastscroll -scrolledup - (win_in->max_y) + y;
+ while (linefrom < 0)linefrom += SCROLLBACKSIZE;
+ while (linefrom >= SCROLLBACKSIZE)linefrom -= SCROLLBACKSIZE;
+ updateline(y,linefrom , win_in, mode, win_out);
+ }
+ checkcursor(mode);
+}
+
+void scrolltext(t_win *win_in, int lines, int mode, t_win *win_out)
+{
+ int topline, storedlines;
+ int y;
+ int wasscrolledup;
+ if (scrolledup + lines < 0){
+ lines = -scrolledup;
+ }
+ // storedlines = Lines stored in buffer.
+ if (lastscroll >= topscroll) storedlines = lastscroll - topscroll;
+ else storedlines = lastscroll + SCROLLBACKSIZE - topscroll;
+ // The max scrolling we can do is the # of lines stored - the
+ // screen size.
+ topline = storedlines - win_in->max_y;
+ if (topline < 0)topline = 0;
+ if (scrolledup + lines > topline){
+ lines = topline - scrolledup;
+ }
+ if (!lines)return;
+ wasscrolledup = scrolledup;
+ scrolledup += lines;
+ wscrl(win_in->ptr, -lines);
+ scrollok(win_in->ptr, FALSE);
+ if (lines > 0){
+ for (y=0;y<lines;y++){
+ int linefrom = lastscroll -scrolledup - (win_in->max_y) + y;
+ while (linefrom < 0)linefrom += SCROLLBACKSIZE;
+ while (linefrom >= SCROLLBACKSIZE)linefrom -= SCROLLBACKSIZE;
+ updateline(y,linefrom , win_in, mode, win_out);
+ }
+ }
+ else {
+ for (y=-lines-1;y>=0;y--){
+ int linefrom = lastscroll -scrolledup - y;
+ while (linefrom < 0)linefrom += SCROLLBACKSIZE;
+ while (linefrom >= SCROLLBACKSIZE)linefrom -= SCROLLBACKSIZE;
+ updateline(win_in->max_y - y,linefrom , win_in, mode, win_out);
+ }
+
+ }
+ scrollok(win_in->ptr, TRUE);
+ checkcursor(mode);
+ wrefresh(win_in->ptr);
+ if (wasscrolledup && !scrolledup){
+ statline(mode, "");
+ }
+ else if (!wasscrolledup && scrolledup){
+ statline(mode, "Viewing Scrollback");
+ }
+}
+
void usage(void)
{
- fprintf(stderr, "usage: call [-b l|e] [-d] [-h] [-m s|e] [-p paclen] [-r] [-R]\n");
- fprintf(stderr, " [-s mycall] [-t] [-T timeout] [-v] [-w window] [-W]\n");
+ fprintf(stderr, "usage: call [-8] [-b l|e] [-d] [-h] [-i] [-m s|e] [-p paclen] [-r] [-R]\n");
+ fprintf(stderr, " [-s mycall] [-S] [-t] [-T timeout] [-v] [-w window] [-W]\n");
fprintf(stderr, " port callsign [[via] digipeaters...]\n");
exit(1);
}
@@ -161,6 +394,73 @@ void convert_upper_lower(char *buf, int len)
}
+
+/* Return the with of this character in character blocks. (Normal = 1, CJK=2)
+ * Also for control chracters, return the width of the replacement string.
+ * */
+static int wcwidthcontrol(wchar_t c)
+{
+ int width;
+ cchar_t cc = {0};
+ wchar_t *str;
+ cc.chars[0] = c;
+ str = wunctrl(&cc);
+ if (!str)return 0;
+ width = wcswidth(str, wcslen(str));
+ return width;
+}
+
+/* Return a string to print for a wchar_t. Expand control characters.
+ * Strings returned by wunctrl don't like to be freed. It seems. */
+static wchar_t *wunctrlwchar(wchar_t c)
+{
+ cchar_t cc = {0};
+ wchar_t *str;
+ cc.chars[0] = c;
+ str = wunctrl(&cc);
+ return str;
+}
+
+// For some reason wins_nwstr fails on fedora 12 on some characters
+// but waddnstr works.
+// Draw the entire input buffer when adding text.
+// The fonts that do overstrike fail when written one char at a time.
+void drawinbuf(WINDOW *w, wchar_t *string, int bytes, int cur_pos)
+{
+ int n, x, cursorx, xpos, ypos, width;
+ getyx(w, ypos, xpos);// Assume cursor to be at position of current char to draw.
+ x = xpos;cursorx = xpos;
+ // cur_pos-1 = the chracter that was just added.
+ for (n=cur_pos-2;n>=0;n--){// Move x position to start of string or 0
+ width = wcwidthcontrol(string[n]);
+ if (x >= width)x -= width;
+ else x = 0;
+ }
+ wmove(w, ypos, x);
+ for (n=0;n<bytes;n++){
+ char obuf[MAX_BUFLEN];
+ char *inbuf, *outbuf = obuf;
+ size_t insize, outsize = MAX_BUFLEN;
+ wchar_t *str;int len, width;
+ if (n == cur_pos){
+ cursorx = x;
+ }
+ str = wunctrlwchar(string[n]);
+ if (!str)continue;
+ inbuf = (char *) str;
+ len = wcslen(str);
+ insize = len * sizeof(wchar_t);
+ width = wcswidth(str, len);
+ iconv(wcharttoutf8, &inbuf, &insize, &outbuf, &outsize);
+ waddnstr(w, obuf, MAX_BUFLEN-outsize);
+ x += width;
+ }
+ if (cur_pos < bytes){
+ wmove(w,ypos, cursorx);
+ }
+}
+
+
/* Convert linear UNIX date to a MS-DOS time/date pair. */
static char * unix_to_sfbin_date_string(time_t gmt)
@@ -412,6 +712,13 @@ static int connect_to(char *address[])
return fd;
}
+
+static void cmd_sigwinch(int sig)
+{
+ signal(SIGWINCH, cmd_sigwinch);
+ sigwinchsignal = TRUE;
+}
+
void cmd_intr(int sig)
{
interrupted = TRUE;
@@ -428,7 +735,7 @@ void statline(int mode, char *s)
if (oldlen > 0) {
move(0, STATW_STAT);
attron(A_REVERSE);
- for (cnt = 0; cnt < oldlen; cnt++)
+ for (cnt = STATW_STAT; cnt < COLS; cnt++)
addch(' ');
oldlen = 0;
attroff(A_REVERSE);
@@ -441,21 +748,18 @@ void statline(int mode, char *s)
fflush(stdout);
return;
}
- if (strlen(s) > 80 - STATW_STAT)
- s[80 - STATW_STAT] = '\0';
+ if (COLS <= STATW_STAT)return;
+ l = strlen(s);
+ if (l > COLS - STATW_STAT)
+ l = COLS-STATW_STAT;
move(0, STATW_STAT);
attron(A_REVERSE);
- addstr(s);
-
- if (oldlen > strlen(s)) {
- l = oldlen - strlen(s);
- for (cnt = 0; cnt < l; cnt++)
- addch(' ');
- }
+ addnstr(s, l);
+ for (cnt = STATW_STAT+l;cnt < COLS;cnt++)addch(' ');
attroff(A_REVERSE);
- oldlen = strlen(s);
+ oldlen = l;
refresh();
}
@@ -800,6 +1104,10 @@ int start_screen(char *call[])
{
int cnt;
char idString[12];
+ struct winsize winsz = {0};
+
+ if ((ioctl(0, TIOCGWINSZ, &winsz) >= 0) && winsz.ws_row && winsz.ws_col)
+ resizeterm(winsz.ws_row, winsz.ws_col);
sprintf(idString, " %9.9s ", call[0]);
if ((win = initscr()) == NULL)
@@ -811,7 +1119,8 @@ int start_screen(char *call[])
addch(ACS_VLINE);
addstr("--------");
addch(ACS_VLINE);
- for (cnt = STATW_STAT; cnt <= 80; cnt++)
+ move(0, STATW_STAT);
+ for (cnt = STATW_STAT; cnt < COLS; cnt++)
addch(' ');
attroff(A_REVERSE);
@@ -819,8 +1128,8 @@ int start_screen(char *call[])
raw();
nodelay(win, TRUE);
keypad(win, TRUE);
+ curson = 1;
refresh();
-
return 0;
}
@@ -841,7 +1150,8 @@ int start_slave_mode(wint * wintab, t_win * win_in, t_win * win_out)
win_out->curs_pos = 0;
win_in->bytes = 0;
win_in->curs_pos = 0;
-
+ redrawscreen(win_in, SLAVEMODE, win_out);
+ wrefresh(win_in->ptr);
return 0;
}
@@ -872,15 +1182,16 @@ int start_talk_mode(wint * wintab, t_win * win_in, t_win * win_out)
scrollok(win_out->ptr, TRUE);
wclear(win_out->ptr);
- wrefresh(win_out->ptr);
wclear(win_in->ptr);
- wrefresh(win_in->ptr);
win_out->bytes = 0;
win_out->curs_pos = 0;
win_in->bytes = 0;
win_out->curs_pos = 0;
-
+ redrawscreen(win_in, TALKMODE, win_out);
+ restorecursor(TALKMODE, win_out);
+ wrefresh(win_in->ptr);
+ wrefresh(win_out->ptr);
return 0;
}
@@ -931,168 +1242,208 @@ int change_mode(int oldmode, int newmode, wint * wintab, t_win * win_in,
break;
}
+ scrolledup = 0;
return newmode;
}
-void writeincom(int mode, t_win * win_in, unsigned char buf[], int bytes)
+static void reinit_mode(int mode, wint * wintab, t_win * win_in, t_win * win_out, char *call[])
{
- int cnt;
-
- if (mode & RAWMODE) {
- while (write(STDOUT_FILENO, buf, bytes) == -1) {
- if (errno == EWOULDBLOCK || errno == EAGAIN) {
- usleep(100000);
- continue;
- }
- exit(1);
- }
- return;
- }
- for (cnt = 0; cnt < bytes; cnt++) {
- switch (buf[cnt]) {
- case 201:
- case 218:
- waddch(win_in->ptr, ACS_ULCORNER);
- break;
- case 187:
- case 191:
- waddch(win_in->ptr, ACS_URCORNER);
- break;
- case 200:
- case 192:
- waddch(win_in->ptr, ACS_LLCORNER);
- break;
- case 188:
- case 217:
- waddch(win_in->ptr, ACS_LRCORNER);
- break;
- case 204:
- case 195:
- waddch(win_in->ptr, ACS_LTEE);
- break;
- case 185:
- case 180:
- waddch(win_in->ptr, ACS_RTEE);
- break;
- case 203:
- case 194:
- waddch(win_in->ptr, ACS_TTEE);
- break;
- case 202:
- case 193:
- waddch(win_in->ptr, ACS_BTEE);
- break;
- case 205:
- case 196:
- waddch(win_in->ptr, ACS_HLINE);
- break;
- case 186:
- case 179:
- waddch(win_in->ptr, ACS_VLINE);
- break;
- case 129:
- waddch(win_in->ptr, 252); /*u umlaut */
- break;
- case 132:
- waddch(win_in->ptr, 228); /*a umlaut */
- break;
- case 142:
- waddch(win_in->ptr, 196); /*A umlaut */
- break;
- case 148:
- waddch(win_in->ptr, 246); /*o umlaut */
- break;
- case 153:
- waddch(win_in->ptr, 214); /*O umlaut */
- break;
- case 154:
- waddch(win_in->ptr, 220); /*U umlaut */
- break;
- case 225:
- waddch(win_in->ptr, 223); /*sz */
- break;
- default:
- {
- if (buf[cnt] > 127)
- waddch(win_in->ptr, '.');
- else
- waddch(win_in->ptr, buf[cnt]);
- }
- }
+ switch (mode) {
+ case RAWMODE:
+ break;
+ case TALKMODE:// Clear the screen and re-init. Which looks awful.
+ wclear(win_out->ptr);
+ wrefresh(win_out->ptr);
+ wclear(win_in->ptr);
+ //wrefresh(win_in->ptr);
+ wintab->next = 0;
+ endwin();
+ start_screen(call);
+ start_talk_mode(wintab, win_in, win_out);
+ restorecursor(mode, win_out);
+ break;
+ case SLAVEMODE:// Also fix me.
+ wclear(win_out->ptr);
+ //wrefresh(win_out->ptr);
+ wintab->next = 0;
+ endwin();
+ start_screen(call);
+ start_slave_mode(wintab, win_in, win_out);
+ restorecursor(mode, win_out);
+ break;
}
-
-/* waddnstr(win_in->ptr, buf, bytes); */
- wrefresh(win_in->ptr);
}
-int getstring(wint * wintab, char text[], char buf[])
+void waddnstrcrcheck(t_win *win_in, char *buf, int bytes, int draw, int mode, t_win *win_out)
{
- int c;
- int ypos = 0, xpos = 0;
- int bytes = 0;
+ int n;
+ for (n=0;n<bytes;n++){
+ int width;
+ incharbuf[incharbuflen++] = buf[n];
+ if (completecharlen(incharbuf) > incharbuflen)continue;
+ if (eatchar && (incharbuf[0] == '\n')){
+ eatchar = 0;
+ incharbuflen = 0;
+ continue;
+ }
+ width = widthchar(incharbuf, incharbuflen, inbufwid);
+ eatchar = 0;
+ if (draw) {
+ if (win_in) waddnstr(win_in->ptr, incharbuf, incharbuflen);
+ else write(STDOUT_FILENO, incharbuf, incharbuflen);
+ }
+ if (incharbuf[0] == '\n')incharbuflen = 0;
+ else if (width + inbufwid <= COLS){
+ if (inbuflen + incharbuflen <= MAX_BUFLEN){
+ memcpy(&inbuf[inbuflen], incharbuf, incharbuflen);
+ inbuflen += incharbuflen;
+ }
+ incharbuflen = 0;
+ inbufwid += width;
+ if (inbufwid >= COLS)eatchar = 1;
+ continue;// Skip to next line when width goes over.
+ }
+ addscrollline(inbuf, inbuflen);
+ if (incharbuflen){
+ memcpy(&inbuf[0], incharbuf, incharbuflen);
+ inbuflen = incharbuflen;
+ incharbuflen = 0;
+ inbufwid = width;
+ }
+ else {
+ inbuflen = 0;
+ inbufwid = 0;
+ }
+ if (scrolledup && win_in && win_out){
+ scrolledup++; // scrolledup is relative to bottom line
+ scrolltext(win_in, 0, mode, win_out);
+ }
+ }
+ if (draw && win_in) wrefresh(win_in->ptr);
+
+}
- WINDOW *win = winopen(wintab, 3, COLS, 10, 0, TRUE);
- wmove(win, 1, 2);
- waddstr(win, text);
- wrefresh(win);
+void writeincom(int mode, int encoding, t_win * win_in, unsigned char buf[], int bytes, t_win *win_out)
+{
+ if (mode & RAWMODE) {
+ while (write(STDOUT_FILENO, buf, bytes) == -1) {
+ if (errno == EWOULDBLOCK || errno == EAGAIN) {
+ usleep(100000);
+ continue;
+ }
+ exit(1);
+ }
+ return;
+ } else if (encoding == UTF8ENCODING)
+ waddnstrcrcheck(win_in, (char *)buf, bytes,scrolledup == 0, mode, win_out);
+ else {
+ char *inbuf = (char *) buf, out[MAX_BUFLEN], *outbuf=out;
+ size_t insize = bytes, outsize = MAX_BUFLEN;
+ iconv(ibm850toutf8, &inbuf, &insize, &outbuf, &outsize);
+ waddnstrcrcheck(win_in, out, MAX_BUFLEN-outsize,scrolledup == 0, mode, win_out);
+ }
+ return;
+}
+static void writeincomstr(int mode, int encoding, t_win * win_in, char buf[], t_win *win_out)
+{
+ int len;
+ len = strlen(buf);
+ writeincom(mode, encoding, win_in, (unsigned char *)buf, len, win_out);
+}
- do {
- c = getch();
- if (c != ERR) {
- switch (c) {
- case KEY_BACKSPACE:
- case 127:
- {
- getyx(win, ypos, xpos);
- if (xpos > 0 && bytes > 0) {
- wmove(win, ypos, --xpos);
- waddch(win, ' ');
- wmove(win, ypos, xpos);
- bytes--;
- }
- }
- break;
- case (int) '\n':
- case (int) '\r':
- case KEY_ENTER:
- {
- waddch(win, '\n');
- buf[bytes++] = (char) '\n';
- wrefresh(win);
- buf[bytes] = 0;
- }
- break;
- default:
- {
- waddch(win, (char) c);
- buf[bytes++] = (char) c;
- }
- }
- wrefresh(win);
- }
- }
- while (c != '\n' && c != '\r' && c != KEY_ENTER);
- delwin(win);
- winclose(wintab);
- return 0;
+int outstring(char *buf, wchar_t *string, int bytes, int encoding)
+{
+ char *inbuf = (char *) string, *outbuf = buf;
+ size_t insize = bytes * sizeof(wchar_t), outsize = MAX_BUFLEN-1;
+ if (encoding == UTF8ENCODING){
+ iconv(wcharttoutf8, &inbuf, &insize, &outbuf, &outsize);
+ }
+ else {
+ iconv(wcharttoibm850, &inbuf, &insize, &outbuf, &outsize);
+
+ }
+ buf[(MAX_BUFLEN-1)-outsize] = '\0';
+ return (MAX_BUFLEN-1)-outsize;
+}
+
+int getstring(wint * wintab, char text[], char buf[])
+{
+ wchar_t c;
+ int ypos = 0, xpos = 0;
+ int bytes = 0;
+ wchar_t wbuf[MAX_BUFLEN];
+ WINDOW *win = winopen(wintab, 3, COLS, 10, 0, TRUE);
+ int done = 0;
+
+ wmove(win, 1, 2);
+ waddstr(win, text);
+ wrefresh(win);
+
+ do {
+ int r;
+ wint_t ci;
+ r = get_wch(&ci);
+ if (r != ERR) {
+ c = (wchar_t) ci;
+ if (((r == KEY_CODE_YES) && (c == KEY_BACKSPACE))||
+ ((r == OK) && ((c==127)|| (c==8)))){
+ getyx(win, ypos, xpos);
+ if (bytes > 0) {
+ int width, j;
+ width = wcwidthcontrol(wbuf[bytes-1]);
+ for (j=0;j<width;j++) mvwdelch(win, ypos, xpos-width);
+ xpos -= width;
+ wmove(win, ypos, xpos);
+ bytes--;
+ }
+ }
+ else if (( (r==KEY_CODE_YES) && (c == KEY_ENTER))||
+ ( (r == OK) && ((c=='\n') || (c=='\r')))){
+ wbuf[bytes++] = (wchar_t) '\n';
+ outstring(buf, wbuf, bytes, UTF8ENCODING);
+ done = 1;
+ }
+ else if (r == KEY_CODE_YES); // Put in code for other KEYCODES here
+ else if (bytes+2 < MAX_BUFLEN){
+ //int width;
+ //width = wins_nwchrmy(win, c);
+ //getyx(win, ypos, xpos);
+ //wmove(win, ypos, xpos+width);
+ wbuf[bytes++] = c;
+ drawinbuf(win, wbuf, bytes, bytes);
+ }
+ wrefresh(win);
+ }
+ }
+ while (!done);
+ delwin(win);
+ winclose(wintab);
+ return 0;
}
+
int readoutg(t_win * win_out, wint * wintab, menuitem * top, char buf[],
- int keyesc)
+ int keyesc, int mode, int encoding, t_win *win_in)
{
int out_cnt;
- int c;
+ int r;
+ wint_t ci;
+ wchar_t c;
int ypos = 0, xpos = 0;
int value;
- c = getch();
- if (c == ERR)
+ r = get_wch(&ci);
+ if (r == ERR)
return 0;
+ c = (wchar_t) ci;
if (c == keyesc) {
- if ((value = top_menu(wintab, top, 1)) == 0)
+ if ((value = top_menu(wintab, top, 1)) == 0) {
+ restorecursor(mode, win_out);
return 0;
+ }
+ restorecursor(mode, win_out);
buf[0] = '~';
switch (value) {
case 0x01:
@@ -1111,6 +1462,7 @@ int readoutg(t_win * win_out, wint * wintab, menuitem * top, char buf[],
getstring(wintab,
"Please enter filename: ",
&buf[2]);
+ restorecursor(mode, win_out);
return strlen(buf);
}
case 0x12:
@@ -1135,6 +1487,7 @@ int readoutg(t_win * win_out, wint * wintab, menuitem * top, char buf[],
getstring(wintab,
"Please enter filename: ",
buf + 2);
+ restorecursor(mode, win_out);
return strlen(buf);
}
case 0x21:
@@ -1158,97 +1511,164 @@ int readoutg(t_win * win_out, wint * wintab, menuitem * top, char buf[],
wrefresh(win_out->ptr);
return 2;
}
- switch (c) {
- case KEY_BACKSPACE:
- case 127:
- {
+ if (((r == KEY_CODE_YES) && (c == KEY_BACKSPACE))||
+ ((r == OK) && ((c==127)|| (c==8)))){
+ if ((mode == SLAVEMODE) && scrolledup) return 0;
+ while(win_out->curs_pos > 0){
+ int width;int j;
getyx(win_out->ptr, ypos, xpos);
- if (win_out->bytes > 0) {
- if (win_out->curs_pos < win_out->bytes) {
- mvwaddnstr(win_out->ptr, ypos,
- --xpos,
- &win_out->
- string[win_out->
- curs_pos],
- win_out->bytes -
- win_out->curs_pos);
- waddch(win_out->ptr, ' ');
- memmove(&win_out->
- string[win_out->curs_pos -
- 1],
- &win_out->string[win_out->
- curs_pos],
- win_out->bytes -
- win_out->curs_pos);
- } else
- mvwaddch(win_out->ptr, ypos,
- --xpos, ' ');
-
- wmove(win_out->ptr, ypos, xpos);
- win_out->bytes--;
- win_out->curs_pos--;
- }
- }
- break;
- case KEY_LEFT:
- if (win_out->curs_pos > 0) {
+ width = wcwidthcontrol(win_out->string[win_out->curs_pos-1]);
+ for (j=0;j<width;j++) mvwdelch(win_out->ptr, ypos, xpos-width);
+ xpos -= width;
+ wmove(win_out->ptr, ypos, xpos);
+ if (win_out->curs_pos < win_out->bytes) {
+ memmove(&win_out->
+ string[win_out->curs_pos - 1],
+ &win_out->string[win_out-> curs_pos],
+ (win_out->bytes -
+ win_out->curs_pos) * sizeof(wchar_t));
+ }
+ win_out->bytes--;
win_out->curs_pos--;
- getyx(win_out->ptr, ypos, xpos);
- wmove(win_out->ptr, ypos, xpos - 1);
+ if (width)break;
}
- break;
- case KEY_RIGHT:
- if (win_out->curs_pos < win_out->bytes) {
+ }
+ else if (( (r==KEY_CODE_YES) && (c == KEY_ENTER))||
+ ( (r == OK) && ((c=='\n') || (c=='\r')))){
+ if ((mode == SLAVEMODE) && scrolledup) return 0;
+ while (win_out->curs_pos < win_out->bytes) { // Move to end of the line
+ int width;
+ width = wcwidthcontrol(win_out->string[win_out->curs_pos]);
win_out->curs_pos++;
getyx(win_out->ptr, ypos, xpos);
- wmove(win_out->ptr, ypos, xpos + 1);
+ wmove(win_out->ptr, ypos, xpos + width);
+ }
+ waddch(win_out->ptr, '\n');
+ win_out->string[win_out->bytes++] = (wchar_t) '\n';
+ wrefresh(win_out->ptr);
+ out_cnt = outstring(buf, win_out->string, win_out->bytes, encoding);
+ if (mode == SLAVEMODE){
+ char obuf[MAX_BUFLEN];
+ char *inbuf = (char *)win_out->string, *outbuf = obuf;
+ size_t insize = win_out->bytes * sizeof(wchar_t), outsize = MAX_BUFLEN;
+ iconv(wcharttoutf8, &inbuf, &insize, &outbuf, &outsize);
+ waddnstrcrcheck(win_in, obuf, MAX_BUFLEN-outsize, 0, mode, win_out);
}
- break;
- case KEY_ENTER:
- case (int) '\n':
- case (int) '\r':
- {
- if (win_out->curs_pos < win_out->bytes) {
- getyx(win_out->ptr, ypos, xpos);
- wmove(win_out->ptr, ypos,
- xpos + win_out->bytes -
- win_out->curs_pos);
+ win_out->bytes = 0;
+ win_out->curs_pos = 0;
+ return out_cnt;
+ }
+ else if (r == KEY_CODE_YES){
+ switch(c){
+ case KEY_LEFT:// Character of 0 width
+ while (win_out->curs_pos > 0) {
+ int width;
+ win_out->curs_pos--;
+ width = wcwidthcontrol(win_out->string[win_out->curs_pos]);
+ getyx(win_out->ptr, ypos, xpos);
+ wmove(win_out->ptr, ypos, xpos - width);
+ if (width)break; // Skip to non-width
+ }
+ break;
+ case KEY_RIGHT:
+ {
+ int skipped = 0;// Skip over 0 length characters
+ while (win_out->curs_pos < win_out->bytes) {
+ int width;
+ width = wcwidthcontrol(win_out->string[win_out->curs_pos]);
+ if (width){
+ if (skipped)break;
+ skipped = 1;
+ }
+ win_out->curs_pos++;
+ getyx(win_out->ptr, ypos, xpos);
+ wmove(win_out->ptr, ypos, xpos + width);
+ }
+ break;
}
- waddch(win_out->ptr, '\n');
- win_out->string[win_out->bytes++] = (char) '\n';
- wrefresh(win_out->ptr);
- strncpy(buf, win_out->string, win_out->bytes);
- wrefresh(win_out->ptr);
- out_cnt = win_out->bytes;
- win_out->bytes = 0;
- win_out->curs_pos = 0;
- return out_cnt;
+ case KEY_UP:
+ scrolltext(win_in, 1, mode, win_out);
+ break;
+ case KEY_DOWN:
+ scrolltext(win_in, -1, mode, win_out);
+ break;
+ case KEY_NPAGE:
+ scrolltext(win_in, -win_in->max_y, mode, win_out);
+ break;
+ case KEY_PPAGE:
+ scrolltext(win_in, win_in->max_y, mode, win_out);
+ break;
+ case KEY_HOME:
+ while (win_out->curs_pos > 0) {
+ int width;
+ win_out->curs_pos--;
+ width = wcwidthcontrol(win_out->string[win_out->curs_pos]);
+ getyx(win_out->ptr, ypos, xpos);
+ wmove(win_out->ptr, ypos, xpos - width);
+ }
+ break;
+ case KEY_END:
+ while (win_out->curs_pos < win_out->bytes) { // Move to end of the line
+ int width;
+ width = wcwidthcontrol(win_out->string[win_out->curs_pos]);
+ win_out->curs_pos++;
+ getyx(win_out->ptr, ypos, xpos);
+ wmove(win_out->ptr, ypos, xpos + width);
+ }
+ break;
+ case KEY_DC:{
+ int skipped = 0;
+ if ((mode == SLAVEMODE) && scrolledup) return 0;
+ while (win_out->curs_pos < win_out->bytes){
+ int width;int j;
+ getyx(win_out->ptr, ypos, xpos);
+ width = wcwidthcontrol(win_out->string[win_out->curs_pos]);
+ if (width){
+ if (skipped)break;
+ skipped = 1;
+ }
+ for (j=0;j<width;j++) mvwdelch(win_out->ptr, ypos, xpos);
+ if (win_out->curs_pos + 1 < win_out->bytes) {
+ memmove(&win_out-> string[win_out->curs_pos],
+ &win_out->string[win_out-> curs_pos+1],
+ (win_out->bytes - (win_out->curs_pos+1)) * sizeof(wchar_t));
+ }
+ win_out->bytes--;
+ }
+ break;
+ }
+ case KEY_RESIZE:
+ break;
+ case KEY_BACKSPACE:
+ break;
+ case KEY_ENTER:
+ break;
+ default:
+ break;
}
+ }
+ else switch (c) {
+ case 8:
+ case 127:
+ case '\r':
+ case '\n':
break;
default:
- {
- waddch(win_out->ptr, (char) c);
+ if ((mode == SLAVEMODE) && scrolledup) return 0; // Don't try to edit while scrolled up in SLAVEmode.
+ // It's just not possible because the cursor is off screen
+ if (win_out->bytes < MAX_BUFLEN ) {
if (win_out->curs_pos < win_out->bytes) {
- getyx(win_out->ptr, ypos, xpos);
- waddnstr(win_out->ptr,
- &win_out->string[win_out->
- curs_pos],
- win_out->bytes -
- win_out->curs_pos);
memmove(&win_out->
string[win_out->curs_pos + 1],
- &win_out->string[win_out->
- curs_pos],
- win_out->bytes -
- win_out->curs_pos);
- win_out->string[win_out->curs_pos] =
- (char) c;
- wmove(win_out->ptr, ypos, xpos);
- } else
- win_out->string[win_out->bytes] = (char) c;
-
+ &win_out->string[win_out-> curs_pos],
+ (win_out->bytes -
+ win_out->curs_pos) * sizeof(wchar_t));
+ }
+ win_out->string[win_out->curs_pos] = c;
win_out->bytes++;
win_out->curs_pos++;
+ drawinbuf(win_out->ptr, win_out->string, win_out->bytes, win_out->curs_pos);
+ break;
}
}
wrefresh(win_out->ptr);
@@ -1521,8 +1941,8 @@ void statbits(int mode, char stat, int m)
refresh();
}
-
-int cmd_call(char *call[], int mode)
+
+int cmd_call(char *call[], int mode, int encoding)
{
menuitem con[] = {
{"~Reconnect", 'R', M_ITEM, (void *) 0x01},
@@ -1585,8 +2005,8 @@ int cmd_call(char *call[], int mode)
int upllen = 0;
char *c, *t;
t_gp gp;
- t_win win_in;
- t_win win_out;
+ t_win win_in = {0};
+ t_win win_out = {0};
WINDOW *swin = 0;
int cnt;
int crc = 0;
@@ -1607,9 +2027,11 @@ int cmd_call(char *call[], int mode)
return FALSE;
interrupted = FALSE;
+ sigwinchsignal = FALSE;
signal(SIGQUIT, cmd_intr);
signal(SIGINT, SIG_IGN);
signal(SIGTSTP, SIG_IGN);
+ signal(SIGWINCH, cmd_sigwinch);
sigemptyset(&oursigs);
sigaddset(&oursigs, SIGQUIT);
@@ -1668,6 +2090,12 @@ int cmd_call(char *call[], int mode)
usleep(100000);
continue;
}
+ if ((errno == EINTR) && sigwinchsignal) {
+ // Just process screen resize here.
+ reinit_mode(mode, &wintab, &win_in, &win_out, call);
+ sigwinchsignal = 0;
+ continue;
+ }
perror("select");
}
break;
@@ -1715,8 +2143,9 @@ int cmd_call(char *call[], int mode)
convert_cr_lf(buf, bytes);
if (!sevenplus) {
- writeincom(mode, &win_in,
- (unsigned char * ) buf, bytes);
+ writeincom(mode, encoding, &win_in,
+ (unsigned char * ) buf, bytes, &win_out);
+ restorecursor(mode, &win_out);
} else {
for (cnt = 0; cnt < bytes;
cnt++)
@@ -1843,7 +2272,7 @@ int cmd_call(char *call[], int mode)
} else {
bytes =
readoutg(&win_out, &wintab, top, buf,
- 0x1d);
+ 0x1d, mode, encoding, &win_in);
if (bytes == -1) {
wclear(win_in.ptr);
wrefresh(win_in.ptr);
@@ -1908,24 +2337,26 @@ int cmd_call(char *call[], int mode)
case '?':
case 'h':
case 'H':
- printf("\nTilde escapes:\n");
- printf(". close\n");
- printf("~ send ~\n");
- printf("r reconnect\n");
- printf("! shell\n");
- printf("Z suspend program. Resume with \"fg\"\n");
- printf("s Stop upload\n");
- printf("o Open log\n");
- printf("c Close log\n");
- printf("0 Switch GUI to \"RAW\" (line) mode - already here ;)\n");
- printf("1 Switch GUI to \"Slave\" mode\n");
- printf("2 Switch GUI to \"Talk\" (split) mode\n");
- printf("u Upload\n");
- printf("a Upload (autobin protocol)\n");
- printf("b Upload binary data (crlf conversion)\n");
- printf("yd YAPP Download\n");
- printf("yu YAPP Upload\n");
- fflush(stdout);
+ writeincomstr(mode, encoding, &win_in,"\nTilde escapes:\n", &win_out);
+ writeincomstr(mode, encoding, &win_in,". close\n", &win_out);
+ writeincomstr(mode, encoding, &win_in,"~ send ~\n", &win_out);
+ writeincomstr(mode, encoding, &win_in,"r reconnect\n", &win_out);
+ writeincomstr(mode, encoding, &win_in,"! shell\n", &win_out);
+ writeincomstr(mode, encoding, &win_in,"Z suspend program. Resume with \"fg\"\n", &win_out);
+ writeincomstr(mode, encoding, &win_in,"s Stop upload\n", &win_out);
+ writeincomstr(mode, encoding, &win_in,"o Open log\n", &win_out);
+ writeincomstr(mode, encoding, &win_in,"c Close log\n", &win_out);
+ writeincomstr(mode, encoding, &win_in,"0 Switch GUI to \"RAW\" (line) mode - already here ;)\n", &win_out);
+ writeincomstr(mode, encoding, &win_in,"1 Switch GUI to \"Slave\" mode\n", &win_out);
+ writeincomstr(mode, encoding, &win_in,"2 Switch GUI to \"Talk\" (split) mode\n", &win_out);
+ writeincomstr(mode, encoding, &win_in,"u Upload\n", &win_out);
+ writeincomstr(mode, encoding, &win_in,"a Upload (autobin protocol)\n", &win_out);
+ writeincomstr(mode, encoding, &win_in,"b Upload binary data (crlf conversion)\n", &win_out);
+ writeincomstr(mode, encoding, &win_in,"yd YAPP Download\n", &win_out);
+ writeincomstr(mode, encoding, &win_in,"yu YAPP Upload\n", &win_out);
+ writeincomstr(mode, encoding, &win_in,"i IBM850 encoding\n", &win_out);
+ writeincomstr(mode, encoding, &win_in,"8 UTF-8 encoding\n", &win_out);
+ restorecursor(mode, &win_out);
continue;
case 'S':
case 's':
@@ -1938,6 +2369,7 @@ int cmd_call(char *call[], int mode)
statline(mode,
"No upload in progress");
}
+ restorecursor(mode, &win_out);
continue;
case 'A':
case 'a':
@@ -1948,6 +2380,7 @@ int cmd_call(char *call[], int mode)
if (uploadfile != -1) {
statline(mode,
"Already uploading");
+ restorecursor(mode, &win_out);
continue;
}
if ((t =
@@ -1959,12 +2392,14 @@ int cmd_call(char *call[], int mode)
if (*t == '\0') {
statline(mode,
"Upload requires a filename");
+ restorecursor(mode, &win_out);
continue;
}
uploadfile = open(t, O_RDONLY);
if (uploadfile == -1) {
statline(mode,
"Unable to open upload file");
+ restorecursor(mode, &win_out);
continue;
}
if (lseek(uploadfile, 0L, SEEK_END)
@@ -2063,8 +2498,9 @@ int cmd_call(char *call[], int mode)
uplpos = 0;
upldp = -1;
upllen = 0;
- }
- break;
+ }
+ restorecursor(mode, &win_out);
+ break;
case 'b':
case 'B':
binup = TRUE;
@@ -2102,6 +2538,7 @@ int cmd_call(char *call[], int mode)
statline(mode, s);
} else
statbits(mode, 'L', 1);
+ restorecursor(mode, &win_out);
continue;
case 'C':
case 'c':
@@ -2113,10 +2550,12 @@ int cmd_call(char *call[], int mode)
statline(mode,
"Log file not open");
}
+ restorecursor(mode, &win_out);
continue;
case 'Y':
case 'y':
cmd_yapp(buf + 2, bytes - 2);
+ restorecursor(mode, &win_out);
continue;
case '~':
bytes--;
@@ -2146,9 +2585,21 @@ int cmd_call(char *call[], int mode)
&wintab, &win_in,
&win_out, call);
continue;
+ case '8':
+ encoding = UTF8ENCODING;
+ statline(mode, "UTF-8 encoding");
+ restorecursor(mode, &win_out);
+ continue;
+ case 'i':
+ case 'I':
+ encoding = ORIGINALENCODING;
+ statline(mode, "IBM850 encoding");
+ restorecursor(mode, &win_out);
+ continue;
default:
statline(mode,
"Unknown '~' escape. Type ~h for a list");
+ restorecursor(mode, &win_out);
continue;
}
}
@@ -2164,8 +2615,10 @@ int cmd_call(char *call[], int mode)
if (uploadfile != -1) {
statline(mode,
"Ignored. Type ~s to stop upload");
+ restorecursor(mode, &win_out);
continue;
}
+
convert_lf_cr(buf, bytes);
while (offset != bytes) {
@@ -2199,6 +2652,7 @@ int cmd_call(char *call[], int mode)
winclose(&wintab);
statline(mode,
"Upload complete: 0 bytes");
+ restorecursor(mode, &win_out);
continue;
}
if (upldp == -1) {
@@ -2214,6 +2668,7 @@ int cmd_call(char *call[], int mode)
"Upload complete: %ld bytes",
uplpos);
statline(mode, s);
+ restorecursor(mode, &win_out);
continue;
}
if (upllen == -1) {
@@ -2225,6 +2680,7 @@ int cmd_call(char *call[], int mode)
"Error reading upload file: upload aborted at %ld bytes",
uplpos);
statline(mode, s);
+ restorecursor(mode, &win_out);
continue;
}
if (!binup)
@@ -2244,6 +2700,7 @@ int cmd_call(char *call[], int mode)
if (errno != EWOULDBLOCK && errno != EAGAIN) {
sprintf(s, "Write error during upload. Connection lost");
statline(mode, s);
+ restorecursor(mode, &win_out);
perror("write");
break;
}
@@ -2302,18 +2759,27 @@ int cmd_call(char *call[], int mode)
}
}
+void iconvclose(void)
+{
+ iconv_close(ibm850toutf8);
+ iconv_close(wcharttoibm850);
+ iconv_close(wcharttoutf8);
+ iconv_close(utf8towchart);
+}
int main(int argc, char **argv)
{
int p;
int mode = TALKMODE;
+ int encoding = UTF8ENCODING;// Maybe controversial?
+ setlocale(LC_ALL, "");
if (!isatty(STDIN_FILENO))
stdin_is_tty = 0;
setlinebuf(stdin);
- while ((p = getopt(argc, argv, "b:dhm:p:rs:RStT:vw:W")) != -1) {
+ while ((p = getopt(argc, argv, "b:dhm:p:rs:RStT:vw:Wi8")) != -1) {
switch (p) {
case 'b':
if (*optarg != 'e' && *optarg != 'l') {
@@ -2350,6 +2816,7 @@ int main(int argc, char **argv)
}
break;
case 'r':
+ COLS = 80; // This is used to format the scrollback buffer, which is stored in raw
mode = RAWMODE;
break;
case 's':
@@ -2402,6 +2869,12 @@ int main(int argc, char **argv)
case 'W':
wait_for_remote_disconnect = TRUE;
break;
+ case 'i':
+ encoding = ORIGINALENCODING;
+ break;
+ case '8':
+ encoding = UTF8ENCODING;
+ break;
case '?':
case ':':
usage();
@@ -2411,6 +2884,13 @@ int main(int argc, char **argv)
if (optind == argc || optind == argc - 1) {
usage();
}
+
+ ibm850toutf8 = iconv_open("UTF8", "IBM850");
+ wcharttoibm850 = iconv_open("IBM850", "WCHAR_T");
+ wcharttoutf8 = iconv_open("UTF8", "WCHAR_T");
+ utf8towchart = iconv_open("WCHAR_T", "UTF8");
+ atexit(iconvclose);
+
port = argv[optind];
if (ax25_config_load_ports() == 0) {
@@ -2459,7 +2939,7 @@ int main(int argc, char **argv)
printf("GW4PTS AX.25 Connect v1.11\n");
fflush(stdout);
}
- while (cmd_call(argv + optind + 1, mode)) {
+ while (cmd_call(argv + optind + 1, mode, encoding)) {
if (!be_silent) {
printf("Wait 60 sec before reconnect\n");
fflush(stdout);