#include <sys_defs.h>
#include <string.h>
#include <ctype.h>
#include <vstring.h>
#include "quote_822_local.h"
#define YES 1
#define NO 0
static int is_822_dot_string(const char *local_part, const char *end, int flags)
{
const char *cp;
int ch;
if (local_part == end || local_part[0] == 0 || local_part[0] == '.')
return (NO);
for (cp = local_part; cp < end && (ch = *(unsigned char *) cp) != 0; cp++) {
if (ch == '.' && (cp + 1) < end && cp[1] == '.')
return (NO);
if (ch > 127 && !(flags & QUOTE_FLAG_8BITCLEAN))
return (NO);
if (ch == ' ')
return (NO);
if (ISCNTRL(ch))
return (NO);
if (ch == '(' || ch == ')'
|| ch == '<' || ch == '>'
|| (ch == '@' && !(flags & QUOTE_FLAG_EXPOSE_AT)) || ch == ','
|| ch == ';' || ch == ':'
|| ch == '\\' || ch == '"'
|| ch == '[' || ch == ']')
return (NO);
}
if (cp[-1] == '.')
return (NO);
return (YES);
}
static VSTRING *make_822_quoted_string(VSTRING *dst, const char *local_part,
const char *end, int flags)
{
const char *cp;
int ch;
VSTRING_ADDCH(dst, '"');
for (cp = local_part; cp < end && (ch = *(unsigned char *) cp) != 0; cp++) {
if ((ch > 127 && !(flags & QUOTE_FLAG_8BITCLEAN))
|| ch == '"' || ch == '\\' || ch == '\r')
VSTRING_ADDCH(dst, '\\');
VSTRING_ADDCH(dst, ch);
}
VSTRING_ADDCH(dst, '"');
return (dst);
}
VSTRING *quote_822_local_flags(VSTRING *dst, const char *mbox, int flags)
{
const char *start;
const char *end;
const char *colon;
if (mbox[0] == '@' && (colon = strchr(mbox, ':')) != 0)
start = colon + 1;
else
start = mbox;
if ((flags & QUOTE_FLAG_BARE_LOCALPART) != 0
|| (end = strrchr(start, '@')) == 0)
end = start + strlen(start);
if ((flags & QUOTE_FLAG_APPEND) == 0)
VSTRING_RESET(dst);
if (is_822_dot_string(start, end, flags)) {
return (vstring_strcat(dst, mbox));
} else {
vstring_strncat(dst, mbox, start - mbox);
make_822_quoted_string(dst, start, end, flags & QUOTE_FLAG_8BITCLEAN);
return (vstring_strcat(dst, end));
}
}
VSTRING *unquote_822_local(VSTRING *dst, const char *mbox)
{
const char *start;
const char *colon;
const char *cp;
int in_quote = 0;
const char *bare_at_src;
int bare_at_dst_pos = -1;
if (mbox[0] == '@' && (colon = strchr(mbox, ':')) != 0) {
start = colon + 1;
vstring_strncpy(dst, mbox, start - mbox);
} else {
start = mbox;
VSTRING_RESET(dst);
}
for (cp = start; *cp; cp++) {
if (*cp == '"') {
in_quote = !in_quote;
continue;
} else if (*cp == '@') {
if (!in_quote) {
bare_at_dst_pos = VSTRING_LEN(dst);
bare_at_src = cp;
}
} else if (*cp == '\\') {
if (cp[1] == 0)
continue;
cp++;
}
VSTRING_ADDCH(dst, *cp);
}
if (bare_at_dst_pos >= 0) {
vstring_truncate(dst, bare_at_dst_pos);
vstring_strcat(dst, bare_at_src);
} else
VSTRING_TERMINATE(dst);
return (dst);
}
#ifdef TEST
#include <ctype.h>
#include <string.h>
#include <msg.h>
#include <name_mask.h>
#include <stringops.h>
#include <vstream.h>
#include <vstring_vstream.h>
#define STR vstring_str
int main(int unused_argc, char **argv)
{
VSTRING *in = vstring_alloc(100);
VSTRING *out = vstring_alloc(100);
char *cmd;
char *bp;
int flags;
while (vstring_fgets_nonl(in, VSTREAM_IN)) {
bp = STR(in);
if ((cmd = mystrtok(&bp, CHARS_SPACE)) != 0) {
while (ISSPACE(*bp))
bp++;
if (*bp == 0) {
msg_warn("missing argument");
} else if (strcmp(cmd, "quote") == 0) {
quote_822_local(out, bp);
vstream_printf("'%s' quoted '%s'\n", bp, STR(out));
} else if (strcmp(cmd, "quote_with_flags") == 0) {
if ((cmd = mystrtok(&bp, CHARS_SPACE)) == 0) {
msg_warn("missing flags");
continue;
}
while (ISSPACE(*bp))
bp++;
flags = quote_flags_from_string(cmd);
quote_822_local_flags(out, bp, flags);
vstream_printf("'%s' quoted flags=%s '%s'\n",
bp, quote_flags_to_string((VSTRING *) 0, flags), STR(out));
} else if (strcmp(cmd, "unquote") == 0) {
unquote_822_local(out, bp);
vstream_printf("'%s' unquoted '%s'\n", bp, STR(out));
} else {
msg_warn("unknown command: %s", cmd);
}
vstream_fflush(VSTREAM_OUT);
}
}
vstring_free(in);
vstring_free(out);
return (0);
}
#endif