Example #1
0
/*
 * Parse all the " by MTA ..." parts in received headers to guess the
 * email address that this was originally delivered to.
 *
 * Extract just the MTA here by removing leading whitespace and
 * assuming that the MTA name ends at the next whitespace. Test for
 * *(by+4) to be non-'\0' to make sure there's something there at all
 * - and then assume that the first whitespace delimited token that
 * follows is the receiving system in this step of the receive chain.
 *
 * Return the address that was found, if any, and NULL otherwise.
 */
static const char *
guess_from_in_received_by (notmuch_config_t *config, const char *received)
{
    const char *addr;
    const char *by = received;
    char *domain, *tld, *mta, *ptr, *token;

    while ((by = strstr (by, " by ")) != NULL) {
	by += 4;
	if (*by == '\0')
	    break;
	mta = xstrdup (by);
	token = strtok(mta," \t");
	if (token == NULL) {
	    free (mta);
	    break;
	}
	/*
	 * Now extract the last two components of the MTA host name as
	 * domain and tld.
	 */
	domain = tld = NULL;
	while ((ptr = strsep (&token, ". \t")) != NULL) {
	    if (*ptr == '\0')
		continue;
	    domain = tld;
	    tld = ptr;
	}

	if (domain) {
	    /*
	     * Recombine domain and tld and look for it among the
	     * configured email addresses. This time we have a known
	     * domain name and nothing else - so the test is the other
	     * way around: we check if this is a substring of one of
	     * the email addresses.
	     */
	    *(tld - 1) = '.';

	    addr = string_in_user_address (domain, config);
	    if (addr) {
		free (mta);
		return addr;
	    }
	}
	free (mta);
    }

    return NULL;
}
Example #2
0
static const char *
guess_from_received_header (notmuch_config_t *config, notmuch_message_t *message)
{
    const char *addr, *received, *by;
    char *mta,*ptr,*token;
    char *domain=NULL;
    char *tld=NULL;
    const char *delim=". \t";
    size_t i;

    const char *to_headers[] = {
	"Envelope-to",
	"X-Original-To",
	"Delivered-To",
    };

    /* sadly, there is no standard way to find out to which email
     * address a mail was delivered - what is in the headers depends
     * on the MTAs used along the way. So we are trying a number of
     * heuristics which hopefully will answer this question.

     * We only got here if none of the users email addresses are in
     * the To: or Cc: header. From here we try the following in order:
     * 1) check for an Envelope-to: header
     * 2) check for an X-Original-To: header
     * 3) check for a Delivered-To: header
     * 4) check for a (for <*****@*****.**>) clause in Received: headers
     * 5) check for the domain part of known email addresses in the
     *    'by' part of Received headers
     * If none of these work, we give up and return NULL
     */
    for (i = 0; i < ARRAY_SIZE (to_headers); i++) {
	const char *tohdr = notmuch_message_get_header (message, to_headers[i]);

	/* Note: tohdr potentially contains a list of email addresses. */
	addr = user_address_in_string (tohdr, config);
	if (addr)
	    return addr;
    }

    /* We get the concatenated Received: headers and search from the
     * front (last Received: header added) and try to extract from
     * them indications to which email address this message was
     * delivered.
     * The Received: header is special in our get_header function
     * and is always concatenated.
     */
    received = notmuch_message_get_header (message, "received");
    if (received == NULL)
	return NULL;

    /* First we look for a " for <*****@*****.**>" in the received
     * header
     */
    ptr = strstr (received, " for ");

    /* Note: ptr potentially contains a list of email addresses. */
    addr = user_address_in_string (ptr, config);
    if (addr)
	return addr;

    /* Finally, we parse all the " by MTA ..." headers to guess the
     * email address that this was originally delivered to.
     * We extract just the MTA here by removing leading whitespace and
     * assuming that the MTA name ends at the next whitespace.
     * We test for *(by+4) to be non-'\0' to make sure there's
     * something there at all - and then assume that the first
     * whitespace delimited token that follows is the receiving
     * system in this step of the receive chain
     */
    by = received;
    while((by = strstr (by, " by ")) != NULL) {
	by += 4;
	if (*by == '\0')
	    break;
	mta = xstrdup (by);
	token = strtok(mta," \t");
	if (token == NULL) {
	    free (mta);
	    break;
	}
	/* Now extract the last two components of the MTA host name
	 * as domain and tld.
	 */
	domain = tld = NULL;
	while ((ptr = strsep (&token, delim)) != NULL) {
	    if (*ptr == '\0')
		continue;
	    domain = tld;
	    tld = ptr;
	}

	if (domain) {
	    /* Recombine domain and tld and look for it among the configured
	     * email addresses.
	     * This time we have a known domain name and nothing else - so
	     * the test is the other way around: we check if this is a
	     * substring of one of the email addresses.
	     */
	    *(tld-1) = '.';

	    addr = string_in_user_address (domain, config);
	    if (addr) {
		free (mta);
		return addr;
	    }
	}
	free (mta);
    }

    return NULL;
}