--- call/call.c	2009-06-21 07:09:49.000000000 -0700
+++ callintl/call.c	2009-12-25 03:12:23.328605199 -0800
@@ -35,7 +35,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 <ncurses.h>
+#include <locale.h>
+#include <iconv.h>
+#include <sys/ioctl.h>
 
 #include <netax25/ax25.h>
 #include <netrom/netrom.h>
@@ -78,10 +85,13 @@
 static char *mycall = NULL;
 
 static int stdin_is_tty = 1;
+static iconv_t ibm850toutf8 = 0,wcharttoibm850 = 0, wcharttoutf8 = 0, utf8towchart = 0;
 
 int interrupted = FALSE;
+static int sigwinchsignal = FALSE;
 int paclen = 0;
 int fd;
+int curson = 1;
 
 #define GP_FILENAME_SIZE	255
 typedef struct {
@@ -98,7 +108,7 @@
 	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;
@@ -107,6 +117,229 @@
 #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, err;
+	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;
+	err= 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] [-s mycall] [-t] [-v] [-w window] port callsign [[via] digipeaters...]\n");
@@ -149,6 +382,73 @@
 }
 
 
+
+/* 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)
@@ -387,6 +687,13 @@
 	return (fd);
 }
 
+
+static void cmd_sigwinch(int sig)
+{
+	signal(SIGWINCH, cmd_sigwinch);
+	sigwinchsignal = TRUE;
+}
+
 void cmd_intr(int sig)
 {
 	signal(SIGQUIT, cmd_intr);
@@ -404,7 +711,7 @@
 		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);
@@ -417,21 +724,18 @@
 		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();
 }
 
@@ -752,8 +1056,11 @@
 {
 	int cnt;
 	char idString[11];
-	sprintf(idString, " %8s ", call[0]);
+	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, " %8s ", call[0]);
 	if ((win = initscr()) == NULL)
 		return -1;
 
@@ -763,7 +1070,8 @@
 	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);
 
@@ -771,8 +1079,8 @@
 	raw();
 	nodelay(win, TRUE);
 	keypad(win, TRUE);
+	curson = 1;
 	refresh();
-
 	return 0;
 }
 
@@ -793,7 +1101,8 @@
 	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;
 }
 
@@ -824,15 +1133,16 @@
 	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;
 }
 
@@ -882,165 +1192,201 @@
 		}
 		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;
+	switch (mode) {
+	case RAWMODE:
+		break;
 
-	if (mode & RAWMODE) {
-		write(STDOUT_FILENO, buf, bytes);
-		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 */
+	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 225:
-			waddch(win_in->ptr, 223);	/*sz */
+
+	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;
-		default:
-			{
-				if (buf[cnt] > 127)
-					waddch(win_in->ptr, '.');
-				else
-					waddch(win_in->ptr, buf[cnt]);
+	}
+}
+
+
+void waddnstrcrcheck(t_win *win_in, char *buf, int bytes, int draw, int mode, t_win *win_out)
+{
+	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);
+	
+}
 
-/*      waddnstr(win_in->ptr, buf, bytes); */
-	wrefresh(win_in->ptr);
 
+void writeincom(int mode, int encoding, t_win * win_in, unsigned char buf[], int bytes, t_win *win_out)
+{
+	if (mode & RAWMODE) waddnstrcrcheck(0, (char *)buf, bytes,1, mode, 0);
+	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);
+}
+
+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[])
 {
-	int c;
+	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 {
-		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;
+		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')))){
+				int out_cnt;
+				wbuf[bytes++] = (wchar_t) '\n';
+		 		out_cnt = 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 (c != '\n' && c != '\r' && c != KEY_ENTER);
+	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 out_cnt, 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:
@@ -1059,6 +1405,7 @@
 				getstring(wintab,
 					  "Please enter filename: ",
 					  &buf[2]);
+				restorecursor(mode, win_out);
 				return strlen(buf);
 			}
 		case 0x12:
@@ -1083,6 +1430,7 @@
 				getstring(wintab,
 					  "Please enter filename: ",
 					  buf + 2);
+				restorecursor(mode, win_out);
 				return strlen(buf);
 			}
 		case 0x21:
@@ -1106,97 +1454,164 @@
 		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);
-		}
-		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);
+			wmove(win_out->ptr, ypos, xpos + width);
 			}
-			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;
+		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);
+		}
+		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;
+			}
+			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);
@@ -1465,8 +1880,8 @@
 	return;
 }
 
-
-int cmd_call(char *call[], int mode)
+	
+int cmd_call(char *call[], int mode, int encoding)
 {
 	menuitem con[] = {
 		{"~Reconnect", 'R', M_ITEM, (void *) 0x01},
@@ -1530,8 +1945,8 @@
 	char *c, *t;
 	int extrach = 0;
 	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;
@@ -1548,12 +1963,14 @@
 
 	if ((fd = connect_to(call)) == -1)
 		return FALSE;
-
+	
 	interrupted = FALSE;
+	sigwinchsignal = FALSE;
 	signal(SIGQUIT, cmd_intr);
 	signal(SIGINT, SIG_IGN);
 	signal(SIGTSTP, SIG_IGN);
-
+	signal(SIGWINCH, cmd_sigwinch);
+	
 	fcntl(fd, F_SETFL, O_NONBLOCK);
 	fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK);
 
@@ -1572,26 +1989,37 @@
 			fflush(stdout);
 		}
 	}
-
+	
 	while (TRUE) {
-		struct timeval tv;
+		struct timespec tv;
+		sigset_t sigmask;
 		tv.tv_sec = 0;
-		tv.tv_usec = 10;
+		tv.tv_nsec = 10000; 
 
 		FD_ZERO(&sock_read);
 		FD_SET(STDIN_FILENO, &sock_read);
 		FD_SET(fd, &sock_read);
 		FD_ZERO(&sock_write);
-
+		sigemptyset(&sigmask);
 		if (uploadfile != -1)
 			FD_SET(fd, &sock_write);
 
-		if (select(fd + 1, &sock_read, &sock_write, NULL, (uploadfile == -1 && downloadfile == -1) ? NULL : &tv) == -1) {
+		if (pselect(fd + 1, &sock_read, &sock_write, NULL, (uploadfile == -1 && downloadfile == -1) ? NULL : &tv, &sigmask) == -1) {
 			if (!interrupted && errno == EAGAIN)
 				continue;
-			if (!interrupted)
-				perror("select");
-			break;
+			if ((errno == EINTR) && sigwinchsignal){
+				// Just process screen resize here.
+				reinit_mode(mode, &wintab, &win_in,
+					&win_out, call);
+				sigwinchsignal = 0;
+				continue;
+			}
+			else {
+				if (!interrupted){
+ 					perror("select");
+				}
+				break;
+			}	
 		}
 		if (FD_ISSET(fd, &sock_read)) {
 			/* bytes = read(fd, buf, 511); */
@@ -1629,8 +2057,9 @@
 					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++)
@@ -1744,7 +2173,7 @@
 			} 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);
@@ -1809,24 +2238,26 @@
 				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':
@@ -1839,6 +2270,7 @@
 						statline(mode,
 							 "No upload in progress");
 					}
+					restorecursor(mode, &win_out);
 					continue;
 				case 'A':
 				case 'a':
@@ -1849,6 +2281,7 @@
 					if (uploadfile != -1) {
 						statline(mode,
 							 "Already uploading");
+						restorecursor(mode, &win_out);
 						continue;
 					}
 					if ((t =
@@ -1860,12 +2293,14 @@
 					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)
@@ -1963,6 +2398,7 @@
 							upldp = -1;
 							upllen = 0;
 						}
+						restorecursor(mode, &win_out);
 						break;
 					case 'b':
 					case 'B':
@@ -2001,6 +2437,7 @@
 						statline(mode, s);
 					} else
 						statbits(mode, 'L', 1);
+					restorecursor(mode, &win_out);
 					continue;
 				case 'C':
 				case 'c':
@@ -2012,10 +2449,12 @@
 						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--;
@@ -2045,9 +2484,21 @@
 							&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;
 				}
 			}
@@ -2068,8 +2519,10 @@
 				if (uploadfile != -1) {
 					statline(mode,
 						 "Ignored. Type ~s to stop upload");
+					restorecursor(mode, &win_out);
 					continue;
 				}
+
 				convert_lf_cr(buf, bytes);
 
 				while (offset != bytes) {
@@ -2098,6 +2551,7 @@
 				winclose(&wintab);
 				statline(mode,
 					 "Upload complete: 0 bytes");
+				restorecursor(mode, &win_out);
 				continue;
 			}
 			if (upldp == -1) {
@@ -2112,6 +2566,7 @@
 					sprintf(s,
 						"Upload complete: %ld bytes",
 						uplpos);
+					restorecursor(mode, &win_out);
 					statline(mode, s);
 					continue;
 				}
@@ -2124,6 +2579,7 @@
 						"Error reading upload file: upload aborted at %ld bytes",
 						uplpos);
 					statline(mode, s);
+					restorecursor(mode, &win_out);
 					continue;
 				}
 				if (!binup)
@@ -2142,6 +2598,7 @@
 				if (errno != EWOULDBLOCK && errno != EAGAIN) {
 					sprintf(s, "Write error during upload. Connection lost");
 					statline(mode, s);
+					restorecursor(mode, &win_out);
 					perror("write");
 					break;
 			  	}
@@ -2192,18 +2649,27 @@
 	}
 }
 
+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:Stvw:")) != -1) {
+	while ((p = getopt(argc, argv, "b:dhm:p:rs:Stvw:i8")) != -1) {
 		switch (p) {
 		case 'b':
 			if (*optarg != 'e' && *optarg != 'l') {
@@ -2240,6 +2706,7 @@
 			}
 			break;
 		case 'r':
+			COLS = 80; // This is used to format the scrollback buffer, which is stored in raw
 			mode = RAWMODE;
 			break;
 		case 's':
@@ -2274,6 +2741,12 @@
 				}
 			}
 			break;
+		case 'i':
+			encoding = ORIGINALENCODING;
+			break;
+		case '8':
+			encoding = UTF8ENCODING;
+			break;
 		case '?':
 		case ':':
 			usage();
@@ -2283,6 +2756,13 @@
 	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) {
@@ -2331,7 +2811,7 @@
 		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);
