/* * 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; }
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; }