From b03aed62997f838e8b75d12839398a999a8f9183 Mon Sep 17 00:00:00 2001 From: Wilfried Goesgens Date: Sun, 1 Sep 2013 18:57:02 +0200 Subject: [PATCH] move email address related functions oven to internet_addressing --- citadel/internet_addressing.c | 638 ++++++++++++++++++++++++++++++++++ citadel/internet_addressing.h | 4 + citadel/msgbase.c | 629 --------------------------------- citadel/msgbase.h | 2 - 4 files changed, 642 insertions(+), 631 deletions(-) diff --git a/citadel/internet_addressing.c b/citadel/internet_addressing.c index 8d751d844..a1b0a37e1 100644 --- a/citadel/internet_addressing.c +++ b/citadel/internet_addressing.c @@ -326,8 +326,637 @@ int CtdlHostAlias(char *fqdn) { +/* + * Determine whether a given Internet address belongs to the current user + */ +int CtdlIsMe(char *addr, int addr_buf_len) +{ + struct recptypes *recp; + int i; + + recp = validate_recipients(addr, NULL, 0); + if (recp == NULL) return(0); + + if (recp->num_local == 0) { + free_recipients(recp); + return(0); + } + + for (i=0; inum_local; ++i) { + extract_token(addr, recp->recp_local, i, '|', addr_buf_len); + if (!strcasecmp(addr, CC->user.fullname)) { + free_recipients(recp); + return(1); + } + } + + free_recipients(recp); + return(0); +} + + +/* + * Citadel protocol command to do the same + */ +void cmd_isme(char *argbuf) { + char addr[256]; + + if (CtdlAccessCheck(ac_logged_in)) return; + extract_token(addr, argbuf, 0, '|', sizeof addr); + + if (CtdlIsMe(addr, sizeof addr)) { + cprintf("%d %s\n", CIT_OK, addr); + } + else { + cprintf("%d Not you.\n", ERROR + ILLEGAL_VALUE); + } + +} + + +/* If the last item in a list of recipients was truncated to a partial address, + * remove it completely in order to avoid choking libSieve + */ +void sanitize_truncated_recipient(char *str) +{ + if (!str) return; + if (num_tokens(str, ',') < 2) return; + + int len = strlen(str); + if (len < 900) return; + if (len > 998) str[998] = 0; + + char *cptr = strrchr(str, ','); + if (!cptr) return; + + char *lptr = strchr(cptr, '<'); + char *rptr = strchr(cptr, '>'); + + if ( (lptr) && (rptr) && (rptr > lptr) ) return; + + *cptr = 0; +} + + + + + +/* + * This function is self explanatory. + * (What can I say, I'm in a weird mood today...) + */ +void remove_any_whitespace_to_the_left_or_right_of_at_symbol(char *name) +{ + int i; + + for (i = 0; i < strlen(name); ++i) { + if (name[i] == '@') { + while (isspace(name[i - 1]) && i > 0) { + strcpy(&name[i - 1], &name[i]); + --i; + } + while (isspace(name[i + 1])) { + strcpy(&name[i + 1], &name[i + 2]); + } + } + } +} + + +/* + * 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; a < strlen(aaa); ++a) { + if (aaa[a] == ',') { + strcpy(bbb, &aaa[a + 1]); + aaa[a] = 0; + } + } + 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; a\n", name); + } + } + } + + /* 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; inum_error = -1 if no addresses + * were specified, or the number of addresses found invalid. + * + * Caller needs to free the result using free_recipients() + */ +struct recptypes *validate_recipients(const char *supplied_recipients, + const char *RemoteIdentifier, + int Flags) { + struct CitContext *CCC = CC; + struct recptypes *ret; + char *recipients = NULL; + char *org_recp; + char this_recp[256]; + char this_recp_cooked[256]; + char append[SIZ]; + long len; + int num_recps = 0; + int i, j; + int mailtype; + int invalid; + struct ctdluser tempUS; + struct ctdlroom tempQR; + struct ctdlroom tempQR2; + int err = 0; + char errmsg[SIZ]; + int in_quotes = 0; + + /* Initialize */ + ret = (struct recptypes *) malloc(sizeof(struct recptypes)); + if (ret == NULL) return(NULL); + + /* Set all strings to null and numeric values to zero */ + memset(ret, 0, sizeof(struct recptypes)); + + if (supplied_recipients == NULL) { + recipients = strdup(""); + } + else { + recipients = strdup(supplied_recipients); + } + + /* Allocate some memory. Yes, this allocates 500% more memory than we will + * actually need, but it's healthier for the heap than doing lots of tiny + * realloc() calls instead. + */ + len = strlen(recipients) + 1024; + ret->errormsg = malloc(len); + ret->recp_local = malloc(len); + ret->recp_internet = malloc(len); + ret->recp_ignet = malloc(len); + ret->recp_room = malloc(len); + ret->display_recp = malloc(len); + ret->recp_orgroom = malloc(len); + org_recp = malloc(len); + + ret->errormsg[0] = 0; + ret->recp_local[0] = 0; + ret->recp_internet[0] = 0; + ret->recp_ignet[0] = 0; + ret->recp_room[0] = 0; + ret->recp_orgroom[0] = 0; + ret->display_recp[0] = 0; + + ret->recptypes_magic = RECPTYPES_MAGIC; + + /* Change all valid separator characters to commas */ + for (i=0; !IsEmptyStr(&recipients[i]); ++i) { + if ((recipients[i] == ';') || (recipients[i] == '|')) { + recipients[i] = ','; + } + } + + /* Now start extracting recipients... */ + + while (!IsEmptyStr(recipients)) { + for (i=0; i<=strlen(recipients); ++i) { + if (recipients[i] == '\"') in_quotes = 1 - in_quotes; + if ( ( (recipients[i] == ',') && (!in_quotes) ) || (recipients[i] == 0) ) { + safestrncpy(this_recp, recipients, i+1); + this_recp[i] = 0; + if (recipients[i] == ',') { + strcpy(recipients, &recipients[i+1]); + } + else { + strcpy(recipients, ""); + } + break; + } + } + + striplt(this_recp); + if (IsEmptyStr(this_recp)) + break; + MSG_syslog(LOG_DEBUG, "Evaluating recipient #%d: %s\n", num_recps, this_recp); + ++num_recps; + + strcpy(org_recp, this_recp); + alias(this_recp); + alias(this_recp); + mailtype = alias(this_recp); + + for (j = 0; !IsEmptyStr(&this_recp[j]); ++j) { + if (this_recp[j]=='_') { + this_recp_cooked[j] = ' '; + } + else { + this_recp_cooked[j] = this_recp[j]; + } + } + this_recp_cooked[j] = '\0'; + invalid = 0; + errmsg[0] = 0; + switch(mailtype) { + case MES_LOCAL: + if (!strcasecmp(this_recp, "sysop")) { + ++ret->num_room; + strcpy(this_recp, config.c_aideroom); + if (!IsEmptyStr(ret->recp_room)) { + strcat(ret->recp_room, "|"); + } + strcat(ret->recp_room, this_recp); + } + else if ( (!strncasecmp(this_recp, "room_", 5)) + && (!CtdlGetRoom(&tempQR, &this_recp_cooked[5])) ) { + /* Save room so we can restore it later */ + tempQR2 = CCC->room; + CCC->room = tempQR; + + /* Check permissions to send mail to this room */ + err = CtdlDoIHavePermissionToPostInThisRoom( + errmsg, + sizeof errmsg, + RemoteIdentifier, + Flags, + 0 /* 0 = not a reply */ + ); + if (err) + { + ++ret->num_error; + invalid = 1; + } + else { + ++ret->num_room; + if (!IsEmptyStr(ret->recp_room)) { + strcat(ret->recp_room, "|"); + } + strcat(ret->recp_room, &this_recp_cooked[5]); + if (!IsEmptyStr(ret->recp_orgroom)) { + strcat(ret->recp_orgroom, "|"); + } + strcat(ret->recp_orgroom, org_recp); + + } + + /* Restore room in case something needs it */ + CCC->room = tempQR2; + + } + else if (CtdlGetUser(&tempUS, this_recp) == 0) { + ++ret->num_local; + strcpy(this_recp, tempUS.fullname); + if (!IsEmptyStr(ret->recp_local)) { + strcat(ret->recp_local, "|"); + } + strcat(ret->recp_local, this_recp); + } + else if (CtdlGetUser(&tempUS, this_recp_cooked) == 0) { + ++ret->num_local; + strcpy(this_recp, tempUS.fullname); + if (!IsEmptyStr(ret->recp_local)) { + strcat(ret->recp_local, "|"); + } + strcat(ret->recp_local, this_recp); + } + else { + ++ret->num_error; + invalid = 1; + } + break; + case MES_INTERNET: + /* Yes, you're reading this correctly: if the target + * domain points back to the local system or an attached + * Citadel directory, the address is invalid. That's + * because if the address were valid, we would have + * already translated it to a local address by now. + */ + if (IsDirectory(this_recp, 0)) { + ++ret->num_error; + invalid = 1; + } + else { + ++ret->num_internet; + if (!IsEmptyStr(ret->recp_internet)) { + strcat(ret->recp_internet, "|"); + } + strcat(ret->recp_internet, this_recp); + } + break; + case MES_IGNET: + ++ret->num_ignet; + if (!IsEmptyStr(ret->recp_ignet)) { + strcat(ret->recp_ignet, "|"); + } + strcat(ret->recp_ignet, this_recp); + break; + case MES_ERROR: + ++ret->num_error; + invalid = 1; + break; + } + if (invalid) { + if (IsEmptyStr(errmsg)) { + snprintf(append, sizeof append, "Invalid recipient: %s", this_recp); + } + else { + snprintf(append, sizeof append, "%s", errmsg); + } + if ( (strlen(ret->errormsg) + strlen(append) + 3) < SIZ) { + if (!IsEmptyStr(ret->errormsg)) { + strcat(ret->errormsg, "; "); + } + strcat(ret->errormsg, append); + } + } + else { + if (IsEmptyStr(ret->display_recp)) { + strcpy(append, this_recp); + } + else { + snprintf(append, sizeof append, ", %s", this_recp); + } + if ( (strlen(ret->display_recp)+strlen(append)) < SIZ) { + strcat(ret->display_recp, append); + } + } + } + free(org_recp); + + if ((ret->num_local + ret->num_internet + ret->num_ignet + + ret->num_room + ret->num_error) == 0) { + ret->num_error = (-1); + strcpy(ret->errormsg, "No recipients specified."); + } + + MSGM_syslog(LOG_DEBUG, "validate_recipients()\n"); + MSG_syslog(LOG_DEBUG, " local: %d <%s>\n", ret->num_local, ret->recp_local); + MSG_syslog(LOG_DEBUG, " room: %d <%s>\n", ret->num_room, ret->recp_room); + MSG_syslog(LOG_DEBUG, " inet: %d <%s>\n", ret->num_internet, ret->recp_internet); + MSG_syslog(LOG_DEBUG, " ignet: %d <%s>\n", ret->num_ignet, ret->recp_ignet); + MSG_syslog(LOG_DEBUG, " error: %d <%s>\n", ret->num_error, ret->errormsg); + + free(recipients); + return(ret); +} + + +/* + * Destructor for struct recptypes + */ +void free_recipients(struct recptypes *valid) { + + if (valid == NULL) { + return; + } + + if (valid->recptypes_magic != RECPTYPES_MAGIC) { + struct CitContext *CCC = CC; + MSGM_syslog(LOG_EMERG, "Attempt to call free_recipients() on some other data type!\n"); + abort(); + } + + if (valid->errormsg != NULL) free(valid->errormsg); + if (valid->recp_local != NULL) free(valid->recp_local); + if (valid->recp_internet != NULL) free(valid->recp_internet); + if (valid->recp_ignet != NULL) free(valid->recp_ignet); + if (valid->recp_room != NULL) free(valid->recp_room); + if (valid->recp_orgroom != NULL) free(valid->recp_orgroom); + if (valid->display_recp != NULL) free(valid->display_recp); + if (valid->bounce_to != NULL) free(valid->bounce_to); + if (valid->envelope_from != NULL) free(valid->envelope_from); + if (valid->sending_room != NULL) free(valid->sending_room); + free(valid); +} + + +char *qp_encode_email_addrs(char *source) +{ + struct CitContext *CCC = CC; + char *user, *node, *name; + const char headerStr[] = "=?UTF-8?Q?"; + char *Encoded; + char *EncodedName; + char *nPtr; + int need_to_encode = 0; + long SourceLen; + long EncodedMaxLen; + long nColons = 0; + long *AddrPtr; + long *AddrUtf8; + long nAddrPtrMax = 50; + long nmax; + int InQuotes = 0; + int i, n; + + if (source == NULL) return source; + if (IsEmptyStr(source)) return source; + if (MessageDebugEnabled != 0) cit_backtrace(); + MSG_syslog(LOG_DEBUG, "qp_encode_email_addrs: [%s]\n", source); + + AddrPtr = malloc (sizeof (long) * nAddrPtrMax); + AddrUtf8 = malloc (sizeof (long) * nAddrPtrMax); + memset(AddrUtf8, 0, sizeof (long) * nAddrPtrMax); + *AddrPtr = 0; + i = 0; + while (!IsEmptyStr (&source[i])) { + if (nColons >= nAddrPtrMax){ + long *ptr; + + ptr = (long *) malloc(sizeof (long) * nAddrPtrMax * 2); + memcpy (ptr, AddrPtr, sizeof (long) * nAddrPtrMax); + free (AddrPtr), AddrPtr = ptr; + + ptr = (long *) malloc(sizeof (long) * nAddrPtrMax * 2); + memset(&ptr[nAddrPtrMax], 0, + sizeof (long) * nAddrPtrMax); + + memcpy (ptr, AddrUtf8, sizeof (long) * nAddrPtrMax); + free (AddrUtf8), AddrUtf8 = ptr; + nAddrPtrMax *= 2; + } + if (((unsigned char) source[i] < 32) || + ((unsigned char) source[i] > 126)) { + need_to_encode = 1; + AddrUtf8[nColons] = 1; + } + if (source[i] == '"') + InQuotes = !InQuotes; + if (!InQuotes && source[i] == ',') { + AddrPtr[nColons] = i; + nColons++; + } + i++; + } + if (need_to_encode == 0) { + free(AddrPtr); + free(AddrUtf8); + return source; + } + + SourceLen = i; + EncodedMaxLen = nColons * (sizeof(headerStr) + 3) + SourceLen * 3; + Encoded = (char*) malloc (EncodedMaxLen); + + for (i = 0; i < nColons; i++) + source[AddrPtr[i]++] = '\0'; + /* TODO: if libidn, this might get larger*/ + user = malloc(SourceLen + 1); + node = malloc(SourceLen + 1); + name = malloc(SourceLen + 1); + + nPtr = Encoded; + *nPtr = '\0'; + for (i = 0; i < nColons && nPtr != NULL; i++) { + nmax = EncodedMaxLen - (nPtr - Encoded); + if (AddrUtf8[i]) { + process_rfc822_addr(&source[AddrPtr[i]], + user, + node, + name); + /* TODO: libIDN here ! */ + if (IsEmptyStr(name)) { + n = snprintf(nPtr, nmax, + (i==0)?"%s@%s" : ",%s@%s", + user, node); + } + else { + EncodedName = rfc2047encode(name, strlen(name)); + n = snprintf(nPtr, nmax, + (i==0)?"%s <%s@%s>" : ",%s <%s@%s>", + EncodedName, user, node); + free(EncodedName); + } + } + else { + n = snprintf(nPtr, nmax, + (i==0)?"%s" : ",%s", + &source[AddrPtr[i]]); + } + if (n > 0 ) + nPtr += n; + else { + char *ptr, *nnPtr; + ptr = (char*) malloc(EncodedMaxLen * 2); + memcpy(ptr, Encoded, EncodedMaxLen); + nnPtr = ptr + (nPtr - Encoded), nPtr = nnPtr; + free(Encoded), Encoded = ptr; + EncodedMaxLen *= 2; + i--; /* do it once more with properly lengthened buffer */ + } + } + for (i = 0; i < nColons; i++) + source[--AddrPtr[i]] = ','; + + free(user); + free(node); + free(name); + free(AddrUtf8); + free(AddrPtr); + return Encoded; +} /* @@ -1074,3 +1703,12 @@ char *harvest_collected_addresses(struct CtdlMessage *msg) { } return(coll); } + + +CTDL_MODULE_INIT(internet_addressing) +{ + if (!threading) { + CtdlRegisterProtoHook(cmd_isme, "ISME", "Determine whether an email address belongs to a user"); + } + return "internet_addressing"; +} diff --git a/citadel/internet_addressing.h b/citadel/internet_addressing.h index 706231e83..5f59ac951 100644 --- a/citadel/internet_addressing.h +++ b/citadel/internet_addressing.h @@ -12,6 +12,10 @@ struct internet_address_list { int fuzzy_match(struct ctdluser *us, char *matchstring); void process_rfc822_addr(const char *rfc822, char *user, char *node, char *name); char *rfc822_fetch_field(const char *rfc822, const char *fieldname); +void sanitize_truncated_recipient(char *str); +char *qp_encode_email_addrs(char *source); +int alias (char *name); + int IsDirectory(char *addr, int allow_masq_domains); void CtdlDirectoryInit(void); diff --git a/citadel/msgbase.c b/citadel/msgbase.c index 052f06fca..f079bdcdc 100644 --- a/citadel/msgbase.c +++ b/citadel/msgbase.c @@ -352,145 +352,6 @@ struct CtdlMessage * CM_Duplicate(struct CtdlMessage *OrgMsg) -/* - * This function is self explanatory. - * (What can I say, I'm in a weird mood today...) - */ -void remove_any_whitespace_to_the_left_or_right_of_at_symbol(char *name) -{ - int i; - - for (i = 0; i < strlen(name); ++i) { - if (name[i] == '@') { - while (isspace(name[i - 1]) && i > 0) { - strcpy(&name[i - 1], &name[i]); - --i; - } - while (isspace(name[i + 1])) { - strcpy(&name[i + 1], &name[i + 2]); - } - } - } -} - - -/* - * 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; a < strlen(aaa); ++a) { - if (aaa[a] == ',') { - strcpy(bbb, &aaa[a + 1]); - aaa[a] = 0; - } - } - 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; a\n", name); - } - } - } - - /* 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= nAddrPtrMax){ - long *ptr; - - ptr = (long *) malloc(sizeof (long) * nAddrPtrMax * 2); - memcpy (ptr, AddrPtr, sizeof (long) * nAddrPtrMax); - free (AddrPtr), AddrPtr = ptr; - - ptr = (long *) malloc(sizeof (long) * nAddrPtrMax * 2); - memset(&ptr[nAddrPtrMax], 0, - sizeof (long) * nAddrPtrMax); - - memcpy (ptr, AddrUtf8, sizeof (long) * nAddrPtrMax); - free (AddrUtf8), AddrUtf8 = ptr; - nAddrPtrMax *= 2; - } - if (((unsigned char) source[i] < 32) || - ((unsigned char) source[i] > 126)) { - need_to_encode = 1; - AddrUtf8[nColons] = 1; - } - if (source[i] == '"') - InQuotes = !InQuotes; - if (!InQuotes && source[i] == ',') { - AddrPtr[nColons] = i; - nColons++; - } - i++; - } - if (need_to_encode == 0) { - free(AddrPtr); - free(AddrUtf8); - return source; - } - - SourceLen = i; - EncodedMaxLen = nColons * (sizeof(headerStr) + 3) + SourceLen * 3; - Encoded = (char*) malloc (EncodedMaxLen); - - for (i = 0; i < nColons; i++) - source[AddrPtr[i]++] = '\0'; - /* TODO: if libidn, this might get larger*/ - user = malloc(SourceLen + 1); - node = malloc(SourceLen + 1); - name = malloc(SourceLen + 1); - - nPtr = Encoded; - *nPtr = '\0'; - for (i = 0; i < nColons && nPtr != NULL; i++) { - nmax = EncodedMaxLen - (nPtr - Encoded); - if (AddrUtf8[i]) { - process_rfc822_addr(&source[AddrPtr[i]], - user, - node, - name); - /* TODO: libIDN here ! */ - if (IsEmptyStr(name)) { - n = snprintf(nPtr, nmax, - (i==0)?"%s@%s" : ",%s@%s", - user, node); - } - else { - EncodedName = rfc2047encode(name, strlen(name)); - n = snprintf(nPtr, nmax, - (i==0)?"%s <%s@%s>" : ",%s <%s@%s>", - EncodedName, user, node); - free(EncodedName); - } - } - else { - n = snprintf(nPtr, nmax, - (i==0)?"%s" : ",%s", - &source[AddrPtr[i]]); - } - if (n > 0 ) - nPtr += n; - else { - char *ptr, *nnPtr; - ptr = (char*) malloc(EncodedMaxLen * 2); - memcpy(ptr, Encoded, EncodedMaxLen); - nnPtr = ptr + (nPtr - Encoded), nPtr = nnPtr; - free(Encoded), Encoded = ptr; - EncodedMaxLen *= 2; - i--; /* do it once more with properly lengthened buffer */ - } - } - for (i = 0; i < nColons; i++) - source[--AddrPtr[i]] = ','; - - free(user); - free(node); - free(name); - free(AddrUtf8); - free(AddrPtr); - return Encoded; -} - - -/* If the last item in a list of recipients was truncated to a partial address, - * remove it completely in order to avoid choking libSieve - */ -void sanitize_truncated_recipient(char *str) -{ - if (!str) return; - if (num_tokens(str, ',') < 2) return; - - int len = strlen(str); - if (len < 900) return; - if (len > 998) str[998] = 0; - - char *cptr = strrchr(str, ','); - if (!cptr) return; - - char *lptr = strchr(cptr, '<'); - char *rptr = strchr(cptr, '>'); - - if ( (lptr) && (rptr) && (rptr > lptr) ) return; - - *cptr = 0; -} - void OutputCtdlMsgHeaders( struct CtdlMessage *TheMessage, @@ -4170,298 +3881,6 @@ struct CtdlMessage *CtdlMakeMessage( -/* - * Validate recipients, count delivery types and errors, and handle aliasing - * FIXME check for dupes!!!!! - * - * Returns 0 if all addresses are ok, ret->num_error = -1 if no addresses - * were specified, or the number of addresses found invalid. - * - * Caller needs to free the result using free_recipients() - */ -struct recptypes *validate_recipients(const char *supplied_recipients, - const char *RemoteIdentifier, - int Flags) { - struct CitContext *CCC = CC; - struct recptypes *ret; - char *recipients = NULL; - char *org_recp; - char this_recp[256]; - char this_recp_cooked[256]; - char append[SIZ]; - long len; - int num_recps = 0; - int i, j; - int mailtype; - int invalid; - struct ctdluser tempUS; - struct ctdlroom tempQR; - struct ctdlroom tempQR2; - int err = 0; - char errmsg[SIZ]; - int in_quotes = 0; - - /* Initialize */ - ret = (struct recptypes *) malloc(sizeof(struct recptypes)); - if (ret == NULL) return(NULL); - - /* Set all strings to null and numeric values to zero */ - memset(ret, 0, sizeof(struct recptypes)); - - if (supplied_recipients == NULL) { - recipients = strdup(""); - } - else { - recipients = strdup(supplied_recipients); - } - - /* Allocate some memory. Yes, this allocates 500% more memory than we will - * actually need, but it's healthier for the heap than doing lots of tiny - * realloc() calls instead. - */ - len = strlen(recipients) + 1024; - ret->errormsg = malloc(len); - ret->recp_local = malloc(len); - ret->recp_internet = malloc(len); - ret->recp_ignet = malloc(len); - ret->recp_room = malloc(len); - ret->display_recp = malloc(len); - ret->recp_orgroom = malloc(len); - org_recp = malloc(len); - - ret->errormsg[0] = 0; - ret->recp_local[0] = 0; - ret->recp_internet[0] = 0; - ret->recp_ignet[0] = 0; - ret->recp_room[0] = 0; - ret->recp_orgroom[0] = 0; - ret->display_recp[0] = 0; - - ret->recptypes_magic = RECPTYPES_MAGIC; - - /* Change all valid separator characters to commas */ - for (i=0; !IsEmptyStr(&recipients[i]); ++i) { - if ((recipients[i] == ';') || (recipients[i] == '|')) { - recipients[i] = ','; - } - } - - /* Now start extracting recipients... */ - - while (!IsEmptyStr(recipients)) { - for (i=0; i<=strlen(recipients); ++i) { - if (recipients[i] == '\"') in_quotes = 1 - in_quotes; - if ( ( (recipients[i] == ',') && (!in_quotes) ) || (recipients[i] == 0) ) { - safestrncpy(this_recp, recipients, i+1); - this_recp[i] = 0; - if (recipients[i] == ',') { - strcpy(recipients, &recipients[i+1]); - } - else { - strcpy(recipients, ""); - } - break; - } - } - - striplt(this_recp); - if (IsEmptyStr(this_recp)) - break; - MSG_syslog(LOG_DEBUG, "Evaluating recipient #%d: %s\n", num_recps, this_recp); - ++num_recps; - - strcpy(org_recp, this_recp); - alias(this_recp); - alias(this_recp); - mailtype = alias(this_recp); - - for (j = 0; !IsEmptyStr(&this_recp[j]); ++j) { - if (this_recp[j]=='_') { - this_recp_cooked[j] = ' '; - } - else { - this_recp_cooked[j] = this_recp[j]; - } - } - this_recp_cooked[j] = '\0'; - invalid = 0; - errmsg[0] = 0; - switch(mailtype) { - case MES_LOCAL: - if (!strcasecmp(this_recp, "sysop")) { - ++ret->num_room; - strcpy(this_recp, config.c_aideroom); - if (!IsEmptyStr(ret->recp_room)) { - strcat(ret->recp_room, "|"); - } - strcat(ret->recp_room, this_recp); - } - else if ( (!strncasecmp(this_recp, "room_", 5)) - && (!CtdlGetRoom(&tempQR, &this_recp_cooked[5])) ) { - - /* Save room so we can restore it later */ - tempQR2 = CCC->room; - CCC->room = tempQR; - - /* Check permissions to send mail to this room */ - err = CtdlDoIHavePermissionToPostInThisRoom( - errmsg, - sizeof errmsg, - RemoteIdentifier, - Flags, - 0 /* 0 = not a reply */ - ); - if (err) - { - ++ret->num_error; - invalid = 1; - } - else { - ++ret->num_room; - if (!IsEmptyStr(ret->recp_room)) { - strcat(ret->recp_room, "|"); - } - strcat(ret->recp_room, &this_recp_cooked[5]); - - if (!IsEmptyStr(ret->recp_orgroom)) { - strcat(ret->recp_orgroom, "|"); - } - strcat(ret->recp_orgroom, org_recp); - - } - - /* Restore room in case something needs it */ - CCC->room = tempQR2; - - } - else if (CtdlGetUser(&tempUS, this_recp) == 0) { - ++ret->num_local; - strcpy(this_recp, tempUS.fullname); - if (!IsEmptyStr(ret->recp_local)) { - strcat(ret->recp_local, "|"); - } - strcat(ret->recp_local, this_recp); - } - else if (CtdlGetUser(&tempUS, this_recp_cooked) == 0) { - ++ret->num_local; - strcpy(this_recp, tempUS.fullname); - if (!IsEmptyStr(ret->recp_local)) { - strcat(ret->recp_local, "|"); - } - strcat(ret->recp_local, this_recp); - } - else { - ++ret->num_error; - invalid = 1; - } - break; - case MES_INTERNET: - /* Yes, you're reading this correctly: if the target - * domain points back to the local system or an attached - * Citadel directory, the address is invalid. That's - * because if the address were valid, we would have - * already translated it to a local address by now. - */ - if (IsDirectory(this_recp, 0)) { - ++ret->num_error; - invalid = 1; - } - else { - ++ret->num_internet; - if (!IsEmptyStr(ret->recp_internet)) { - strcat(ret->recp_internet, "|"); - } - strcat(ret->recp_internet, this_recp); - } - break; - case MES_IGNET: - ++ret->num_ignet; - if (!IsEmptyStr(ret->recp_ignet)) { - strcat(ret->recp_ignet, "|"); - } - strcat(ret->recp_ignet, this_recp); - break; - case MES_ERROR: - ++ret->num_error; - invalid = 1; - break; - } - if (invalid) { - if (IsEmptyStr(errmsg)) { - snprintf(append, sizeof append, "Invalid recipient: %s", this_recp); - } - else { - snprintf(append, sizeof append, "%s", errmsg); - } - if ( (strlen(ret->errormsg) + strlen(append) + 3) < SIZ) { - if (!IsEmptyStr(ret->errormsg)) { - strcat(ret->errormsg, "; "); - } - strcat(ret->errormsg, append); - } - } - else { - if (IsEmptyStr(ret->display_recp)) { - strcpy(append, this_recp); - } - else { - snprintf(append, sizeof append, ", %s", this_recp); - } - if ( (strlen(ret->display_recp)+strlen(append)) < SIZ) { - strcat(ret->display_recp, append); - } - } - } - free(org_recp); - - if ((ret->num_local + ret->num_internet + ret->num_ignet + - ret->num_room + ret->num_error) == 0) { - ret->num_error = (-1); - strcpy(ret->errormsg, "No recipients specified."); - } - - MSGM_syslog(LOG_DEBUG, "validate_recipients()\n"); - MSG_syslog(LOG_DEBUG, " local: %d <%s>\n", ret->num_local, ret->recp_local); - MSG_syslog(LOG_DEBUG, " room: %d <%s>\n", ret->num_room, ret->recp_room); - MSG_syslog(LOG_DEBUG, " inet: %d <%s>\n", ret->num_internet, ret->recp_internet); - MSG_syslog(LOG_DEBUG, " ignet: %d <%s>\n", ret->num_ignet, ret->recp_ignet); - MSG_syslog(LOG_DEBUG, " error: %d <%s>\n", ret->num_error, ret->errormsg); - - free(recipients); - return(ret); -} - - -/* - * Destructor for struct recptypes - */ -void free_recipients(struct recptypes *valid) { - - if (valid == NULL) { - return; - } - - if (valid->recptypes_magic != RECPTYPES_MAGIC) { - struct CitContext *CCC = CC; - MSGM_syslog(LOG_EMERG, "Attempt to call free_recipients() on some other data type!\n"); - abort(); - } - - if (valid->errormsg != NULL) free(valid->errormsg); - if (valid->recp_local != NULL) free(valid->recp_local); - if (valid->recp_internet != NULL) free(valid->recp_internet); - if (valid->recp_ignet != NULL) free(valid->recp_ignet); - if (valid->recp_room != NULL) free(valid->recp_room); - if (valid->recp_orgroom != NULL) free(valid->recp_orgroom); - if (valid->display_recp != NULL) free(valid->display_recp); - if (valid->bounce_to != NULL) free(valid->bounce_to); - if (valid->envelope_from != NULL) free(valid->envelope_from); - if (valid->sending_room != NULL) free(valid->sending_room); - free(valid); -} - - - /* * message entry - mode 0 (normal) */ @@ -5513,53 +4932,6 @@ void CtdlPutSysConfig(char *sysconfname, char *sysconfdata) { } -/* - * Determine whether a given Internet address belongs to the current user - */ -int CtdlIsMe(char *addr, int addr_buf_len) -{ - struct recptypes *recp; - int i; - - recp = validate_recipients(addr, NULL, 0); - if (recp == NULL) return(0); - - if (recp->num_local == 0) { - free_recipients(recp); - return(0); - } - - for (i=0; inum_local; ++i) { - extract_token(addr, recp->recp_local, i, '|', addr_buf_len); - if (!strcasecmp(addr, CC->user.fullname)) { - free_recipients(recp); - return(1); - } - } - - free_recipients(recp); - return(0); -} - - -/* - * Citadel protocol command to do the same - */ -void cmd_isme(char *argbuf) { - char addr[256]; - - if (CtdlAccessCheck(ac_logged_in)) return; - extract_token(addr, argbuf, 0, '|', sizeof addr); - - if (CtdlIsMe(addr, sizeof addr)) { - cprintf("%d %s\n", CIT_OK, addr); - } - else { - cprintf("%d Not you.\n", ERROR + ILLEGAL_VALUE); - } - -} - /*****************************************************************************/ /* MODULE INITIALIZATION STUFF */ @@ -5584,7 +4956,6 @@ CTDL_MODULE_INIT(msgbase) CtdlRegisterProtoHook(cmd_ent0, "ENT0", "Enter a message"); CtdlRegisterProtoHook(cmd_dele, "DELE", "Delete a message"); CtdlRegisterProtoHook(cmd_move, "MOVE", "Move or copy a message to another room"); - CtdlRegisterProtoHook(cmd_isme, "ISME", "Determine whether an email address belongs to a user"); } /* return our Subversion id for the Log */ diff --git a/citadel/msgbase.h b/citadel/msgbase.h index 11a46d6ea..1d01a24e1 100644 --- a/citadel/msgbase.h +++ b/citadel/msgbase.h @@ -94,9 +94,7 @@ struct addresses_to_be_filed { extern struct addresses_to_be_filed *atbf; -int alias (char *name); void cmd_msgs (char *cmdbuf); -void cmd_isme (char *cmdbuf); void memfmout (char *mptr, const char *nl); void output_mime_parts(char *); -- 2.30.2