Index: tin/include/proto.h
diff -c tin/include/proto.h:1.1.1.3 tin/include/proto.h:1.1.1.3.2.1
*** tin/include/proto.h:1.1.1.3	Tue Nov 16 13:34:32 1999
--- tin/include/proto.h	Tue Nov 16 14:07:54 1999
***************
*** 46,51 ****
--- 46,53 ----
  extern void ConvertBody2Printable (char* buf);
  extern void ConvertIso2Asc (char *iso, char *asc, int t);
  extern void ConvertTeX2Iso (char *from, char *to);
+ extern char* ISO2022_substr (const char* src, size_t len, int padf);
+ extern size_t ISO2022_strlen (const char* p);
  
  /* color.c */
  extern void bcol (int color);
Index: tin/src/charset.c
diff -c tin/src/charset.c:1.1.1.2 tin/src/charset.c:1.1.1.2.2.1
*** tin/src/charset.c:1.1.1.2	Tue Nov 16 13:34:37 1999
--- tin/src/charset.c	Tue Nov 16 14:08:11 1999
***************
*** 306,311 ****
--- 306,313 ----
  }
  
  
+ int iso2022_support = 1;
+ 
  /*
   *  Replace all non printable characters by '?'
   */
***************
*** 316,321 ****
--- 318,346 ----
  	unsigned char *c;
  
  	for (c= (unsigned char *)buf; *c; c++) {
+ 		if (iso2022_support) {
+ 			if (c[0] == ESC) {
+ 				if (c[1] == '$' &&
+ 				    (c[2] == '@' || c[2] == 'A' ||
+ 				     c[2] == 'B')) {
+ 					/* fall through */
+ 				} else if (c[1] == '$' && c[2] == '(' &&
+ 					   (0x40 <= c[3] && c[3] <= 0x5f)) {
+ 					/* fall through */
+ 				} else if ((c[1] == '(' || c[1] == '-') &&
+ 					   (0x30 <= c[2] && c[2] <= 0x7e)) {
+ 					/* fall through */
+ 				} else {
+ 					*c = '?';
+ 				}
+ 			} else if (0x20 <= *c && *c <= 0x7e) {
+ 				/* fall through */
+ 			} else if (*c == 0x0e || *c == 0x0f) {
+ 				/* fall through */
+ 			} else {
+ 				*c = '?';
+ 			}
+ 		} else
  		if (!my_isprint(*c))
  			*c = '?';
  	}
***************
*** 332,338 ****
--- 357,829 ----
  	unsigned char *c;
  
  	for (c = (unsigned char *)buf; *c; c++) {
+ 		if (iso2022_support) {
+ 			if (c[0] == ESC) {
+ 				if (c[1] == '$' &&
+ 				    (c[2] == '@' || c[2] == 'A' ||
+ 				     c[2] == 'B')) {
+ 					/* fall through */
+ 				} else if (c[1] == '$' && c[2] == '(' &&
+ 					   (0x40 <= c[3] && c[3] <= 0x5f)) {
+ 					/* fall through */
+ 				} else if ((c[1] == '(' || c[1] == '-') &&
+ 					   (0x30 <= c[2] && c[2] <= 0x7e)) {
+ 					/* fall through */
+ 				} else {
+ 					*c = '?';
+ 				}
+ 			} else if (0x20 <= *c && *c <= 0x7e) {
+ 				/* fall through */
+ 			} else if (*c == 0x0e || *c == 0x0f) {
+ 				/* fall through */
+ 			} else if (*c==8 || *c==9 || *c==12) {
+ 				/* fall through */
+ 			} else {
+ 				*c = '?';
+ 			}
+ 		} else
  		if (!(my_isprint(*c) || *c==8 || *c==9 || *c==12))
  			*c = '?';
  	}
+ }
+ 
+ /*
+  * Mini ISO2022 string library.
+  *   char* ISO2022_substr(const char* str, size_t len, int padf);
+  *   size_t ISO2022_strlen(const char* str);
+  *   char* ISO2022_to_EUCJP(const char* str);
+  *   char* EUCJP_substr(const char* p, size_t length, int padf)
+  *
+  * $Id: tin-1.4.0-ja.diff,v 1.1.1.1 2000/03/08 14:24:19 iyoda Exp $
+  *
+  * Copyright (c) 1998  Kazushi (Jam) Marukawa
+  * All rights reserved.
+  *
+  * Redistribution and use in source and binary forms, with or without
+  * modification, are permitted provided that the following conditions
+  * are met:
+  * 1. Redistributions of source code must retain the above copyright
+  *    notice, this list of conditions and the following disclaimer.
+  * 2. Redistributions in binary form must reproduce the above copyright
+  *    notice in the documentation and/or other materials provided with 
+  *    the distribution.
+  *
+  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY
+  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
+  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE
+  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
+  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 
+  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
+  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 
+  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 
+  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  */
+ 
+ #include <stdio.h>
+ 
+ #define is94(c) ((0x21 <= (c) && (c) <= 0x7e) || \
+ 		 (0xa1 <= (c) && (c) <= 0xfe))
+ #define is96(c) ((0x20 <= (c) && (c) <= 0x7f) || \
+ 		 (0xa0 <= (c) && (c) <= 0xff))
+ #define iseuc(c) (0xa1 <= (c) && (c) <= 0xfe)
+ 
+ /*
+  *  Return len length substring of p.  The ISO 2022's escape sequences
+  *  are parsed.
+  */
+ char* ISO2022_substr(const char* p, size_t length, int padf)
+ {
+     static int bufsize = 0;
+     static char* buffer = NULL;
+     int i = 0;
+     int n = 0;
+     int len = 1;
+     int nonascii = 0;
+ 
+     if (buffer == NULL) {
+ 	bufsize = BUFSIZ;
+ 	buffer = (char*)malloc(bufsize);
+     }
+ 
+     while (*p && n < length) {
+ 	if (*p == ESC) {
+ 	    int escseqlen = 0;
+ 
+ 	    if (p[1] == '$') {
+ 		if (p[2] == '@' || p[2] == 'A' ||
+ 		    p[2] == 'B') {
+ 		    escseqlen = 3;
+ 		    len = 2;
+ 		    nonascii = 1;
+ 		} else if (p[2] == '(') {
+ 		    if (0x40 <= p[3] && p[3] <= 0x5f) {
+ 			escseqlen = 4;
+ 			len = 2;
+ 			nonascii = 1;
+ 		    }
+ 		}
+ 	    } else if (p[1] == '(' || p[1] == '-') {
+ 		if (0x30 <= p[2] && p[2] <= 0x7e) {
+ 		    escseqlen = 3;
+ 		    len = 1;
+ 		    if (p[1] == '(') {
+ 			if (p[2] == 'B')
+ 			    nonascii = 0;
+ 			else
+ 			    nonascii = 1;
+ 		    }
+ 		}
+ 	    }
+ 
+ 	    if (escseqlen) {
+ 		/*
+ 		 * Copy one escape sequence.
+ 		 */
+ 		int j;
+ 
+ 		if (i + escseqlen >= bufsize) {
+ 		    bufsize += BUFSIZ;
+ 		    buffer = realloc(buffer, bufsize);
+ 		}
+ 
+ 		for (j = 0; j < escseqlen; j++)
+ 		    buffer[i++] = *p++;
+ 		continue;
+ 	    }
+ 	    /* fall through */
+ 	} else if (*p == 0x0e || *p == 0x0f) {
+ 	    buffer[i++] = *p++;
+ 	    if (i >= bufsize) {
+ 		bufsize += BUFSIZ;
+ 		buffer = realloc(buffer, bufsize);
+ 	    }
+ 	    continue;
+ 	} else if (len > 1) {
+ 	    /*
+ 	     * Copy one multi bytes character which is len length.
+ 	     */
+ 	    int j;
+ 
+ 	    if (n + len > length)
+ 		break;
+ 
+ 	    if (i + len >= bufsize) {
+ 		bufsize += BUFSIZ;
+ 		buffer = realloc(buffer, bufsize);
+ 	    }
+ 
+ 
+ 	    for (j = 0; j < len && is94(*(unsigned char*)p); j++)
+ 		buffer[i + j] = *p++;
+ 	    if (j < len) {
+ 		/* Discard a wrong multi bytes character. */
+ 		p++;
+ 	    } else {
+ 		i += len;
+ 		n += len;
+ 	    }
+ 	    continue;
+ 	}
+ 	buffer[i++] = *p++;
+ 	n++;
+ 	if (i >= bufsize) {
+ 	    bufsize += BUFSIZ;
+ 	    buffer = realloc(buffer, bufsize);
+ 	}
+     }
+     if (nonascii) {
+ 	/*
+ 	 * Copy a escape sequence to disignate ASCII.
+ 	 */
+ 	int j;
+ 
+ 	if (i + 3 >= bufsize) {
+ 	    bufsize += BUFSIZ;
+ 	    buffer = realloc(buffer, bufsize);
+ 	}
+ 
+ 	buffer[i+0] = ESC;
+ 	buffer[i+1] = '(';
+ 	buffer[i+2] = 'B';
+ 	i += 3;
+     }
+     if (padf) {
+ 	while (n < length) {
+ 	    buffer[i++] = ' ';
+ 	    n++;
+ 	}
+     }
+     buffer[i] = '\0';
+     return buffer;
+ }
+ 
+ /*
+  *  Return the length of strings.  The ISO 2022's escape sequences
+  *  are parsed.
+  */
+ size_t ISO2022_strlen(const char* p)
+ {
+     int n = 0;
+     int len = 1;
+ 
+     while (*p) {
+ 	if (*p == ESC) {
+ 	    if (p[1] == '$') {
+ 		if (p[2] == '@' || p[2] == 'A' ||
+ 		    p[2] == 'B') {
+ 		    p += 3;
+ 		    len = 2;
+ 		    continue;
+ 		} else if (p[2] == '(') {
+ 		    if (0x40 <= p[3] && p[3] <= 0x5f) {
+ 			p += 4;
+ 			len = 2;
+ 			continue;
+ 		    }
+ 		}
+ 	    } else if (p[1] == '(' || p[1] == '-') {
+ 		if (0x30 <= p[2] && p[2] <= 0x7e) {
+ 		    p += 3;
+ 		    len = 1;
+ 		    continue;
+ 		}
+ 	    }
+ 	    /* fall through */
+ 	} else if (*p == 0x0e || *p == 0x0f) {
+ 	    p++;
+ 	    continue;
+ 	} else if (len > 1) {
+ 	    /*
+ 	     * Copy one multi bytes character which is len length.
+ 	     */
+ 	    int j;
+ 
+ 	    for (j = 0; j < len && is94(*(unsigned char*)p); j++)
+ 		p++;
+ 	    if (j < len) {
+ 		/* Discard a wrong multi bytes character. */
+ 		p++;
+ 	    } else {
+ 		n += len;
+ 	    }
+ 	    continue;
+ 	}
+ 	p++;
+ 	n++;
+     }
+     return n;
+ }
+ 
+ /*
+  *  Return an EUC string converted from an ISO2022 string.
+  */
+ char* ISO2022_to_EUCJP(const char* p)
+ {
+     static int bufsize = 0;
+     static char* buffer = NULL;
+     int i = 0;
+     int len = 1;
+     enum { ascii, jisx0208, jisx0201 } charset = ascii;
+ 
+     if (buffer == NULL) {
+ 	bufsize = BUFSIZ;
+ 	buffer = (char*)malloc(bufsize);
+     }
+ 
+     while (*p) {
+ 	if (*p == ESC) {
+ 	    int escseqlen = 0;
+ 	    int ignoreescseqp = 0;
+ 
+ 	    if (p[1] == '$') {
+ 		if (p[2] == '@' || p[2] == 'A' ||
+ 		    p[2] == 'B') {
+ 		    escseqlen = 3;
+ 		    len = 2;
+ 		    if (p[2] == '@' || p[2] == 'B') {
+ 			charset = jisx0208;
+ 			ignoreescseqp = 1;
+ 		    }
+ 		} else if (p[2] == '(') {
+ 		    if (0x40 <= p[3] && p[3] <= 0x5f) {
+ 			escseqlen = 4;
+ 			len = 2;
+ 			if (p[3] == '@' || p[3] == 'B') {
+ 			    charset = jisx0208;
+ 			    ignoreescseqp = 1;
+ 			}
+ 		    }
+ 		}
+ 	    } else if (p[1] == '(' || p[1] == '-') {
+ 		if (0x30 <= p[2] && p[2] <= 0x7e) {
+ 		    escseqlen = 3;
+ 		    len = 1;
+ 		    if (p[1] == '(') {
+ 			if (p[2] == 'B' || p[2] == 'J') {
+ 			    charset = ascii;
+ 			    ignoreescseqp = 1;
+ 			} else if (p[2] == 'I') {
+ 			    charset = jisx0201;
+ 			    ignoreescseqp = 1;
+ 			}
+ 		    }
+ 		}
+ 	    }
+ 
+ 	    if (escseqlen && ignoreescseqp) {
+ 		/*
+ 		 * Ignore one escape sequence.
+ 		 */
+ 		p += escseqlen;
+ 		continue;
+ 	    } else if (escseqlen) {
+ 		/*
+ 		 * Copy one escape sequence.
+ 		 */
+ 		int j;
+ 
+ 		if (i + escseqlen >= bufsize) {
+ 		    bufsize += BUFSIZ;
+ 		    buffer = realloc(buffer, bufsize);
+ 		}
+ 
+ 		/* protect from escape sequence */
+ 		buffer[i++] = '?';
+ 		p++;
+ 		for (j = 1; j < escseqlen; j++)
+ 		    buffer[i++] = *p++;
+ 		continue;
+ 	    }
+ 	    /* fall through */
+ 	} else if (*p == 0x0e || *p == 0x0f) {
+ 	    /* protect from escape sequence */
+ 	    buffer[i++] = '?';
+ 	    if (i >= bufsize) {
+ 		bufsize += BUFSIZ;
+ 		buffer = realloc(buffer, bufsize);
+ 	    }
+ 	    continue;
+ 	} else if (len > 1) {
+ 	    /*
+ 	     * Copy one multi bytes character which is len length.
+ 	     */
+ 	    int j;
+ 
+ 	    if (i + len >= bufsize) {
+ 		bufsize += BUFSIZ;
+ 		buffer = realloc(buffer, bufsize);
+ 	    }
+ 
+ 	    if (charset == jisx0208) {
+ 		for (j = 0; j < len && is94(*(unsigned char*)p); j++)
+ 		    ((unsigned char*)buffer)[i + j] = *p++ | 0x80;
+ 	    } else {
+ 		for (j = 0; j < len && is94(*(unsigned char*)p); j++)
+ 		    buffer[i + j] = *p++;
+ 	    }
+ 	    if (j < len) {
+ 		/* Discard a wrong multi bytes character. */
+ 		p++;
+ 	    } else {
+ 		i += len;
+ 	    }
+ 	    continue;
+ 	} else if (charset == jisx0201) {
+ 	    /*
+ 	     * Copy one jisx0201 character with conversion.
+ 	     */
+ 	    int j;
+ 
+ 	    assert(len == 1);
+ 	    if (i + 1 + len >= bufsize) {
+ 		bufsize += BUFSIZ;
+ 		buffer = realloc(buffer, bufsize);
+ 	    }
+ 
+ 	    ((unsigned char*)buffer)[i + 1] = 0x8e;
+ 	    for (j = 0; j < len && is94(*(unsigned char*)p); j++)
+ 		((unsigned char*)buffer)[i + 1 + j] = *p++ | 0x80;
+ 	    if (j < len) {
+ 		/* Discard a wrong multi bytes character. */
+ 		p++;
+ 	    } else {
+ 		i += 1 + len;
+ 	    }
+ 	    continue;
+ 	}
+ 	buffer[i++] = *p++;
+ 	if (i >= bufsize) {
+ 	    bufsize += BUFSIZ;
+ 	    buffer = realloc(buffer, bufsize);
+ 	}
+     }
+     buffer[i] = '\0';
+     return buffer;
+ }
+ 
+ /*
+  *  Return len length substring of p.  The string is treated
+  *  as EUC Japan.
+  */
+ char* EUCJP_substr(const char* p, size_t length, int padf)
+ {
+     static int bufsize = 0;
+     static char* buffer = NULL;
+     int i = 0;
+     int n = 0;
+ 
+     if (buffer == NULL) {
+ 	bufsize = BUFSIZ;
+ 	buffer = (char*)malloc(bufsize);
+     }
+ 
+     while (*p && n < length) {
+ 	if (*(unsigned char*)p >= 0x80) {
+ 	    int j;
+ 	    int len;
+ 	    if (*(unsigned char*)p == 0x8f) {
+ 		/* for JISX 0212 */
+ 		len = 3;
+ 	    } else {
+ 		/* for JISX 0208 or JISX 0201 Katakana */
+ 		len = 2;
+ 	    }
+ 
+ 	    if (n + len > length)
+ 		break;
+ 
+ 	    if (i + len >= bufsize) {
+ 		bufsize += BUFSIZ;
+ 		buffer = realloc(buffer, bufsize);
+ 	    }
+ 
+ 
+ 	    for (j = 0; j < len && iseuc(*(unsigned char*)p); j++)
+ 		buffer[i + j] = *p++;
+ 	    if (j < len) {
+ 		/* Discard a wrong multi bytes character. */
+ 		p++;
+ 	    } else {
+ 		i += len;
+ 		n += len;
+ 	    }
+ 	    continue;
+ 	}
+ 	buffer[i++] = *p++;
+ 	n++;
+ 	if (i >= bufsize) {
+ 	    bufsize += BUFSIZ;
+ 	    buffer = realloc(buffer, bufsize);
+ 	}
+     }
+     if (padf) {
+ 	while (n < length) {
+ 	    buffer[i++] = ' ';
+ 	    n++;
+ 	}
+     }
+     buffer[i] = '\0';
+     return buffer;
  }
Index: tin/src/filter.c
diff -c tin/src/filter.c:1.1.1.3 tin/src/filter.c:1.1.1.3.2.1
*** tin/src/filter.c:1.1.1.3	Tue Nov 16 13:34:41 1999
--- tin/src/filter.c	Tue Nov 16 14:08:11 1999
***************
*** 727,733 ****
  		show_menu_help (help);
  
  	do {
! 		MoveCursor(x, (int) strlen (prompt));
  		my_fputs (argv[i], stdout);
  		my_flush ();
  		CleartoEOLN ();
--- 727,733 ----
  		show_menu_help (help);
  
  	do {
! 		MoveCursor(x, (int) ISO2022_strlen (prompt));
  		my_fputs (argv[i], stdout);
  		my_flush ();
  		CleartoEOLN ();
***************
*** 827,837 ****
  	len = cCOLS - 30;
  
  	sprintf (text_time, txt_time_default_days, tinrc.filter_days);
! 	sprintf (text_subj, ptr_filter_subj, len, len, art->subject);
! 
! 	strcpy (buf, art->from);
! 
! 	sprintf (text_from, ptr_filter_from, len, len, buf);
  	sprintf (text_msgid, ptr_filter_msgid, len-4, len-4, MSGID(art));
  
  	ClearScreen ();
--- 827,837 ----
  	len = cCOLS - 30;
  
  	sprintf (text_time, txt_time_default_days, tinrc.filter_days);
! 	strcpy(buf, ISO2022_substr(art->subject, len, TRUE));
! 	sprintf (text_subj, ptr_filter_subj, buf);
!   
! 	strcpy(buf, ISO2022_substr(art->from, len, TRUE));
! 	sprintf (text_from, ptr_filter_from, buf);
  	sprintf (text_msgid, ptr_filter_msgid, len-4, len-4, MSGID(art));
  
  	ClearScreen ();
Index: tin/src/group.c
diff -c tin/src/group.c:1.1.1.3 tin/src/group.c:1.1.1.3.2.1
*** tin/src/group.c:1.1.1.3	Tue Nov 16 13:34:42 1999
--- tin/src/group.c	Tue Nov 16 14:08:11 1999
***************
*** 1825,1847 ****
  	if (CURR_GROUP.attribute->show_author != SHOW_FROM_NONE)
  		get_author (FALSE, &arts[j], from, len_from);
  
! 	strncpy(arts_sub, arts[j].subject, len_subj+12);
  	j = INDEX2SNUM(i);
- 	arts_sub[len_subj-12+1] = '\0';
  
  #ifndef USE_CURSES
  	buffer = screen[j].col;
  #endif /* !USE_CURSES */
  	if (tinrc.show_score)
! 		sprintf (buffer, "  %s %s %s%6d %-*.*s%s%-*.*s",
! 			 tin_ltoa(i+1, 4), new_resps, art_cnt, sbuf.score,
! 			 len_subj-12, len_subj-12, arts_sub,
! 			 spaces, len_from, len_from, from);
  	else
! 		sprintf (buffer, "  %s %s %s%-*.*s%s%-*.*s",
! 			 tin_ltoa(i+1, 4), new_resps, art_cnt,
! 			 len_subj-12, len_subj-12, arts_sub,
! 			 spaces, len_from, len_from, from);
  
  	/* protect display from non-displayable characters (e.g., form-feed) */
  	Convert2Printable (buffer);
--- 1825,1844 ----
  	if (CURR_GROUP.attribute->show_author != SHOW_FROM_NONE)
  		get_author (FALSE, &arts[j], from, len_from);
  
! 	strcpy(arts_sub, ISO2022_substr(arts[j].subject, len_subj-12, TRUE));
  	j = INDEX2SNUM(i);
  
  #ifndef USE_CURSES
  	buffer = screen[j].col;
  #endif /* !USE_CURSES */
  	if (tinrc.show_score)
! 		sprintf (buffer, "  %s %s %s%6d %s%s%s",
! 		tin_ltoa(i+1, 4), new_resps, art_cnt, sbuf.score,
! 		arts_sub, spaces, from);
  	else
! 		sprintf (buffer, "  %s %s %s%s%s%s",
! 		tin_ltoa(i+1, 4), new_resps, art_cnt, 
! 		arts_sub, spaces, from);
  
  	/* protect display from non-displayable characters (e.g., form-feed) */
  	Convert2Printable (buffer);
Index: tin/src/lang.c
diff -c tin/src/lang.c:1.1.1.3 tin/src/lang.c:1.1.1.3.2.1
*** tin/src/lang.c:1.1.1.3	Tue Nov 16 13:34:45 1999
--- tin/src/lang.c	Tue Nov 16 14:08:12 1999
***************
*** 948,970 ****
  constext txt_help_filter_time[] = "Expiration time in days for the entered filter. <SPACE> toggles & <CR> sets.";
  constext txt_help_kill_scope[] = "Apply kill only to current group or all groups. <SPACE> toggles & <CR> sets.";
  constext txt_help_select_scope[] = "Apply select to current group or all groups. <SPACE> toggles & <CR> sets.";
! constext txt_kill_from[] = "Kill From:     [%-*.*s] (y/n): ";
  constext txt_kill_lines[] = "Kill Lines: (</>num): ";
  constext txt_kill_menu[] = "Kill Article Menu";
  constext txt_kill_msgid[] = "Kill Msg-Id:   [%-*.*s] (f/l/o/n): ";
  constext txt_kill_scope[] = "Kill pattern scope  : ";
! constext txt_kill_subj[] = "Kill Subject:  [%-*.*s] (y/n): ";
  constext txt_kill_text[] = "Kill text pattern   : ";
  constext txt_kill_time[] = "Kill time in days   : ";
  constext txt_msgid_line_only[] = "Message-Id: line";
  constext txt_quit_edit_save_kill[] = "q)uit e)dit s)ave kill description: ";
  constext txt_quit_edit_save_select[] = "q)uit e)dit s)ave select description: ";
! constext txt_select_from[] = "Select From    [%-*.*s] (y/n): ";
  constext txt_select_lines[] = "Select Lines: (</>num): ";
  constext txt_select_menu[] = "Auto-select Article Menu";
  constext txt_select_msgid[] = "Select Msg-Id  [%-*.*s] (f/l/o/n): ";
  constext txt_select_scope[] = "Select pattern scope: ";
! constext txt_select_subj[] = "Select Subject [%-*.*s] (y/n): ";
  constext txt_select_text[] = "Select text pattern : ";
  constext txt_select_time[] = "Select time in days   : ";
  constext txt_subj_line_only[] = "Subject: line (ignore case)     ";
--- 948,970 ----
  constext txt_help_filter_time[] = "Expiration time in days for the entered filter. <SPACE> toggles & <CR> sets.";
  constext txt_help_kill_scope[] = "Apply kill only to current group or all groups. <SPACE> toggles & <CR> sets.";
  constext txt_help_select_scope[] = "Apply select to current group or all groups. <SPACE> toggles & <CR> sets.";
! constext txt_kill_from[] = "Kill From:     [%s] (y/n): ";
  constext txt_kill_lines[] = "Kill Lines: (</>num): ";
  constext txt_kill_menu[] = "Kill Article Menu";
  constext txt_kill_msgid[] = "Kill Msg-Id:   [%-*.*s] (f/l/o/n): ";
  constext txt_kill_scope[] = "Kill pattern scope  : ";
! constext txt_kill_subj[] = "Kill Subject:  [%s] (y/n): ";
  constext txt_kill_text[] = "Kill text pattern   : ";
  constext txt_kill_time[] = "Kill time in days   : ";
  constext txt_msgid_line_only[] = "Message-Id: line";
  constext txt_quit_edit_save_kill[] = "q)uit e)dit s)ave kill description: ";
  constext txt_quit_edit_save_select[] = "q)uit e)dit s)ave select description: ";
! constext txt_select_from[] = "Select From    [%s] (y/n): ";
  constext txt_select_lines[] = "Select Lines: (</>num): ";
  constext txt_select_menu[] = "Auto-select Article Menu";
  constext txt_select_msgid[] = "Select Msg-Id  [%-*.*s] (f/l/o/n): ";
  constext txt_select_scope[] = "Select pattern scope: ";
! constext txt_select_subj[] = "Select Subject [%s] (y/n): ";
  constext txt_select_text[] = "Select text pattern : ";
  constext txt_select_time[] = "Select time in days   : ";
  constext txt_subj_line_only[] = "Subject: line (ignore case)     ";
Index: tin/src/memory.c
diff -c tin/src/memory.c:1.1.1.3 tin/src/memory.c:1.1.1.3.2.1
*** tin/src/memory.c:1.1.1.3	Tue Nov 16 13:34:47 1999
--- tin/src/memory.c	Tue Nov 16 14:08:12 1999
***************
*** 146,153 ****
  		screen = (struct t_screen *) my_malloc (
  			sizeof (struct t_screen) * cLINES+1);
  
! 		for (i = 0; i < cLINES; i++)
! 			screen[i].col = (char *) my_malloc ((size_t)(cCOLS+2));
  
  	} else {
  		if (screen != (struct t_screen *) 0) {
--- 146,153 ----
  		screen = (struct t_screen *) my_malloc (
  			sizeof (struct t_screen) * cLINES+1);
  
! 		for (i=0 ; i < cLINES ; i++)
! 			screen[i].col = (char *) my_malloc ((size_t)(cCOLS*2));
  
  	} else {
  		if (screen != (struct t_screen *) 0) {
Index: tin/src/misc.c
diff -c tin/src/misc.c:1.1.1.3 tin/src/misc.c:1.1.1.3.2.1
*** tin/src/misc.c:1.1.1.3	Tue Nov 16 13:34:48 1999
--- tin/src/misc.c	Tue Nov 16 14:08:13 1999
***************
*** 1248,1272 ****
  			str[0] = '\0';
  			break;
  		case SHOW_FROM_ADDR:
! 			strncpy (str, art->from, len);
  			break;
  		case SHOW_FROM_NAME:
  			strncpy (str, (art->name ? art->name : art->from), len);
  			break;
  		case SHOW_FROM_BOTH:
  			if (art->name) {
  				char buff[LEN];			/* TODO eliminate this with snprintf() */
  
  				sprintf (buff, "%s <%s>", art->name, art->from);
! 				strncpy (str, buff, len);
  			} else
! 				strncpy (str, art->from, len);
  			break;
  		default:
  			break;
  	}
- 
- 	*(str + len) = '\0';				/* NULL terminate */
  }
  
  
--- 1248,1274 ----
  			str[0] = '\0';
  			break;
  		case SHOW_FROM_ADDR:
! 			strcpy (str, ISO2022_substr(art->from, len, FALSE));
  			break;
  		case SHOW_FROM_NAME:
  			strncpy (str, (art->name ? art->name : art->from), len);
+ 			strcpy (str, ISO2022_substr((art->name ? art->name :
+ 						art->from), len, FALSE));
  			break;
  		case SHOW_FROM_BOTH:
  			if (art->name) {
  				char buff[LEN];			/* TODO eliminate this with snprintf() */
  
  				sprintf (buff, "%s <%s>", art->name, art->from);
! 				strcpy (str, ISO2022_substr(buff, len, FALSE));
  			} else
! 				strcpy (str, ISO2022_substr(art->from, len,
! 							FALSE));
  			break;
  		default:
+ 			str[0] = '\0';
  			break;
  	}
  }
  
  
Index: tin/src/page.c
diff -c tin/src/page.c:1.1.1.3 tin/src/page.c:1.1.1.3.2.1
*** tin/src/page.c:1.1.1.3	Tue Nov 16 13:34:50 1999
--- tin/src/page.c	Tue Nov 16 14:08:13 1999
***************
*** 814,819 ****
--- 814,821 ----
  			while (i++ < j)
  				*q++ = ' ';
  
+ 		} else if (((*p) & 0xFF) == ESC) {
+ 			*q++ = *p;
  		} else if (((*p) & 0xFF) < ' ') {
  			*q++ = '^';
  			*q++ = ((*p) & 0xFF) + '@';
***************
*** 1028,1033 ****
--- 1030,1041 ----
  
  	} /* loop show_note_page */
  
+ #ifdef HAVE_COLOR
+ 	print_color ("\033(B ", below_sig);
+ #else
+ 	my_printf ("%s" cCRLF, "\033(B ");
+ #endif
+ 
  	if (!tinrc.show_last_line_prev_page)
  		note_mark[++note_page] = ftell (note_fp);
  	else
***************
*** 1181,1187 ****
  		char ftbuf[HEADER_LEN]; /* FTN-To aka X-Comment-To */
  		my_fputs (buf, stdout);
  		strip_address(note_h.ftnto, ftbuf);
! 		ftbuf[19] = '\0';
  		Convert2Printable (ftbuf);
  		StartInverse ();
  		my_fputs (ftbuf, stdout);
--- 1189,1195 ----
  		char ftbuf[HEADER_LEN]; /* FTN-To aka X-Comment-To */
  		my_fputs (buf, stdout);
  		strip_address(note_h.ftnto, ftbuf);
! 		strcpy(ftbuf, ISO2022_substr(ftbuf, 19, FALSE));
  		Convert2Printable (ftbuf);
  		StartInverse ();
  		my_fputs (ftbuf, stdout);
***************
*** 1223,1231 ****
  
  	strncpy (buf, (*note_h.subj ? note_h.subj : arts[respnum].subject), HEADER_LEN - 1);
  
! 	buf[RIGHT_POS - 5 - n] = '\0';
  
! 	pos = ((cCOLS - (int) strlen (buf)) / 2) - 2;
  
  	MoveCursor (1, ((pos > n) ? pos : n));
  
--- 1231,1239 ----
  
  	strncpy (buf, (*note_h.subj ? note_h.subj : arts[respnum].subject), HEADER_LEN - 1);
  
! 	strcpy (buf, ISO2022_substr(buf, RIGHT_POS - 5 - n, FALSE));
  
! 	pos = ((cCOLS - (int) ISO2022_strlen (buf)) / 2) - 2;
  
  	MoveCursor (1, ((pos > n) ? pos : n));
  
***************
*** 1259,1277 ****
  	if (arts[respnum].name)
  		sprintf (buf, "%s <%s>", arts[respnum].name, arts[respnum].from);
  	else
! 		strncpy (buf, arts[respnum].from, cCOLS-1);
! 	buf[cCOLS-1] = '\0';
  
  	if (*note_h.org) {
  		sprintf (tmp, txt_at_s, note_h.org);
  		tmp[sizeof(tmp)-1] = '\0';
  
! 		if ((int) strlen (buf) + (int) strlen (tmp) >= cCOLS -1) {
! 			strncat (buf, tmp, cCOLS - 1 - strlen(buf));
! 			buf[cCOLS-1] = '\0';
  		} else {
! 			pos = cCOLS - 1 - (int) strlen(tmp);
! 			for (i = strlen(buf); i < pos; i++)
  				buf[i] = ' ';
  			buf[i] = '\0';
  			strcat (buf, tmp);
--- 1267,1289 ----
  	if (arts[respnum].name)
  		sprintf (buf, "%s <%s>", arts[respnum].name, arts[respnum].from);
  	else
! 		strcpy (buf, arts[respnum].from);
! 	strcpy(buf, ISO2022_substr(buf, cCOLS-1, FALSE));
  
  	if (*note_h.org) {
+ 		int buflen = ISO2022_strlen(buf);
+ 		int tmplen;
+ 
  		sprintf (tmp, txt_at_s, note_h.org);
  		tmp[sizeof(tmp)-1] = '\0';
+ 		tmplen = ISO2022_strlen(tmp);
  
! 		if (buflen + tmplen >= cCOLS -1) {
! 			strcat(buf, ISO2022_substr(tmp, cCOLS-1-buflen, FALSE));
  		} else {
! 			int j;
! 			pos = cCOLS - 1 - tmplen;
! 			for (i = strlen(buf), j = 0; j < pos - buflen; i++, j++)
  				buf[i] = ' ';
  			buf[i] = '\0';
  			strcat (buf, tmp);
***************
*** 1338,1344 ****
  	strip_line (buf);
  
  	if (cCOLS)
! 		buf[cCOLS-1] = '\0';
  
  	Convert2Printable (buf);
  
--- 1350,1356 ----
  	strip_line (buf);
  
  	if (cCOLS)
! 		strcpy(buf, ISO2022_substr(buf, cCOLS-1, FALSE));
  
  	Convert2Printable (buf);
  
***************
*** 1433,1439 ****
  		}
  
  		for (ptr = buf; *ptr && ((*ptr != '\n') || (ptr[1] != '\0')); ptr++) {
! 			if ((((*ptr) & 0xFF) < ' ') && (*ptr != '\n') && ((*ptr != '\t') || (!is_summary)))
  				*ptr = ' ';
  		}
  		*ptr = '\0';
--- 1445,1454 ----
  		}
  
  		for (ptr = buf; *ptr && ((*ptr != '\n') || (ptr[1] != '\0')); ptr++) {
! 			if ((((*ptr) & 0xFF) < ' ')
! 				&& (*ptr != ESC)
! 				&& (*ptr != '\n')
! 				&& ((*ptr != '\t') || (!is_summary)))
  				*ptr = ' ';
  		}
  		*ptr = '\0';
Index: tin/src/post.c
diff -c tin/src/post.c:1.1.1.3 tin/src/post.c:1.1.1.3.2.1
*** tin/src/post.c:1.1.1.3	Tue Nov 16 13:34:51 1999
--- tin/src/post.c	Tue Nov 16 14:08:14 1999
***************
*** 608,616 ****
  			errors++;
  		}
  		if (cp - line == 7 && !strncasecmp (line, "Subject", 7)) {
! 			found_subject_lines++;
! 			strncpy (subject, cp+2, cCOLS-6);
! 			subject[cCOLS-6] = '\0';
  		}
  
  #ifndef FORGERY
--- 608,615 ----
  			errors++;
  		}
  		if (cp - line == 7 && !strncasecmp (line, "Subject", 7)) {
! 			found_subject_lines = TRUE;
! 			strcpy (subject, ISO2022_substr(cp+2, cCOLS-6, FALSE));
  		}
  
  #ifndef FORGERY
***************
*** 1326,1334 ****
  	/* TODO rework without tmp */
  	/* combine with other code in tin that does the ... truncation ? */
  	/* Get subject for posting article - Limit the display if needed */
! 	if (strlen(tinrc.default_post_subject) > DISPLAY_SUBJECT_LEN) {
! 		strncpy(tmp, tinrc.default_post_subject, DISPLAY_SUBJECT_LEN);
! 		tmp[DISPLAY_SUBJECT_LEN] = '\0';
  		strcat(tmp, " ...");
  	} else
  		strncpy(tmp, tinrc.default_post_subject, sizeof(tmp));
--- 1325,1332 ----
  	/* TODO rework without tmp */
  	/* combine with other code in tin that does the ... truncation ? */
  	/* Get subject for posting article - Limit the display if needed */
! 	if (ISO2022_strlen(tinrc.default_post_subject) > DISPLAY_SUBJECT_LEN) {
! 		strcpy(tmp, ISO2022_substr(tinrc.default_post_subject, DISPLAY_SUBJECT_LEN, FALSE));
  		strcat(tmp, " ...");
  	} else
  		strncpy(tmp, tinrc.default_post_subject, sizeof(tmp));
Index: tin/src/screen.c
diff -c tin/src/screen.c:1.1.1.3 tin/src/screen.c:1.1.1.3.2.1
*** tin/src/screen.c:1.1.1.3	Tue Nov 16 13:34:55 1999
--- tin/src/screen.c	Tue Nov 16 14:08:14 1999
***************
*** 195,202 ****
  	STRCPY(buffer, str);
  
  	if (!cmd_line) {
! 		if (cCOLS >= (int) strlen (str))
! 			pos = (cCOLS - (int) strlen (str)) / 2;
  		else
  			pos = 1;
  
--- 195,203 ----
  	STRCPY(buffer, str);
  
  	if (!cmd_line) {
! 		int len = ISO2022_strlen(str);
! 		if (cCOLS >= len)
! 			pos = (cCOLS - len) / 2;
  		else
  			pos = 1;
  
***************
*** 210,218 ****
  	/* protect terminal... */
  	Convert2Printable (buffer);
  
! 	if ((int) strlen (buffer) >= cCOLS) {
  		char buf[256];
! 		sprintf(buf, "%-.*s%s", cCOLS-6, buffer, " ...");
  		my_fputs (buf, stdout);
  	} else
  		my_fputs (buffer, stdout);
--- 211,220 ----
  	/* protect terminal... */
  	Convert2Printable (buffer);
  
! 	if ((int) ISO2022_strlen (buffer) >= cCOLS) {
  		char buf[256];
! 		strcpy(buf, ISO2022_substr(buffer, cCOLS-6, FALSE));
! 		strcat(buf, " ...");
  		my_fputs (buf, stdout);
  	} else
  		my_fputs (buffer, stdout);
Index: tin/src/select.c
diff -c tin/src/select.c:1.1.1.3 tin/src/select.c:1.1.1.3.2.1
*** tin/src/select.c:1.1.1.3	Tue Nov 16 13:34:56 1999
--- tin/src/select.c	Tue Nov 16 14:08:14 1999
***************
*** 706,720 ****
  		if (blank_len > 254)
  			blank_len = 254;
  		/* copy of active[n].description fix some malloc bugs kg */
! 		strncpy(group_descript, active[n].description ? active[n].description : " ", blank_len);
! 		group_descript[blank_len] = '\0';
  
  		if (show_description) {
  			if (active[n].description)
! 				sprintf (sptr, "  %c %s %s  %-*.*s  %-*.*s" cCRLF,
  				         subs, tin_ltoa(i+1, 4), tmp,
  				         groupname_len, groupname_len, active_name,
! 				         blank_len, blank_len, group_descript);
  			else
  				sprintf (sptr, "  %c %s %s  %-*.*s  " cCRLF,
  				         subs, tin_ltoa(i+1, 4), tmp,
--- 706,719 ----
  		if (blank_len > 254)
  			blank_len = 254;
  		/* copy of active[n].description fix some malloc bugs kg */
! 		strcpy(group_descript, ISO2022_substr(active[n].description ? active[n].description : " ", blank_len, TRUE));
  
  		if (show_description) {
  			if (active[n].description)
! 				sprintf (sptr, "  %c %s %s  %-*.*s  %s" cCRLF,
  				         subs, tin_ltoa(i+1, 4), tmp,
  				         groupname_len, groupname_len, active_name,
! 				         group_descript);
  			else
  				sprintf (sptr, "  %c %s %s  %-*.*s  " cCRLF,
  				         subs, tin_ltoa(i+1, 4), tmp,
Index: tin/src/thread.c
diff -c tin/src/thread.c:1.1.1.3 tin/src/thread.c:1.1.1.3.2.1
*** tin/src/thread.c:1.1.1.3	Tue Nov 16 13:35:00 1999
--- tin/src/thread.c	Tue Nov 16 14:08:15 1999
***************
*** 192,198 ****
  			for (ptr = art->refptr->parent; ptr && EXPIRED (ptr); ptr = ptr->parent)
  				;
  			if (!(ptr && arts[ptr->article].subject == art->subject))
! 				strncat(buff, art->subject, gap);
  
  			buff[len+gap] = '\0';	/* Just in case */
  		}
--- 192,198 ----
  			for (ptr = art->refptr->parent; ptr && EXPIRED (ptr); ptr = ptr->parent)
  				;
  			if (!(ptr && arts[ptr->article].subject == art->subject))
! 				strcat(buff, ISO2022_substr(art->subject, gap, FALSE));
  
  			buff[len+gap] = '\0';	/* Just in case */
  		}
***************
*** 201,213 ****
  		 * If we need to show the author, pad out to the start of the author field,
  		 */
  		if (len_from) {
! 			for (gap = strlen(buff); gap < (cCOLS - len_from); gap++)
! 				buff[gap] = ' ';
  
  			/*
  			 * Now add the author info at the end. This will be 0 terminated
  			 */
! 			get_author (TRUE, art, buff + cCOLS - len_from, len_from);
  		}
  
  	} else /* Add the author info. This is always shown if subject is not */
--- 201,212 ----
  		 * If we need to show the author, pad out to the start of the author field,
  		 */
  		if (len_from) {
! 			strcpy(buff, ISO2022_substr(buff, cCOLS - len_from, TRUE));
  
  			/*
  			 * Now add the author info at the end. This will be 0 terminated
  			 */
! 			get_author (TRUE, art, buff + strlen(buff), len_from);
  		}
  
  	} else /* Add the author info. This is always shown if subject is not */
