char * formataddr (char *orig, char *str) { register int len; register int isgroup; register char *dst; register char *cp; register char *sp; register struct mailname *mp = NULL; /* if we don't have a buffer yet, get one */ if (bufsiz == 0) { buf = mh_xmalloc (BUFINCR); last_dst = buf; /* XXX */ bufsiz = BUFINCR - 6; /* leave some slop */ bufend = buf + bufsiz; } /* * If "orig" points to our buffer we can just pick up where we * left off. Otherwise we have to copy orig into our buffer. */ if (orig == buf) dst = last_dst; else if (!orig || !*orig) { dst = buf; *dst = '\0'; } else { dst = last_dst; /* XXX */ CHECKMEM (orig); CPY (orig); } /* concatenate all the new addresses onto 'buf' */ for (isgroup = 0; (cp = getname (str)); ) { if ((mp = getm (cp, NULL, 0, fmt_norm, NULL)) == NULL) continue; if (isgroup && (mp->m_gname || !mp->m_ingrp)) { *dst++ = ';'; isgroup = 0; } /* if we get here we're going to add an address */ if (dst != buf) { *dst++ = ','; *dst++ = ' '; } if (mp->m_gname) { CHECKMEM (mp->m_gname); CPY (mp->m_gname); isgroup++; } sp = adrformat (mp); CHECKMEM (sp); CPY (sp); mnfree (mp); } if (isgroup) *dst++ = ';'; *dst = '\0'; last_dst = dst; return (buf); }
static int field_encode_address(const char *name, char **value, int encoding, const char *charset) { int prefixlen = strlen(name) + 2, column = prefixlen, groupflag; int asciichars, specialchars, eightbitchars, reformat = 0, errflag = 0; size_t len; char *mp, *cp = NULL, *output = NULL; char *tmpbuf = NULL; size_t tmpbufsize = 0; struct mailname *mn; char errbuf[BUFSIZ]; /* * Because these are addresses, we need to handle them individually. * * Break them down and process them one by one. This means we have to * rewrite the whole header, but that's unavoidable. */ /* * The output headers always have to start with a space first; this * is just the way the API works right now. */ output = add(" ", output); for (groupflag = 0; (mp = getname(*value)); ) { if ((mn = getm(mp, NULL, 0, errbuf, sizeof(errbuf))) == NULL) { advise(NULL, "%s: %s", errbuf, mp); errflag++; continue; } reformat = 0; /* * We only care if the phrase (m_pers) or any trailing comment * (m_note) have 8-bit characters. If doing q-p, we also need * to encode anything marked as qspecial(). Unquote it first * so the specialchars count is right. */ if (! mn->m_pers) goto check_note; if ((len = strlen(mn->m_pers)) + 1 > tmpbufsize) { tmpbuf = mh_xrealloc(tmpbuf, tmpbufsize = len + 1); } unquote_string(mn->m_pers, tmpbuf); if (scanstring(tmpbuf, &asciichars, &eightbitchars, &specialchars)) { /* * If we have 8-bit characters, encode it. */ if (encoding == CE_UNKNOWN) encoding = pref_encoding(asciichars, specialchars, eightbitchars); /* * This is okay, because the output of unquote_string will be either * equal or shorter than the original. */ strcpy(mn->m_pers, tmpbuf); switch (encoding) { case CE_BASE64: if (field_encode_base64(NULL, &mn->m_pers, charset)) { errflag++; goto out; } break; case CE_QUOTED: if (field_encode_quoted(NULL, &mn->m_pers, charset, asciichars, eightbitchars + specialchars, 1)) { errflag++; goto out; } break; default: advise(NULL, "Internal error: unknown RFC-2047 encoding type"); errflag++; goto out; } reformat++; } check_note: /* * The "note" field is generally a comment at the end of the address, * at least as how it's implemented here. Notes are always surrounded * by parenthesis (since they're comments). Strip them out and * then put them back when we format the final field, but they do * not get encoded. */ if (! mn->m_note) goto do_reformat; if ((len = strlen(mn->m_note)) + 1 > tmpbufsize) { tmpbuf = mh_xrealloc(tmpbuf, tmpbufsize = len + 1); } if (mn->m_note[0] != '(' || mn->m_note[len - 1] != ')') { advise(NULL, "Internal error: Invalid note field \"%s\"", mn->m_note); errflag++; goto out; } strncpy(tmpbuf, mn->m_note + 1, len - 1); tmpbuf[len - 2] = '\0'; if (scanstring(tmpbuf, &asciichars, &eightbitchars, &specialchars)) { /* * If we have 8-bit characters, encode it. */ if (encoding == CE_UNKNOWN) encoding = pref_encoding(asciichars, specialchars, eightbitchars); switch (encoding) { case CE_BASE64: if (field_encode_base64(NULL, &tmpbuf, charset)) { errflag++; goto out; } break; case CE_QUOTED: if (field_encode_quoted(NULL, &tmpbuf, charset, asciichars, eightbitchars + specialchars, 1)) { errflag++; goto out; } break; default: advise(NULL, "Internal error: unknown RFC-2047 encoding type"); errflag++; goto out; } reformat++; /* * Make sure the size of tmpbuf is correct (it always gets * reallocated in the above functions). */ tmpbufsize = strlen(tmpbuf) + 1; /* * Put the note field back surrounded by parenthesis. */ mn->m_note = mh_xrealloc(mn->m_note, tmpbufsize + 2); snprintf(mn->m_note, tmpbufsize + 2, "(%s)", tmpbuf); } do_reformat: /* * So, some explanation is in order. * * We know we need to rewrite at least one address in the header, * otherwise we wouldn't be here. If we had to reformat this * particular address, then run it through adrformat(). Otherwise * we can use m_text directly. */ /* * If we were in a group but are no longer, make sure we add a * semicolon (which needs to be FIRST, as it needs to be at the end * of the last address). */ if (groupflag && ! mn->m_ingrp) { output = add(";", output); column += 1; } groupflag = mn->m_ingrp; if (mn->m_gname) { cp = add(mn->m_gname, NULL); } if (reformat) { cp = add(adrformat(mn), cp); } else { cp = add(mn->m_text, cp); } len = strlen(cp); /* * If we're not at the beginning of the line, add a command and * either a space or a newline. */ if (column != prefixlen) { if (len + column + 2 > OUTPUTLINELEN) { if ((size_t) (prefixlen + 3) < tmpbufsize) tmpbuf = mh_xrealloc(tmpbuf, tmpbufsize = prefixlen + 3); snprintf(tmpbuf, tmpbufsize, ",\n%*s", column = prefixlen, ""); output = add(tmpbuf, output); } else { output = add(", ", output); column += 2; } } /* * Finally add the address */ output = add(cp, output); column += len; free(cp); cp = NULL; } /* * Just in case we're at the end of a list */ if (groupflag) { output = add(";", output); } output = add("\n", output); free(*value); *value = output; output = NULL; out: if (tmpbuf) free(tmpbuf); if (output) free(output); return errflag > 0; }