Index: src/lib/print.c
===================================================================
RCS file: /source/radiusd/src/lib/print.c,v
retrieving revision 1.49
diff -u -r1.49 print.c
--- src/lib/print.c	29 May 2007 14:33:26 -0000	1.49
+++ src/lib/print.c	28 Aug 2007 08:47:28 -0000
@@ -28,28 +28,122 @@
 #include	<ctype.h>
 
 /*
- *	Convert a string to something printable.
- *	The output string has to be _at least_ 4x the size
- *	of the input string!
+ *	Checks for utf-8,
+ *	taken from:
+ *
+ *  http://www.w3.org/International/questions/qa-forms-utf-8
+ */
+static int utf8_char(uint8_t *str)
+{
+	if (*str < 0x20) return 0;
+
+	if (*str <= 0x7e) return 1; /* 1 */
+
+	if (*str <= 0xc1) return 0;
+
+	if ((str[0] >= 0xc2) &&	/* 2 */
+	    (str[0] <= 0xdf) &&
+	    (str[1] >= 0x80) &&
+	    (str[1] <= 0xbf)) {
+		return 2;
+	}
+
+	if ((str[0] == 0xe0) &&	/* 3 */
+	    (str[1] >= 0xa0) &&
+	    (str[1] <= 0xbf) &&
+	    (str[2] >= 0x80) &&
+	    (str[2] <= 0xbf)) {
+		return 3;
+	}
+
+	if ((str[0] >= 0xe1) &&	/* 4a */
+	    (str[0] <= 0xec) &&
+	    (str[1] >= 0x80) &&
+	    (str[1] <= 0xbf) &&
+	    (str[2] >= 0x80) &&
+	    (str[2] <= 0xbf)) {
+		return 3;
+	}
+
+	if ((str[0] >= 0xee) &&	/* 4b */
+	    (str[0] <= 0xef) &&
+	    (str[1] >= 0x80) &&
+	    (str[1] <= 0xbf) &&
+	    (str[2] >= 0x80) &&
+	    (str[2] <= 0xbf)) {
+		return 3;
+	}
+
+	if ((str[0] == 0xed) &&	/* 5 */
+	    (str[1] >= 0x80) &&
+	    (str[1] <= 0x9f) &&
+	    (str[2] >= 0x80) &&
+	    (str[2] <= 0xbf)) {
+		return 3;
+	}
+
+	if ((str[0] == 0xf0) &&	/* 6 */
+	    (str[1] >= 0x90) &&
+	    (str[1] <= 0xbf) &&
+	    (str[2] >= 0x80) &&
+	    (str[2] <= 0xbf) &&
+	    (str[3] >= 0x80) &&
+	    (str[3] <= 0xbf)) {
+		return 4;
+	}
+
+	if ((str[0] >= 0xf1) &&	/* 6 */
+	    (str[1] <= 0xf3) &&
+	    (str[1] >= 0x80) &&
+	    (str[1] <= 0xbf) &&
+	    (str[2] >= 0x80) &&
+	    (str[2] <= 0xbf) &&
+	    (str[3] >= 0x80) &&
+	    (str[3] <= 0xbf)) {
+		return 4;
+	}
+
+
+	if ((str[0] == 0xf4) &&	/* 7 */
+	    (str[1] >= 0x80) &&
+	    (str[1] <= 0x8f) &&
+	    (str[2] >= 0x80) &&
+	    (str[2] <= 0xbf) &&
+	    (str[3] >= 0x80) &&
+	    (str[3] <= 0xbf)) {
+		return 4;
+	}
+
+	/*
+	 *	Invalid UTF-8 Character
+	 */
+	return 0;
+}
+
+/*
+ *	Convert a string to something printable.  The output string
+ *	has to be larger than the input string by at least 5 bytes.
+ *	If not, the output is silently truncated...
  */
 void librad_safeprint(char *in, int inlen, char *out, int outlen)
 {
 	unsigned char	*str = (unsigned char *)in;
 	int		done = 0;
 	int		sp = 0;
+	int		utf8 = 0;
 
 	if (inlen < 0) inlen = strlen(in);
 
-	while (inlen-- > 0 && (done + 3) < outlen) {
+	/*
+	 *	
+	 */
+	while ((inlen > 0) && (done + 5) < outlen) {
 		/*
 		 *	Hack: never print trailing zero.
 		 *	Some clients send strings with an off-by-one
 		 *	length (confused with strings in C).
 		 */
-		if (inlen == 0 && *str == 0)
-			break;
-
-		sp = 0;
+		if ((inlen == 0) && (*str == 0)) break;
 
 		switch (*str) {
 			case '\\':
@@ -68,24 +162,37 @@
 				sp = '"';
 				break;
 			default:
-			  if (*str < 32 || (*str >= 128)){
-					snprintf(out, outlen, "\\%03o", *str);
-					done += 4;
-					out  += 4;
-					outlen -= 4;
-				} else {
-					*out++ = *str;
-					outlen--;
-					done++;
-				}
+				sp = 0;
+				break;
 		}
+
 		if (sp) {
 			*out++ = '\\';
 			*out++ = sp;
 			outlen -= 2;
 			done += 2;
+			str++;
+			inlen--;
+			continue;
+		}
+
+		utf8 = utf8_char((uint8_t *)str);
+		if (!utf8) {
+			snprintf(out, outlen, "\\%03o", *str);
+			done += 4;
+			out  += 4;
+			outlen -= 4;
+			str++;
+			inlen--;
+			continue;
 		}
-		str++;
+
+		do {
+			*out++ = *str++;
+			outlen--;
+			inlen--;
+			done++;
+		} while (--utf8 > 0);
 	}
 	*out = 0;
 }
@@ -122,10 +229,6 @@
 						 vp->length, buf + 1, sizeof(buf) - 2);
 				strcat(buf, "\"");
 
-			} else if (delimitst < 0) {
-				strlcpy(out, vp->vp_strvalue, outlen);
-				return strlen(out);
-
 			} else {
 				/* Non-tagged attribute: no delimiter */
 				librad_safeprint((char *)vp->vp_strvalue,
@@ -137,20 +240,21 @@
 		        if ( vp->flags.has_tag ) {
 			        /* Attribute value has a tag, need to ignore it */
 			        if ((v = dict_valbyattr(vp->attribute, (vp->vp_integer & 0xffffff)))
-				    != NULL)
+				    != NULL) {
 				        a = v->name;
+				}
 				else {
 				        snprintf(buf, sizeof(buf), "%u", (vp->vp_integer & 0xffffff));
 				        a = buf;
 				}
 			} else {
-			case PW_TYPE_BYTE:
-			case PW_TYPE_SHORT:
+		case PW_TYPE_BYTE:
+		case PW_TYPE_SHORT:
 			        /* Normal, non-tagged attribute */
 			        if ((v = dict_valbyattr(vp->attribute, vp->vp_integer))
-				    != NULL)
+				    != NULL) {
 				        a = v->name;
-				else {
+				}else {
 				        snprintf(buf, sizeof(buf), "%u", vp->vp_integer);
 					a = buf;
 				}
