Index: icb.c
===================================================================
--- icb.c	(revision 677a45b0962b882f3296ae4a62c2df400a73c894)
+++ icb.c	(revision 176b6efc59392dc1804fe0b24f4ca85fd8f4080b)
@@ -38,5 +38,4 @@
 int    icb_login(struct icb_session *, char *, char *, char *);
 int    icb_dowho(struct icb_session *, struct icb_group *);
-char  *icb_nextfield(char **, int);
 
 /*
@@ -76,5 +75,7 @@
 {
 	char *msg = is->buffer;
+	int msglen = is->length;
 	unsigned char type;
+	char *wptr = NULL;
 	int res = 0;
 
@@ -88,10 +89,33 @@
 	switch (type) {
 	case ICB_M_LOGIN: {
-		char *nick, *group, *client, *cmd;
-
-		client = icb_nextfield(&msg, 1);
-		nick = icb_nextfield(&msg, 1);
-		group = icb_nextfield(&msg, 1);
-		cmd = icb_nextfield(&msg, 1);
+		char client[ICB_MAXNICKLEN];
+		char nick[ICB_MAXNICKLEN];
+		char group[ICB_MAXGRPLEN];
+		char cmd[ICB_MAXCMDLEN];
+
+		if (icb_token(msg, msglen, &wptr, client, ICB_MAXNICKLEN,
+		    ICB_M_SEP, 1) < 0) {
+			icb_error(is, "Invalid client");
+			icbd_drop(is, NULL);
+			return (1);
+		}
+		if (icb_token(msg, msglen, &wptr, nick, ICB_MAXNICKLEN,
+		    ICB_M_SEP, 1) <= 0) {
+			icb_error(is, "Invalid nick");
+			icbd_drop(is, NULL);
+			return (1);
+		}
+		if (icb_token(msg, msglen, &wptr, group, ICB_MAXGRPLEN,
+		    ICB_M_SEP, 1) < 0) {
+			icb_error(is, "Invalid group");
+			icbd_drop(is, NULL);
+			return (1);
+		}
+		if (icb_token(msg, msglen, &wptr, cmd, ICB_MAXCMDLEN,
+		    ICB_M_SEP, 1) < 0) {
+			icb_error(is, "Invalid command");
+			icbd_drop(is, NULL);
+			return (1);
+		}
 		if (strlen(cmd) > 0 && cmd[0] == 'w') {
 			icb_error(is, "Command not implemented");
@@ -108,15 +132,23 @@
 	}
 	case ICB_M_OPEN: {
-		char *grpmsg;
-
-		grpmsg = icb_nextfield(&msg, 0);
-		icb_groupmsg(is, grpmsg);
+		icb_groupmsg(is, msg);
 		break;
 	}
 	case ICB_M_COMMAND: {
-		char *cmd, *arg;
-
-		cmd = icb_nextfield(&msg, 1);
-		arg = icb_nextfield(&msg, 0);
+		char cmd[ICB_MAXCMDLEN];
+		char arg[ICB_MAXTOPICLEN];
+
+		if (icb_token(msg, msglen, &wptr, cmd, ICB_MAXCMDLEN,
+		    ICB_M_SEP, 1) <= 0) {
+			icb_error(is, "Invalid command");
+			icbd_drop(is, NULL);
+			return (1);
+		}
+		if (icb_token(msg, msglen, &wptr, arg, ICB_MAXTOPICLEN,
+		    ICB_M_SEP, 1) < 0) {
+			icb_error(is, "Invalid argument");
+			icbd_drop(is, NULL);
+			return (1);
+		}
 		icb_command(is, cmd, arg);
 		break;
@@ -286,5 +318,5 @@
 {
 	void (*handler)(struct icb_session *, char *);
-	char command[32]; /* XXX */
+	char command[ICB_MAXCMDLEN];
 
 	icb_vis(command, cmd, sizeof command, VIS_SP);
@@ -586,27 +618,4 @@
 
 /*
- *  icb_nextfield: advances through a given buffer returning pointer to the
- *                 beginning of the icb field or an empty string otherwise;
- *                 cleans up trailing spaces
- */
-char *
-icb_nextfield(char **buf, int notrspace)
-{
-	char *start = *buf;
-	char *end = NULL;
-
-	while (*buf && **buf != '\0' && **buf != ICB_M_SEP)
-		(*buf)++;
-	if (*buf && **buf == ICB_M_SEP) {
-		**buf = '\0';
-		(*buf)++;
-	}
-	end = *buf;
-	while (notrspace && end && end > start && *(--end) == ' ')
-		*end = '\0';
-	return (start);
-}
-
-/*
  *  icb_sendfmt: formats a string and sends it over
  */
@@ -632,10 +641,11 @@
  */
 int
-icb_token(char *buf, int len, char **bufptr, char *dst, int dlen, int sep)
+icb_token(char *buf, int len, char **bufptr, char *dst, int dstlen, int sep,
+    int trim)
 {
 	char *start;
 	int i, ret;
 
-	if (buf == NULL || len <= 0 || dlen <= 0)
+	if (buf == NULL || len <= 0 || dst == NULL || dstlen <= 0)
 		return (0);
 	if (*bufptr == NULL)
@@ -646,7 +656,9 @@
 			/* copy and null terminate the token */
 			ret = strlcpy(dst, start,
-			    MIN(*bufptr - start + 1, dlen));
+			    MIN(*bufptr - start + 1, dstlen));
 			if (**bufptr != '\0')
 				(*bufptr)++;
+			if (ret > 0 && trim)
+				ret = icb_trim(dst, dstlen);
 			return (ret);
 		}
@@ -658,8 +670,32 @@
 	 */
 	if (*bufptr - start > 0) {
-		ret = strlcpy(dst, start, MIN(*bufptr - start + 1, dlen));
+		ret = strlcpy(dst, start, MIN(*bufptr - start + 1, dstlen));
+		if (ret > 0 && trim)
+			ret = icb_trim(dst, dstlen);
 		return (ret);
 	}
 	return (0);
+}
+
+/*
+ *  icb_trim: trims trailing whitespace
+ */
+int
+icb_trim(char *buf, int len)
+{
+	char *p = buf;
+	int i;
+
+	for (i = 0; i < len && *p != '\0'; i++)
+		p++;
+	if (*p == '\0' && p - buf > 0)
+		p--;
+	while (p >= buf && isspace(*p)) {
+		*p = '\0';
+		i--;
+		if (p > buf)
+			p--;
+	}
+	return (i);
 }
 
Index: icb.h
===================================================================
--- icb.h	(revision 677a45b0962b882f3296ae4a62c2df400a73c894)
+++ icb.h	(revision 176b6efc59392dc1804fe0b24f4ca85fd8f4080b)
@@ -30,4 +30,5 @@
 #define ICB_MAXTOPICLEN		 160
 #define ICB_MAXHOSTLEN		 40
+#define ICB_MAXCMDLEN		 32
 #define ICB_MTABLEN		 50 /* XXX */
 
@@ -141,4 +142,5 @@
 		    int, const char *, ...);
 void		icb_who(struct icb_session *, struct icb_group *);
-int		icb_token(char *, int, char **, char *, int, int);
+int		icb_token(char *, int, char **, char *, int, int, int);
+int		icb_trim(char *, int);
 int		icb_vis(char *, const char *, size_t, int);
Index: icbd.c
===================================================================
--- icbd.c	(revision 677a45b0962b882f3296ae4a62c2df400a73c894)
+++ icbd.c	(revision 176b6efc59392dc1804fe0b24f4ca85fd8f4080b)
@@ -130,5 +130,5 @@
 	if (grplist) {
 		while (icb_token(grplist, strlen(grplist), &ptr, group,
-		    ICB_MAXGRPLEN, ',') > 0)
+		    ICB_MAXGRPLEN, ',', 0) > 0)
 			if (icb_addgroup(NULL, group) == NULL)
 				err(EX_UNAVAILABLE, NULL);
