+
+
+/*
+ * Look for a particular header field in an RFC822 message text. If the
+ * requested field is found, it is unfolded (if necessary) and returned to
+ * the caller. The field name is stripped out, leaving only its contents.
+ * The caller is responsible for freeing the returned buffer. If the requested
+ * field is not present, or anything else goes wrong, it returns NULL.
+ */
+char *rfc822_fetch_field(const char *rfc822, const char *fieldname) {
+ char *fieldbuf = NULL;
+ const char *end_of_headers;
+ const char *field_start;
+ const 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);
+
+ snprintf(fieldhdr, sizeof fieldhdr, "%s:", fieldname);
+
+ /* Locate the end of the headers, so we don't run past that point */
+ end_of_headers = cbmstrcasestr(rfc822, "\n\r\n");
+ if (end_of_headers == NULL) {
+ end_of_headers = cbmstrcasestr(rfc822, "\n\n");
+ }
+ if (end_of_headers == NULL) return (NULL);
+
+ field_start = cbmstrcasestr(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 = cmemreadline(ptr, fieldbuf, SIZ-strlen(fieldbuf) );
+ while ( (isspace(ptr[0])) && (ptr < end_of_headers) ) {
+ strcat(fieldbuf, " ");
+ cont = &fieldbuf[strlen(fieldbuf)];
+ ptr = cmemreadline(ptr, cont, SIZ-strlen(fieldbuf) );
+ striplt(cont);
+ }
+
+ strcpy(fieldbuf, &fieldbuf[strlen(fieldhdr)]);
+ striplt(fieldbuf);
+
+ return(fieldbuf);
+}
+
+
+
+/*****************************************************************************
+ * DIRECTORY MANAGEMENT FUNCTIONS *
+ *****************************************************************************/
+
+/*
+ * Generate the index key for an Internet e-mail address to be looked up
+ * in the database.
+ */
+void directory_key(char *key, char *addr) {
+ int i;
+ int keylen = 0;
+
+ for (i=0; !IsEmptyStr(&addr[i]); ++i) {
+ if (!isspace(addr[i])) {
+ key[keylen++] = tolower(addr[i]);
+ }
+ }
+ key[keylen++] = 0;
+
+ syslog(LOG_DEBUG, "Directory key is <%s>\n", key);
+}
+
+
+
+/* Return nonzero if the supplied address is in a domain we keep in
+ * the directory
+ */
+int IsDirectory(char *addr, int allow_masq_domains) {
+ char domain[256];
+ int h;
+
+ extract_token(domain, addr, 1, '@', sizeof domain);
+ striplt(domain);
+
+ h = CtdlHostAlias(domain);
+
+ if ( (h == hostalias_masq) && allow_masq_domains)
+ return(1);
+
+ if ( (h == hostalias_localhost) || (h == hostalias_directory) ) {
+ return(1);
+ }
+ else {
+ return(0);
+ }
+}
+
+
+/*
+ * Initialize the directory database (erasing anything already there)
+ */
+void CtdlDirectoryInit(void) {
+ cdb_trunc(CDB_DIRECTORY);
+}
+
+
+/*
+ * Add an Internet e-mail address to the directory for a user
+ */
+int CtdlDirectoryAddUser(char *internet_addr, char *citadel_addr) {
+ char key[SIZ];
+
+ if (IsDirectory(internet_addr, 0) == 0)
+ return 0;
+ syslog(LOG_DEBUG, "Create directory entry: %s --> %s\n", internet_addr, citadel_addr);
+ directory_key(key, internet_addr);
+ cdb_store(CDB_DIRECTORY, key, strlen(key), citadel_addr, strlen(citadel_addr)+1 );
+ return 1;
+}
+
+
+/*
+ * Delete an Internet e-mail address from the directory.
+ *
+ * (NOTE: we don't actually use or need the citadel_addr variable; it's merely
+ * here because the callback API expects to be able to send it.)
+ */
+int CtdlDirectoryDelUser(char *internet_addr, char *citadel_addr) {
+ char key[SIZ];
+
+ syslog(LOG_DEBUG, "Delete directory entry: %s --> %s\n", internet_addr, citadel_addr);
+ directory_key(key, internet_addr);
+ return cdb_delete(CDB_DIRECTORY, key, strlen(key) ) == 0;
+}
+
+
+/*
+ * Look up an Internet e-mail address in the directory.
+ * On success: returns 0, and Citadel address stored in 'target'
+ * On failure: returns nonzero
+ */
+int CtdlDirectoryLookup(char *target, char *internet_addr, size_t targbuflen) {
+ struct cdbdata *cdbrec;
+ char key[SIZ];
+
+ /* Dump it in there unchanged, just for kicks */
+ 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) == 0) return(-1);
+
+ directory_key(key, internet_addr);
+ cdbrec = cdb_fetch(CDB_DIRECTORY, key, strlen(key) );
+ if (cdbrec != NULL) {
+ 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;
+ 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) && (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);
+}