+
+
+/*
+ * 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;
+ eMsgField field = 0;
+
+ if (msg == NULL) return(NULL);
+
+ is_harvestable = 1;
+ strcpy(addr, "");
+ if (!CM_IsEmpty(msg, eAuthor)) {
+ strcat(addr, msg->cm_fields[eAuthor]);
+ }
+ if (!CM_IsEmpty(msg, erFc822Addr)) {
+ strcat(addr, " <");
+ strcat(addr, msg->cm_fields[erFc822Addr]);
+ strcat(addr, ">");
+ if (IsDirectory(msg->cm_fields[erFc822Addr], 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 = eRecipient;
+ if (i == 1) field = eCarbonCopY;
+
+ if (!CM_IsEmpty(msg, field)) {
+ for (j=0; j<num_tokens(msg->cm_fields[field], ','); ++j) {
+ extract_token(addr, msg->cm_fields[field], j, ',', sizeof addr);
+ if (strstr(addr, "=?") != NULL)
+ utf8ify_rfc822_string(addr);
+ process_rfc822_addr(addr, user, node, name);
+ h = CtdlHostAlias(node);
+ if (h != hostalias_localhost) {
+ 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);
+}
+
+
+/*
+ * Helper function for CtdlRebuildDirectoryIndex()
+ *
+ * Call this function as a ForEachUser backend in order to queue up
+ * user names, or call it with a null user to make it do the processing.
+ * This allows us to maintain the list as a static instead of passing
+ * pointers around.
+ */
+void CtdlRebuildDirectoryIndex_backend(struct ctdluser *usbuf, void *data) {
+
+ struct crdib {
+ char name[64];
+ char emails[512];
+ };
+
+ static struct crdib *e = NULL;
+ static int num_e = 0;
+ static int alloc_e = 0;
+
+ /* this is the calling mode where we add a user */
+
+ if (usbuf != NULL) {
+ if (num_e >= alloc_e) {
+ if (alloc_e == 0) {
+ alloc_e = 100;
+ e = malloc(sizeof(struct crdib) * alloc_e);
+ }
+ else {
+ alloc_e *= 2;
+ e = realloc(e, (sizeof(struct crdib) * alloc_e));
+ }
+ }
+ strcpy(e[num_e].name, usbuf->fullname);
+ strcpy(e[num_e].emails, usbuf->emailaddrs);
+ ++num_e;
+ return;
+ }
+
+ /* this is the calling mode where we do the processing */
+
+ int i, j;
+ for (i=0; i<num_e; ++i) {
+ if ( (!IsEmptyStr(e[i].name)) && (!IsEmptyStr(e[i].emails)) ) {
+ for (j=0; j<num_tokens(e[i].emails, '|'); ++j) {
+ char one_email[512];
+ extract_token(one_email, e[i].emails, j, '|', sizeof one_email);
+ CtdlDirectoryAddUser(one_email, e[i].name);
+ }
+ }
+ }
+ free(e);
+ num_e = 0;
+ alloc_e = 0;
+ return;
+}
+
+
+/*
+ * Initialize the directory database (erasing anything already there)
+ */
+void CtdlRebuildDirectoryIndex(void) {
+ syslog(LOG_INFO, "internet_addressing: rebuilding email address directory index");
+ cdb_trunc(CDB_DIRECTORY);
+ ForEachUser(CtdlRebuildDirectoryIndex_backend, NULL);
+ CtdlRebuildDirectoryIndex_backend(NULL, NULL);
+}
+
+
+/*
+ * Configure Internet email addresses for a user account, updating the Directory Index in the process
+ */
+void CtdlSetEmailAddressesForUser(char *requested_user, char *new_emailaddrs)
+{
+ struct ctdluser usbuf;
+ int i;
+ char buf[SIZ];
+
+ if (CtdlGetUserLock(&usbuf, requested_user) != 0) { // We are relying on the fact that the DirectoryIndex functions don't lock.
+ return; // Silently fail here if we can't acquire a lock on the user record.
+ }
+
+ syslog(LOG_DEBUG, "internet_addressing: setting email addresses for <%s> to <%s>", usbuf.fullname, new_emailaddrs);
+
+ /* Delete all of the existing directory index records for the user (easier this way) */
+ for (i=0; i<num_tokens(usbuf.emailaddrs, '|'); ++i) {
+ extract_token(buf, usbuf.emailaddrs, i, '|', sizeof buf);
+ CtdlDirectoryDelUser(buf, requested_user);
+ }
+
+ strcpy(usbuf.emailaddrs, new_emailaddrs); // make it official.
+
+ /* Index all of the new email addresses (they've already been sanitized) */
+ for (i=0; i<num_tokens(usbuf.emailaddrs, '|'); ++i) {
+ extract_token(buf, usbuf.emailaddrs, i, '|', sizeof buf);
+ CtdlDirectoryAddUser(buf, requested_user);
+ }
+
+ CtdlPutUserLock(&usbuf);
+}
+
+
+/*
+ * Auto-generate an Internet email address for a user account
+ */
+void AutoGenerateEmailAddressForUser(struct ctdluser *user)
+{
+ char synthetic_email_addr[1024];
+ int i, j;
+ int u = 0;
+
+ for (i=0; u==0; ++i) {
+ if (i == 0) {
+ // first try just converting the user name to lowercase and replacing spaces with underscores
+ snprintf(synthetic_email_addr, sizeof synthetic_email_addr, "%s@%s", user->fullname, CtdlGetConfigStr("c_fqdn"));
+ for (j=0; ((synthetic_email_addr[j] != '\0')&&(synthetic_email_addr[j] != '@')); j++) {
+ synthetic_email_addr[j] = tolower(synthetic_email_addr[j]);
+ if (!isalnum(synthetic_email_addr[j])) {
+ synthetic_email_addr[j] = '_';
+ }
+ }
+ }
+ else if (i == 1) {
+ // then try 'ctdl' followed by the user number
+ snprintf(synthetic_email_addr, sizeof synthetic_email_addr, "ctdl%08lx@%s", user->usernum, CtdlGetConfigStr("c_fqdn"));
+ }
+ else if (i > 1) {
+ // oof. just keep trying other numbers until we find one
+ snprintf(synthetic_email_addr, sizeof synthetic_email_addr, "ctdl%08x@%s", i, CtdlGetConfigStr("c_fqdn"));
+ }
+ u = CtdlDirectoryLookup(NULL, synthetic_email_addr, 0);
+ }
+
+ CtdlSetEmailAddressesForUser(user->fullname, synthetic_email_addr);
+ strncpy(CC->user.emailaddrs, synthetic_email_addr, sizeof(user->emailaddrs));
+ syslog(LOG_DEBUG, "user_ops: auto-generated email address <%s> for <%s>", synthetic_email_addr, user->fullname);
+}