+ len = strlen(recipients) + 1024; // allocate memory
+ ret->errormsg = malloc(len);
+ ret->recp_local = malloc(len);
+ ret->recp_internet = malloc(len);
+ ret->recp_room = malloc(len);
+ ret->display_recp = malloc(len);
+ ret->recp_orgroom = malloc(len);
+
+ ret->errormsg[0] = 0;
+ ret->recp_local[0] = 0;
+ ret->recp_internet[0] = 0;
+ ret->recp_room[0] = 0;
+ ret->recp_orgroom[0] = 0;
+ ret->display_recp[0] = 0;
+ ret->recptypes_magic = RECPTYPES_MAGIC;
+
+ Array *recp_array = split_recps(supplied_recipients, NULL);
+
+ char *aliases = CtdlGetSysConfig(GLOBAL_ALIASES); // First hit the Global Alias Table
+
+ int r;
+ for (r=0; (recp_array && r<array_len(recp_array)); ++r) {
+ org_recp = (char *)array_get_element_at(recp_array, r);
+ strncpy(this_recp, org_recp, sizeof this_recp);
+
+ int i;
+ for (i=0; i<3; ++i) { // pass three times through the aliaser
+ mailtype = expand_aliases(this_recp, aliases);
+
+ // If an alias expanded to multiple recipients, strip off those recipients and append them
+ // to the end of the array. This loop will hit those again when it gets there.
+ if (mailtype == EA_MULTIPLE) {
+ recp_array = split_recps(this_recp, recp_array);
+ }
+ }
+
+ // This loop searches for duplicate recipients in the final list and marks them to be skipped.
+ int j;
+ for (j=0; j<r; ++j) {
+ if (!strcasecmp(this_recp, (char *)array_get_element_at(recp_array, j) )) {
+ mailtype = EA_SKIP;
+ }
+ }
+
+ syslog(LOG_DEBUG, "Recipient #%d of type %d is <%s>", r, mailtype, this_recp);
+ invalid = 0;
+ errmsg[0] = 0;
+ switch(mailtype) {
+ case EA_LOCAL: // There are several types of "local" recipients.
+
+ // Old BBS conventions require mail to "sysop" to go somewhere. Send it to the admin room.
+ if (!strcasecmp(this_recp, "sysop")) {
+ ++ret->num_room;
+ strcpy(this_recp, CtdlGetConfigStr("c_aideroom"));
+ if (!IsEmptyStr(ret->recp_room)) {
+ strcat(ret->recp_room, "|");
+ }
+ strcat(ret->recp_room, this_recp);
+ }
+
+ // This handles rooms which can receive posts via email.
+ else if (!strncasecmp(this_recp, "room_", 5)) {
+ original_room = CC->room; // Remember where we parked
+
+ char mail_to_room[ROOMNAMELEN];
+ char *m;
+ strncpy(mail_to_room, &this_recp[5], sizeof mail_to_room);
+ for (m = mail_to_room; *m; ++m) {
+ if (m[0] == '_') m[0]=' ';
+ }
+ if (!CtdlGetRoom(&CC->room, mail_to_room)) { // Find the room they asked for
+
+ err = CtdlDoIHavePermissionToPostInThisRoom( // check for write permissions to room
+ errmsg,
+ sizeof errmsg,
+ RemoteIdentifier,
+ Flags,
+ 0 // 0 means "this is 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, CC->room.QRname);
+
+ if (!IsEmptyStr(ret->recp_orgroom)) {
+ strcat(ret->recp_orgroom, "|");
+ }
+ strcat(ret->recp_orgroom, this_recp);
+
+ }
+ }
+ else { // no such room exists
+ ++ret->num_error;
+ invalid = 1;
+ }
+
+ // Restore this session's original room location.
+ CC->room = original_room;
+
+ }
+
+ // This handles the most common case, which is mail to a user's inbox.
+ 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);
+ }
+
+ // No match for this recipient
+ else {
+ ++ret->num_error;
+ invalid = 1;
+ }
+ break;
+ case EA_INTERNET:
+ // Yes, you're reading this correctly: if the target domain points back to the local system,
+ // 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 EA_MULTIPLE:
+ case EA_SKIP:
+ // no action required, anything in this slot has already been processed elsewhere
+ break;
+ case EA_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);
+ }
+ }
+ }
+
+ if (aliases != NULL) { // ok, we're done with the global alias list now
+ free(aliases);
+ }
+
+ if ( (ret->num_local + ret->num_internet + ret->num_room + ret->num_error) == 0) {
+ ret->num_error = (-1);
+ strcpy(ret->errormsg, "No recipients specified.");
+ }
+
+ syslog(LOG_DEBUG, "internet_addressing: validate_recipients() = %d local, %d room, %d SMTP, %d error",
+ ret->num_local, ret->num_room, ret->num_internet, ret->num_error
+ );
+
+ free(recipients);
+ if (recp_array) {
+ array_free(recp_array);
+ }
+
+ return(ret);
+}
+
+
+// Destructor for recptypes
+void free_recipients(struct recptypes *valid) {
+
+ if (valid == NULL) {
+ return;
+ }
+
+ if (valid->recptypes_magic != RECPTYPES_MAGIC) {
+ syslog(LOG_ERR, "internet_addressing: attempt to call free_recipients() on some other data type!");
+ abort();