int smtp_resolve_recipients(SmtpOutMsg *Msg) { AsyncIO *IO = &Msg->IO; const char *ptr; char buf[1024]; int scan_done; int lp, rp; int i; EVNCS_syslog(LOG_DEBUG, "%s\n", __FUNCTION__); if ((Msg==NULL) || (Msg->MyQEntry == NULL) || (StrLength(Msg->MyQEntry->Recipient) == 0)) { return 0; } /* Parse out the host portion of the recipient address */ process_rfc822_addr(ChrPtr(Msg->MyQEntry->Recipient), Msg->user, Msg->node, Msg->name); EVNCS_syslog(LOG_DEBUG, "Attempting delivery to <%s> @ <%s> (%s)\n", Msg->user, Msg->node, Msg->name); /* If no envelope_from is supplied, extract one from the message */ Msg->envelope_from = ChrPtr(Msg->MyQItem->EnvelopeFrom); if ( (Msg->envelope_from == NULL) || (IsEmptyStr(Msg->envelope_from)) ) { Msg->mailfrom[0] = '\0'; scan_done = 0; ptr = ChrPtr(Msg->msgtext); do { if (ptr = cmemreadline(ptr, buf, sizeof buf), *ptr == 0) { scan_done = 1; } if (!strncasecmp(buf, "From:", 5)) { safestrncpy(Msg->mailfrom, &buf[5], sizeof Msg->mailfrom); striplt(Msg->mailfrom); for (i=0; Msg->mailfrom[i]; ++i) { if (!isprint(Msg->mailfrom[i])) { strcpy(&Msg->mailfrom[i], &Msg->mailfrom[i+1]); i=0; } } /* Strip out parenthesized names */ lp = (-1); rp = (-1); for (i=0; !IsEmptyStr(Msg->mailfrom + i); ++i) { if (Msg->mailfrom[i] == '(') lp = i; if (Msg->mailfrom[i] == ')') rp = i; } if ((lp>0)&&(rp>lp)) { strcpy(&Msg->mailfrom[lp-1], &Msg->mailfrom[rp+1]); } /* Prefer brokketized names */ lp = (-1); rp = (-1); for (i=0; !IsEmptyStr(Msg->mailfrom + i); ++i) { if (Msg->mailfrom[i] == '<') lp = i; if (Msg->mailfrom[i] == '>') rp = i; } if ( (lp>=0) && (rp>lp) ) { Msg->mailfrom[rp] = 0; memmove(Msg->mailfrom, &Msg->mailfrom[lp + 1], rp - lp); } scan_done = 1; } } while (scan_done == 0); if (IsEmptyStr(Msg->mailfrom)) strcpy(Msg->mailfrom, "*****@*****.**"); stripallbut(Msg->mailfrom, '<', '>'); Msg->envelope_from = Msg->mailfrom; } return 1; }
/* * Aliasing for network mail. * (Error messages have been commented out, because this is a server.) */ int alias(char *name) { /* process alias and routing info for mail */ struct CitContext *CCC = CC; FILE *fp; int a, i; char aaa[SIZ], bbb[SIZ]; char *ignetcfg = NULL; char *ignetmap = NULL; int at = 0; char node[64]; char testnode[64]; char buf[SIZ]; char original_name[256]; safestrncpy(original_name, name, sizeof original_name); striplt(name); remove_any_whitespace_to_the_left_or_right_of_at_symbol(name); stripallbut(name, '<', '>'); fp = fopen(file_mail_aliases, "r"); if (fp == NULL) { fp = fopen("/dev/null", "r"); } if (fp == NULL) { return (MES_ERROR); } strcpy(aaa, ""); strcpy(bbb, ""); while (fgets(aaa, sizeof aaa, fp) != NULL) { while (isspace(name[0])) strcpy(name, &name[1]); aaa[strlen(aaa) - 1] = 0; strcpy(bbb, ""); for (a = 0; aaa[a] != '\0'; ++a) { if (aaa[a] == ',') { strcpy(bbb, &aaa[a + 1]); aaa[a] = 0; break; } } if (!strcasecmp(name, aaa)) strcpy(name, bbb); } fclose(fp); /* Hit the Global Address Book */ if (CtdlDirectoryLookup(aaa, name, sizeof aaa) == 0) { strcpy(name, aaa); } if (strcasecmp(original_name, name)) { MSG_syslog(LOG_INFO, "%s is being forwarded to %s\n", original_name, name); } /* Change "user @ xxx" to "user" if xxx is an alias for this host */ for (a=0; name[a] != '\0'; ++a) { if (name[a] == '@') { if (CtdlHostAlias(&name[a+1]) == hostalias_localhost) { name[a] = 0; MSG_syslog(LOG_INFO, "Changed to <%s>\n", name); break; } } } /* determine local or remote type, see citadel.h */ at = haschar(name, '@'); if (at == 0) return(MES_LOCAL); /* no @'s - local address */ if (at > 1) return(MES_ERROR); /* >1 @'s - invalid address */ remove_any_whitespace_to_the_left_or_right_of_at_symbol(name); /* figure out the delivery mode */ extract_token(node, name, 1, '@', sizeof node); /* If there are one or more dots in the nodename, we assume that it * is an FQDN and will attempt SMTP delivery to the Internet. */ if (haschar(node, '.') > 0) { return(MES_INTERNET); } /* Otherwise we look in the IGnet maps for a valid Citadel node. * Try directly-connected nodes first... */ ignetcfg = CtdlGetSysConfig(IGNETCFG); for (i=0; i<num_tokens(ignetcfg, '\n'); ++i) { extract_token(buf, ignetcfg, i, '\n', sizeof buf); extract_token(testnode, buf, 0, '|', sizeof testnode); if (!strcasecmp(node, testnode)) { free(ignetcfg); return(MES_IGNET); } } free(ignetcfg); /* * Then try nodes that are two or more hops away. */ ignetmap = CtdlGetSysConfig(IGNETMAP); for (i=0; i<num_tokens(ignetmap, '\n'); ++i) { extract_token(buf, ignetmap, i, '\n', sizeof buf); extract_token(testnode, buf, 0, '|', sizeof testnode); if (!strcasecmp(node, testnode)) { free(ignetmap); return(MES_IGNET); } } free(ignetmap); /* If we get to this point it's an invalid node name */ return (MES_ERROR); }
static long parse_MimeHeaders(interesting_mime_headers *m, char** pcontent_start, char *content_end) { char buf[SIZ]; char header[SIZ]; long headerlen; char *ptr, *pch; int buflen = 0; int i; /* Learn interesting things from the headers */ ptr = *pcontent_start; *header = '\0'; headerlen = 0; do { ptr = memreadlinelen(ptr, buf, SIZ, &buflen); for (i = 0; i < buflen; ++i) { if (isspace(buf[i])) { buf[i] = ' '; } } if (!isspace(buf[0]) && (headerlen > 0)) { if (!strncasecmp(header, "Content-type:", 13)) { memcpy (m->b[content_type].Key, &header[13], headerlen - 12); m->b[content_type].Key[headerlen - 12] = '\0'; m->b[content_type].len = striplt (m->b[content_type].Key); m->b[content_type_name].len = extract_key(m->b[content_type_name].Key, CKEY(m->b[content_type]), HKEY("name"), '='); m->b[charset].len = extract_key(m->b[charset].Key, CKEY(m->b[content_type]), HKEY("charset"), '='); m->b[boundary].len = extract_key(m->b[boundary].Key, header, headerlen, HKEY("boundary"), '='); /* Deal with weird headers */ pch = strchr(m->b[content_type].Key, ' '); if (pch != NULL) { *pch = '\0'; m->b[content_type].len = m->b[content_type].Key - pch; } pch = strchr(m->b[content_type].Key, ';'); if (pch != NULL) { *pch = '\0'; m->b[content_type].len = m->b[content_type].Key - pch; } } else if (!strncasecmp(header, "Content-Disposition:", 20)) { memcpy (m->b[disposition].Key, &header[20], headerlen - 19); m->b[disposition].Key[headerlen - 19] = '\0'; m->b[disposition].len = striplt(m->b[disposition].Key); m->b[content_disposition_name].len = extract_key(m->b[content_disposition_name].Key, CKEY(m->b[disposition]), HKEY("name"), '='); m->b[filename].len = extract_key(m->b[filename].Key, CKEY(m->b[disposition]), HKEY("filename"), '='); pch = strchr(m->b[disposition].Key, ';'); if (pch != NULL) *pch = '\0'; m->b[disposition].len = striplt(m->b[disposition].Key); } else if (!strncasecmp(header, "Content-ID:", 11)) { memcpy(m->b[id].Key, &header[11], headerlen - 11); m->b[id].Key[headerlen - 11] = '\0'; striplt(m->b[id].Key); m->b[id].len = stripallbut(m->b[id].Key, '<', '>'); } else if (!strncasecmp(header, "Content-length: ", 15)) { char *clbuf; clbuf = &header[15]; while (isspace(*clbuf)) clbuf ++; m->content_length = (size_t) atol(clbuf); } else if (!strncasecmp(header, "Content-transfer-encoding: ", 26)) { memcpy(m->b[encoding].Key, &header[26], headerlen - 26); m->b[encoding].Key[headerlen - 26] = '\0'; m->b[encoding].len = striplt(m->b[encoding].Key); } *header = '\0'; headerlen = 0; } if ((headerlen + buflen + 2) < SIZ) { memcpy(&header[headerlen], buf, buflen); headerlen += buflen; header[headerlen] = '\0'; } if (ptr >= content_end) { return -1; } } while ((!IsEmptyStr(buf)) && (*ptr != 0)); m->is_multipart = m->b[boundary].len != 0; *pcontent_start = ptr; return 0; }
/* * Split an RFC822-style address into userid, host, and full name * */ void process_rfc822_addr(const char *rfc822, char *user, char *node, char *name) { int a; strcpy(user, ""); strcpy(node, CtdlGetConfigStr("c_fqdn")); strcpy(name, ""); if (rfc822 == NULL) return; /* extract full name - first, it's From minus <userid> */ strcpy(name, rfc822); stripout(name, '<', '>'); /* strip anything to the left of a bang */ while ((!IsEmptyStr(name)) && (haschar(name, '!') > 0)) strcpy(name, &name[1]); /* and anything to the right of a @ or % */ for (a = 0; name[a] != '\0'; ++a) { if (name[a] == '@') { name[a] = 0; break; } if (name[a] == '%') { name[a] = 0; break; } } /* but if there are parentheses, that changes the rules... */ if ((haschar(rfc822, '(') == 1) && (haschar(rfc822, ')') == 1)) { strcpy(name, rfc822); stripallbut(name, '(', ')'); } /* but if there are a set of quotes, that supersedes everything */ if (haschar(rfc822, 34) == 2) { strcpy(name, rfc822); while ((!IsEmptyStr(name)) && (name[0] != 34)) { strcpy(&name[0], &name[1]); } strcpy(&name[0], &name[1]); for (a = 0; name[a] != '\0'; ++a) if (name[a] == 34) { name[a] = 0; break; } } /* extract user id */ strcpy(user, rfc822); /* first get rid of anything in parens */ stripout(user, '(', ')'); /* if there's a set of angle brackets, strip it down to that */ if ((haschar(user, '<') == 1) && (haschar(user, '>') == 1)) { stripallbut(user, '<', '>'); } /* strip anything to the left of a bang */ while ((!IsEmptyStr(user)) && (haschar(user, '!') > 0)) strcpy(user, &user[1]); /* and anything to the right of a @ or % */ for (a = 0; user[a] != '\0'; ++a) { if (user[a] == '@') { user[a] = 0; break; } if (user[a] == '%') { user[a] = 0; break; } } /* extract node name */ strcpy(node, rfc822); /* first get rid of anything in parens */ stripout(node, '(', ')'); /* if there's a set of angle brackets, strip it down to that */ if ((haschar(node, '<') == 1) && (haschar(node, '>') == 1)) { stripallbut(node, '<', '>'); } /* If no node specified, tack ours on instead */ if ( (haschar(node, '@')==0) && (haschar(node, '%')==0) && (haschar(node, '!')==0) ) { strcpy(node, CtdlGetConfigStr("c_nodename")); } else { /* strip anything to the left of a @ */ while ((!IsEmptyStr(node)) && (haschar(node, '@') > 0)) strcpy(node, &node[1]); /* strip anything to the left of a % */ while ((!IsEmptyStr(node)) && (haschar(node, '%') > 0)) strcpy(node, &node[1]); /* reduce multiple system bang paths to node!user */ while ((!IsEmptyStr(node)) && (haschar(node, '!') > 1)) strcpy(node, &node[1]); /* now get rid of the user portion of a node!user string */ for (a = 0; node[a] != '\0'; ++a) if (node[a] == '!') { node[a] = 0; break; } } /* strip leading and trailing spaces in all strings */ striplt(user); striplt(node); striplt(name); /* If we processed a string that had the address in angle brackets * 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 ((IsEmptyStr(name)) && (!IsEmptyStr(user))) { strcpy(name, user); } }