X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=citadel%2Finternet_addressing.c;h=ebc419f6abfbc60444615a81e9b28435cfcaf94c;hb=a2fda4eafb51bbf58c04471522aa2d0f116c797e;hp=fd16a6f1813e1bb1385b859be08d00c2e3690369;hpb=c7b582a4a56b2b2252588a222a81835d00a41327;p=citadel.git diff --git a/citadel/internet_addressing.c b/citadel/internet_addressing.c index fd16a6f18..ebc419f6a 100644 --- a/citadel/internet_addressing.c +++ b/citadel/internet_addressing.c @@ -5,10 +5,6 @@ * to users on the Citadel system. */ -#ifdef DLL_EXPORT -#define IN_LIBCIT -#endif - #include "sysdep.h" #include #include @@ -34,14 +30,13 @@ #include #include #include +#include #include "citadel.h" #include "server.h" -#include "serv_extensions.h" #include "sysdep_decls.h" #include "citserver.h" #include "support.h" #include "config.h" -#include "tools.h" #include "msgbase.h" #include "internet_addressing.h" #include "user_ops.h" @@ -70,20 +65,21 @@ struct spamstrings_t *spamstrings = NULL; int CtdlHostAlias(char *fqdn) { int config_lines; int i; - char buf[SIZ]; - char host[SIZ], type[SIZ]; + char buf[256]; + char host[256], type[256]; if (fqdn == NULL) return(hostalias_nomatch); - if (strlen(fqdn) == 0) return(hostalias_nomatch); + if (IsEmptyStr(fqdn)) return(hostalias_nomatch); + if (!strcasecmp(fqdn, "localhost")) return(hostalias_localhost); if (!strcasecmp(fqdn, config.c_fqdn)) return(hostalias_localhost); if (!strcasecmp(fqdn, config.c_nodename)) return(hostalias_localhost); if (inetcfg == NULL) return(hostalias_nomatch); config_lines = num_tokens(inetcfg, '\n'); for (i=0; iusernum)) { return 0; } - - for (a=0; afullname); ++a) { + len = strlen(matchstring); + for (a=0; !IsEmptyStr(&us->fullname[a]); ++a) { if (!strncasecmp(&us->fullname[a], - matchstring, strlen(matchstring))) { + matchstring, len)) { return 0; } } @@ -167,12 +168,14 @@ void process_rfc822_addr(const char *rfc822, char *user, char *node, char *name) strcpy(node, config.c_fqdn); strcpy(name, ""); + if (rfc822 == NULL) return; + /* extract full name - first, it's From minus */ strcpy(name, rfc822); stripout(name, '<', '>'); /* strip anything to the left of a bang */ - while ((strlen(name) > 0) && (haschar(name, '!') > 0)) + while ((!IsEmptyStr(name)) && (haschar(name, '!') > 0)) strcpy(name, &name[1]); /* and anything to the right of a @ or % */ @@ -192,7 +195,7 @@ void process_rfc822_addr(const char *rfc822, char *user, char *node, char *name) /* but if there are a set of quotes, that supersedes everything */ if (haschar(rfc822, 34) == 2) { strcpy(name, rfc822); - while ((strlen(name) > 0) && (name[0] != 34)) { + while ((!IsEmptyStr(name)) && (name[0] != 34)) { strcpy(&name[0], &name[1]); } strcpy(&name[0], &name[1]); @@ -212,7 +215,7 @@ void process_rfc822_addr(const char *rfc822, char *user, char *node, char *name) } /* strip anything to the left of a bang */ - while ((strlen(user) > 0) && (haschar(user, '!') > 0)) + while ((!IsEmptyStr(user)) && (haschar(user, '!') > 0)) strcpy(user, &user[1]); /* and anything to the right of a @ or % */ @@ -247,15 +250,15 @@ void process_rfc822_addr(const char *rfc822, char *user, char *node, char *name) else { /* strip anything to the left of a @ */ - while ((strlen(node) > 0) && (haschar(node, '@') > 0)) + while ((!IsEmptyStr(node)) && (haschar(node, '@') > 0)) strcpy(node, &node[1]); /* strip anything to the left of a % */ - while ((strlen(node) > 0) && (haschar(node, '%') > 0)) + while ((!IsEmptyStr(node)) && (haschar(node, '%') > 0)) strcpy(node, &node[1]); /* reduce multiple system bang paths to node!user */ - while ((strlen(node) > 0) && (haschar(node, '!') > 1)) + while ((!IsEmptyStr(node)) && (haschar(node, '!') > 1)) strcpy(node, &node[1]); /* now get rid of the user portion of a node!user string */ @@ -273,7 +276,7 @@ void process_rfc822_addr(const char *rfc822, char *user, char *node, char *name) * but no name outside the brackets, we now have an empty name. In * this case, use the user portion of the address as the name. */ - if ((strlen(name) == 0) && (strlen(user) > 0)) { + if ((IsEmptyStr(name)) && (!IsEmptyStr(user))) { strcpy(name, user); } } @@ -309,7 +312,7 @@ int convert_field(struct CtdlMessage *msg, int beg, int end) { if (colonpos < 0) return(0); /* no colon? not a valid header line */ - key = mallok((end - beg) + 2); + key = malloc((end - beg) + 2); safestrncpy(key, &rfc822[beg], (end-beg)+1); key[colonpos - beg] = 0; value = &key[(colonpos - beg) + 1]; @@ -327,35 +330,47 @@ int convert_field(struct CtdlMessage *msg, int beg, int end) { if (parsed_date < 0L) parsed_date = time(NULL); snprintf(buf, sizeof buf, "%ld", (long)parsed_date ); if (msg->cm_fields['T'] == NULL) - msg->cm_fields['T'] = strdoop(buf); + msg->cm_fields['T'] = strdup(buf); processed = 1; } else if (!strcasecmp(key, "From")) { process_rfc822_addr(value, user, node, name); - lprintf(9, "Converted to <%s@%s> (%s)\n", user, node, name); + CtdlLogPrintf(CTDL_DEBUG, "Converted to <%s@%s> (%s)\n", user, node, name); snprintf(addr, sizeof addr, "%s@%s", user, node); if (msg->cm_fields['A'] == NULL) - msg->cm_fields['A'] = strdoop(name); + msg->cm_fields['A'] = strdup(name); processed = 1; if (msg->cm_fields['F'] == NULL) - msg->cm_fields['F'] = strdoop(addr); + msg->cm_fields['F'] = strdup(addr); processed = 1; } else if (!strcasecmp(key, "Subject")) { if (msg->cm_fields['U'] == NULL) - msg->cm_fields['U'] = strdoop(value); + msg->cm_fields['U'] = strdup(value); + processed = 1; + } + + else if (!strcasecmp(key, "To")) { + if (msg->cm_fields['R'] == NULL) + msg->cm_fields['R'] = strdup(value); + processed = 1; + } + + else if (!strcasecmp(key, "CC")) { + if (msg->cm_fields['Y'] == NULL) + msg->cm_fields['Y'] = strdup(value); processed = 1; } else if (!strcasecmp(key, "Message-ID")) { if (msg->cm_fields['I'] != NULL) { - lprintf(5, "duplicate message id\n"); + CtdlLogPrintf(CTDL_WARNING, "duplicate message id\n"); } if (msg->cm_fields['I'] == NULL) { - msg->cm_fields['I'] = strdoop(value); + msg->cm_fields['I'] = strdup(value); /* Strip angle brackets */ while (haschar(msg->cm_fields['I'], '<') > 0) { @@ -370,8 +385,20 @@ int convert_field(struct CtdlMessage *msg, int beg, int end) { processed = 1; } + else if (!strcasecmp(key, "Return-Path")) { + if (msg->cm_fields['P'] == NULL) + msg->cm_fields['P'] = strdup(value); + processed = 1; + } + + else if (!strcasecmp(key, "Envelope-To")) { + if (msg->cm_fields['V'] == NULL) + msg->cm_fields['V'] = strdup(value); + processed = 1; + } + /* Clean up and move on. */ - phree(key); /* Don't free 'value', it's actually the same buffer */ + free(key); /* Don't free 'value', it's actually the same buffer */ return(processed); } @@ -391,7 +418,7 @@ struct CtdlMessage *convert_internet_message(char *rfc822) { char buf[SIZ]; int converted; - msg = mallok(sizeof(struct CtdlMessage)); + msg = malloc(sizeof(struct CtdlMessage)); if (msg == NULL) return msg; memset(msg, 0, sizeof(struct CtdlMessage)); @@ -400,7 +427,6 @@ struct CtdlMessage *convert_internet_message(char *rfc822) { msg->cm_format_type = FMT_RFC822; /* internet message */ msg->cm_fields['M'] = rfc822; - lprintf(9, "Unconverted RFC822 message length = %ld\n", (long)strlen(rfc822)); pos = 0; done = 0; @@ -420,17 +446,7 @@ struct CtdlMessage *convert_internet_message(char *rfc822) { end = pos; } - /* done with headers? (commented out; see below) - if ( ((rfc822[pos]=='\n') - ||(rfc822[pos]=='\r') ) - && ( (rfc822[pos+1]=='\n') - ||(rfc822[pos+1]=='\r')) ) { - end = pos; - done = 1; - } - */ - - /* done with headers? (try this way instead) */ + /* done with headers? */ if ( (rfc822[pos]=='\n') && ( (rfc822[pos+1]=='\n') ||(rfc822[pos+1]=='\r')) ) { @@ -465,11 +481,9 @@ struct CtdlMessage *convert_internet_message(char *rfc822) { /* If there's no timestamp on this message, set it to now. */ if (msg->cm_fields['T'] == NULL) { snprintf(buf, sizeof buf, "%ld", (long)time(NULL)); - msg->cm_fields['T'] = strdoop(buf); + msg->cm_fields['T'] = strdup(buf); } - lprintf(9, "RFC822 length remaining after conversion = %ld\n", - (long)strlen(rfc822)); return msg; } @@ -483,62 +497,46 @@ struct CtdlMessage *convert_internet_message(char *rfc822) { * field is not present, or anything else goes wrong, it returns NULL. */ char *rfc822_fetch_field(char *rfc822, char *fieldname) { - int pos = 0; - int beg, end; - int done = 0; - int colonpos, i; char *fieldbuf = NULL; + char *end_of_headers; + char *field_start; + char *ptr; + char *cont; + char fieldhdr[SIZ]; /* Should never happen, but sometimes we get stupid */ if (rfc822 == NULL) return(NULL); if (fieldname == NULL) return(NULL); - while (!done) { + snprintf(fieldhdr, sizeof fieldhdr, "%s:", fieldname); - /* Locate beginning and end of field, keeping in mind that - * some fields might be multiline - */ - beg = pos; - end = (-1); - for (pos=beg; ((pos<=strlen(rfc822))&&(end<0)); ++pos) { - if ((rfc822[pos]=='\n') - && (!isspace(rfc822[pos+1]))) { - end = pos; - } - if ( (rfc822[pos]=='\n') /* done w. headers? */ - && ( (rfc822[pos+1]=='\n') - ||(rfc822[pos+1]=='\r'))) { - end = pos; - done = 1; - } - - } + /* Locate the end of the headers, so we don't run past that point */ + end_of_headers = bmstrcasestr(rfc822, "\n\r\n"); + if (end_of_headers == NULL) { + end_of_headers = bmstrcasestr(rfc822, "\n\n"); + } + if (end_of_headers == NULL) return (NULL); + + field_start = bmstrcasestr(rfc822, fieldhdr); + if (field_start == NULL) return(NULL); + if (field_start > end_of_headers) return(NULL); + + fieldbuf = malloc(SIZ); + strcpy(fieldbuf, ""); + + ptr = field_start; + ptr = memreadline(ptr, fieldbuf, SIZ-strlen(fieldbuf) ); + while ( (isspace(ptr[0])) && (ptr < end_of_headers) ) { + strcat(fieldbuf, " "); + cont = &fieldbuf[strlen(fieldbuf)]; + ptr = memreadline(ptr, cont, SIZ-strlen(fieldbuf) ); + striplt(cont); + } - /* At this point we have a field. Is it The One? */ - if (end > beg) { - fieldbuf = mallok((end-beg)+3); - if (fieldbuf == NULL) return(NULL); - safestrncpy(fieldbuf, &rfc822[beg], (end-beg)+1); - unfold_rfc822_field(fieldbuf); - colonpos = (-1); - for (i = strlen(fieldbuf); i >= 0; --i) { - if (fieldbuf[i] == ':') colonpos = i; - } - if (colonpos > 0) { - fieldbuf[colonpos] = 0; - if (!strcasecmp(fieldbuf, fieldname)) { - strcpy(fieldbuf, &fieldbuf[colonpos+1]); - striplt(fieldbuf); - return(fieldbuf); - } - } - phree(fieldbuf); - } + strcpy(fieldbuf, &fieldbuf[strlen(fieldhdr)]); + striplt(fieldbuf); - /* If we've hit the end of the message, bail out */ - if (pos > strlen(rfc822)) done = 1; - } - return(NULL); + return(fieldbuf); } @@ -555,14 +553,14 @@ void directory_key(char *key, char *addr) { int i; int keylen = 0; - for (i=0; i\n", key); + CtdlLogPrintf(CTDL_DEBUG, "Directory key is <%s>\n", key); } @@ -570,22 +568,22 @@ void directory_key(char *key, char *addr) { /* Return nonzero if the supplied address is in a domain we keep in * the directory */ -int IsDirectory(char *addr) { - char domain[SIZ]; +int IsDirectory(char *addr, int allow_masq_domains) { + char domain[256]; int h; - extract_token(domain, addr, 1, '@'); + extract_token(domain, addr, 1, '@', sizeof domain); striplt(domain); h = CtdlHostAlias(domain); - lprintf(9, "IsDirectory(%s)\n", domain); + if ( (h == hostalias_masq) && allow_masq_domains) + return(1); + if ( (h == hostalias_localhost) || (h == hostalias_directory) ) { - lprintf(9, " ...yes\n"); return(1); } else { - lprintf(9, " ...no\n"); return(0); } } @@ -605,9 +603,9 @@ void CtdlDirectoryInit(void) { void CtdlDirectoryAddUser(char *internet_addr, char *citadel_addr) { char key[SIZ]; - lprintf(9, "Dir: %s --> %s\n", + CtdlLogPrintf(CTDL_DEBUG, "Dir: %s --> %s\n", internet_addr, citadel_addr); - if (IsDirectory(internet_addr) == 0) return; + if (IsDirectory(internet_addr, 0) == 0) return; directory_key(key, internet_addr); @@ -635,26 +633,94 @@ void CtdlDirectoryDelUser(char *internet_addr, char *citadel_addr) { * On success: returns 0, and Citadel address stored in 'target' * On failure: returns nonzero */ -int CtdlDirectoryLookup(char *target, char *internet_addr) { +int CtdlDirectoryLookup(char *target, char *internet_addr, size_t targbuflen) { struct cdbdata *cdbrec; char key[SIZ]; /* Dump it in there unchanged, just for kicks */ - strcpy(target, internet_addr); + safestrncpy(target, internet_addr, targbuflen); /* Only do lookups for addresses with hostnames in them */ if (num_tokens(internet_addr, '@') != 2) return(-1); /* Only do lookups for domains in the directory */ - if (IsDirectory(internet_addr) == 0) return(-1); + if (IsDirectory(internet_addr, 0) == 0) return(-1); directory_key(key, internet_addr); cdbrec = cdb_fetch(CDB_DIRECTORY, key, strlen(key) ); if (cdbrec != NULL) { - safestrncpy(target, cdbrec->ptr, SIZ); + safestrncpy(target, cdbrec->ptr, targbuflen); cdb_free(cdbrec); return(0); } return(-1); } + + +/* + * Harvest any email addresses that someone might want to have in their + * "collected addresses" book. + */ +char *harvest_collected_addresses(struct CtdlMessage *msg) { + char *coll = NULL; + char addr[256]; + char user[256], node[256], name[256]; + int is_harvestable; + int i, j, h; + int field = 0; + + if (msg == NULL) return(NULL); + + is_harvestable = 1; + strcpy(addr, ""); + if (msg->cm_fields['A'] != NULL) { + strcat(addr, msg->cm_fields['A']); + } + if (msg->cm_fields['F'] != NULL) { + strcat(addr, " <"); + strcat(addr, msg->cm_fields['F']); + strcat(addr, ">"); + if (IsDirectory(msg->cm_fields['F'], 0)) { + is_harvestable = 0; + } + } + + if (is_harvestable) { + coll = strdup(addr); + } + else { + coll = strdup(""); + } + + if (coll == NULL) return(NULL); + + /* Scan both the R (To) and Y (CC) fields */ + for (i = 0; i < 2; ++i) { + if (i == 0) field = 'R' ; + if (i == 1) field = 'Y' ; + + if (msg->cm_fields[field] != NULL) { + for (j=0; jcm_fields[field], ','); ++j) { + extract_token(addr, msg->cm_fields[field], j, ',', sizeof addr); + process_rfc822_addr(addr, user, node, name); + h = CtdlHostAlias(node); + if ( (h != hostalias_localhost) && (h != hostalias_directory) ) { + coll = realloc(coll, strlen(coll) + strlen(addr) + 4); + if (coll == NULL) return(NULL); + if (!IsEmptyStr(coll)) { + strcat(coll, ","); + } + striplt(addr); + strcat(coll, addr); + } + } + } + } + + if (IsEmptyStr(coll)) { + free(coll); + return(NULL); + } + return(coll); +}