static gboolean decode_route (const char **in) { const char *start = *in; const char *inptr = *in; GString *route; route = g_string_new (""); do { inptr++; g_string_append_c (route, '@'); if (!decode_domain (&inptr, route)) { g_string_free (route, TRUE); goto error; } decode_lwsp (&inptr); if (*inptr == ',') { g_string_append_c (route, ','); inptr++; decode_lwsp (&inptr); /* obs-domain-lists allow commas with nothing between them... */ while (*inptr == ',') { inptr++; decode_lwsp (&inptr); } } } while (*inptr == '@'); g_string_free (route, TRUE); decode_lwsp (&inptr); if (*inptr != ':') { w(g_warning ("Invalid route domain-list, missing ':': %.*s", inptr - start, start)); goto error; } /* eat the ':' */ *in = inptr + 1; return TRUE; error: while (*inptr && *inptr != ':' && *inptr != '>') inptr++; if (*inptr == ':') inptr++; *in = inptr; return FALSE; }
static InternetAddress * decode_address (const char **in) { const char *inptr, *start, *word, *comment = NULL; InternetAddress *addr = NULL; gboolean has_lwsp = FALSE; gboolean is_word; GString *name; decode_lwsp (in); start = inptr = *in; name = g_string_new (""); /* Both groups and mailboxes can begin with a phrase (denoting * the display name for the address). Collect all of the * tokens that make up this name phrase. */ while (*inptr) { if ((word = decode_word (&inptr))) { g_string_append_len (name, word, (size_t) (inptr - word)); check_lwsp: word = inptr; skip_lwsp (&inptr); /* is the next token a word token? */ is_word = *inptr == '"' || is_atom (*inptr); if (inptr > word && is_word) { g_string_append_c (name, ' '); has_lwsp = TRUE; } if (is_word) continue; } /* specials = "(" / ")" / "<" / ">" / "@" ; Must be in quoted- * / "," / ";" / ":" / "\" / <"> ; string, to use * / "." / "[" / "]" ; within a word. */ if (*inptr == ':') { /* rfc2822 group */ inptr++; addr = decode_group (&inptr); decode_lwsp (&inptr); if (*inptr != ';') w(g_warning ("Invalid group spec, missing closing ';': %.*s", inptr - start, start)); else inptr++; break; } else if (*inptr == '<') { /* rfc2822 angle-addr */ inptr++; /* check for obsolete routing... */ if (*inptr != '@' || decode_route (&inptr)) { /* rfc2822 addr-spec */ addr = decode_addrspec (&inptr); } decode_lwsp (&inptr); if (*inptr != '>') { w(g_warning ("Invalid rfc2822 angle-addr, missing closing '>': %.*s", inptr - start, start)); while (*inptr && *inptr != '>' && *inptr != ',') inptr++; if (*inptr == '>') inptr++; } else { inptr++; } /* if comment is non-NULL, we can check for a comment containing a name */ comment = inptr; break; } else if (*inptr == '(') { /* beginning of a comment, use decode_lwsp() to skip past it */ decode_lwsp (&inptr); } else if (*inptr && strchr ("@,;", *inptr)) { if (name->len == 0) { if (*inptr == '@') { GString *domain; w(g_warning ("Unexpected address: %s: skipping.", start)); /* skip over @domain? */ inptr++; domain = g_string_new (""); decode_domain (&inptr, domain); g_string_free (domain, TRUE); } else { /* empty address */ } break; } else if (has_lwsp) { /* assume this is just an unquoted special that we should treat as part of the name */ w(g_warning ("Unquoted '%c' in address name: %s: ignoring.", *inptr, start)); g_string_append_c (name, *inptr); inptr++; goto check_lwsp; } addrspec: /* what we thought was a name was actually an addrspec? */ g_string_truncate (name, 0); inptr = start; addr = decode_addrspec (&inptr); /* if comment is non-NULL, we can check for a comment containing a name */ comment = inptr; break; } else if (*inptr == '.') { /* This would normally signify that we are * decoding the local-part of an addr-spec, * but sadly, it is common for broken mailers * to forget to quote/encode .'s in the name * phrase. */ g_string_append_c (name, *inptr); inptr++; goto check_lwsp; } else if (*inptr) { /* Technically, these are all invalid tokens * but in the interest of being liberal in * what we accept, we'll ignore them. */ w(g_warning ("Unexpected char '%c' in address: %s: ignoring.", *inptr, start)); g_string_append_c (name, *inptr); inptr++; goto check_lwsp; } else { goto addrspec; } } /* Note: will also skip over any comments */ decode_lwsp (&inptr); if (name->len == 0 && comment && inptr > comment) { /* missing a name, look for a trailing comment */ if ((comment = memchr (comment, '(', inptr - comment))) { const char *cend; /* find the end of the comment */ cend = inptr - 1; while (cend > comment && is_lwsp (*cend)) cend--; if (*cend == ')') cend--; g_string_append_len (name, comment + 1, (size_t) (cend - comment)); } } if (addr && name->len > 0) _internet_address_decode_name (addr, name); g_string_free (name, TRUE); *in = inptr; return addr; }
static InternetAddress * decode_addrspec (const char **in) { InternetAddress *mailbox = NULL; const char *start, *inptr, *word; gboolean got_local = FALSE; GString *addr; size_t len; addr = g_string_new (""); inptr = *in; decode_lwsp (&inptr); /* some spam bots set their addresses to stuff like: )[email protected] */ while (*inptr && !(*inptr == '"' || is_atom (*inptr))) inptr++; start = inptr; /* extract the first word of the local-part */ if ((word = decode_word (&inptr))) { g_string_append_len (addr, word, (size_t) (inptr - word)); decode_lwsp (&inptr); got_local = TRUE; } /* extract the rest of the local-part */ while (word && *inptr == '.') { /* Note: According to the spec, only a single '.' is * allowed between word tokens in the local-part of an * addr-spec token, but according to Evolution bug * #547969, some Japanese cellphones have email * addresses that look like [email protected] */ do { inptr++; decode_lwsp (&inptr); g_string_append_c (addr, '.'); } while (*inptr == '.'); if ((word = decode_word (&inptr))) g_string_append_len (addr, word, (size_t) (inptr - word)); decode_lwsp (&inptr); } if (*inptr == '@') { len = addr->len; g_string_append_c (addr, '@'); inptr++; if (!decode_domain (&inptr, addr)) { /* drop the @domain and continue as if it weren't there */ w(g_warning ("Missing domain in addr-spec: %.*s", inptr - start, start)); g_string_truncate (addr, len); } } else if (got_local) { w(g_warning ("Missing '@' and domain in addr-spec: %.*s", inptr - start, start)); } *in = inptr; if (!got_local) { w(g_warning ("Invalid addr-spec, missing local-part: %.*s", inptr - start, start)); g_string_free (addr, TRUE); return NULL; } mailbox = g_object_newv (INTERNET_ADDRESS_TYPE_MAILBOX, 0, NULL); ((InternetAddressMailbox *) mailbox)->addr = addr->str; g_string_free (addr, FALSE); return mailbox; }
static int get_command(struct command_s *command) { char *next; again: printf("command: "); if (!fgets(cbuf, COMMAND_MAX_LEN, stdin)) return -1; next = strtok(cbuf, " \n"); if (!next) goto again; if (decode_type(command, next)) { fprintf(stderr, "Invalid command type \"%s\"\n", next); goto again; } if (command->c_type == HELP) return 0; next = strtok(NULL, " "); if (!next) { fprintf(stderr, "invalid input!\n"); goto again; } switch (command->c_type) { case REGISTER: case UNREGISTER: if (decode_domain(command, next)) { fprintf(stderr, "Invalid domain \"%s\"\n", next); goto again; } break; case LOCK: case TRYLOCK: if (decode_level(command, next)) { fprintf(stderr, "Invalid lock level \"%s\"\n", next); goto again; } next = strtok(NULL, " "); if (!next) { fprintf(stderr, "invalid input!\n"); goto again; } /* fall through */ case SETLVB: case GETLVB: case UNLOCK: if (decode_lock(command, next)) { fprintf(stderr, "Invalid lock \"%s\"\n", next); goto again; } if (command->c_type == SETLVB) { /* for setlvb we want to get a pointer to the * start of the string to stuff */ next = strtok(NULL, "\n"); if (!next) { fprintf(stderr, "invalid input!\n"); goto again; } kill_return(next); command->c_lvb = next; } break; default: fprintf(stderr, "whoa, can't parse this\n"); } return 0; }