PRIVATE char *intlmime_decode_qp(char *in) { int i = 0, length; char token[3]; char *out, *dest = 0; out = dest = (char *)XP_ALLOC(strlen(in)+1); if (dest == NULL) return NULL; memset(out, 0, strlen(in)+1); length = strlen(in); while (length > 0 || i != 0) { while (i < 3 && length > 0) { token [i++] = *in; in++; length--; } if (i < 3) { /* Didn't get enough for a complete token. If it might be a token, unread it. Otherwise, just dump it. */ strncpy (out, token, i); break; } i = 0; if (token [0] == '=') { unsigned char c = 0; if (token[1] >= '0' && token[1] <= '9') c = token[1] - '0'; else if (token[1] >= 'A' && token[1] <= 'F') c = token[1] - ('A' - 10); else if (token[1] >= 'a' && token[1] <= 'f') c = token[1] - ('a' - 10); else if (token[1] == CR || token[1] == LF) { /* =\n means ignore the newline. */ if (token[1] == CR && token[2] == LF) ; /* swallow all three chars */ else { in--; /* put the third char back */ length++; } continue; } else { /* = followed by something other than hex or newline - pass it through unaltered, I guess. (But, if this bogus token happened to occur over a buffer boundary, we can't do this, since we don't have space for it. Oh well. Forget it.) */ if (in > out) *out++ = token[0]; if (in > out) *out++ = token[1]; if (in > out) *out++ = token[2]; continue; } /* Second hex digit */ c = (c << 4); if (token[2] >= '0' && token[2] <= '9') c += token[2] - '0'; else if (token[2] >= 'A' && token[2] <= 'F') c += token[2] - ('A' - 10); else if (token[2] >= 'a' && token[2] <= 'f') c += token[2] - ('a' - 10); else { /* We got =xy where "x" was hex and "y" was not, so treat that as a literal "=", x, and y. (But, if this bogus token happened to occur over a buffer boundary, we can't do this, since we don't have space for it. Oh well. Forget it.) */ if (in > out) *out++ = token[0]; if (in > out) *out++ = token[1]; if (in > out) *out++ = token[2]; continue; } *out++ = (char) c; } else { *out++ = token [0]; token[0] = token[1]; token[1] = token[2]; i = 2; } } /* take care of special underscore case */ for (out = dest; *out; out++) if (*out == '_') *out = ' '; return dest; }