/** * @brief Get the media type for a given file extension. * @note If no direct match is found for the content, "application/octet-stream" will be returned. * @param extension a pointer to a null-terminated string containing the file extension to be looked up, starting with a period. * @return a pointer to a media type object corresponding to the media type of the specified file extension. */ media_type_t * mail_mime_get_media_type (chr_t *extension) { size_t cmplen = 0; // If extension is NULL, return application/octet-stream. if (ns_empty(extension)) return (&(media_types[0])); cmplen = ns_length_get(extension) + 1; for (size_t i = 1; i < sizeof(media_types) / sizeof(media_type_t); i++) { if (!mm_cmp_cs_eq(media_types[i].extension, extension, cmplen)) { return (&(media_types[i])); } } return (&(media_types[0])); }
/** * @brief Set the value of a global config key. * @note This function will also free the value of the global config key if it has already previously been set. * @param setting a pointer to the global key to have its value adjusted. * @param value a managed string containing the new key value, or if NULL, the key's default value will be used. * @return true if the specified key's value was set successfully, or false on failure. */ bool_t config_value_set(magma_keys_t *setting, stringer_t *value) { bool_t result = true; /// LOW: Realtime blacklist domains are handled using custom code because we don't yet have a generic type to store lists. if (!st_cmp_cs_eq(NULLER(setting->name), PLACER("magma.smtp.blacklist", 20))) { // When the default values are assigned an empty string is passed in. Returning false then tricks the system into // thinking the default value is wrong, so we just return true to avoid the issue. if (st_empty(value)) { return true; } // Were using a fixed array, so if we run out of room we have to reject config. if (magma.smtp.blacklists.count >= MAGMA_BLACKLIST_INSTANCES) { log_critical("magma.smtp.blacklist is limited to %u %s and the configuration currently contains more than %u %s.", MAGMA_BLACKLIST_INSTANCES, MAGMA_BLACKLIST_INSTANCES == 1 ? "domain" : "domains", MAGMA_BLACKLIST_INSTANCES, MAGMA_BLACKLIST_INSTANCES == 1 ? "domain" : "domains"); return false; } // Make sure the targeted array slot is empty, and the string passed to us has data in it. If so duplicate the value and // and store it in the array. If anything fails, return false. else if (magma.smtp.blacklists.domain[magma.smtp.blacklists.count] || !(magma.smtp.blacklists.domain[magma.smtp.blacklists.count] = st_dupe_opts(MANAGED_T | CONTIGUOUS | HEAP, value))) { return false; } // Track the number of blacklist domains we have. magma.smtp.blacklists.count++; // Return true so the switch statement below doesn't corrupt the array. return true; } else if (!st_cmp_cs_eq(NULLER(setting->name), NULLER("magma.smtp.bypass_addr"))) { // When the default values are assigned an empty string is passed in. Returning false then tricks the system into // thinking the default value is wrong, so we just return true to avoid the issue. if (st_empty(value)) { return true; } if (!smtp_add_bypass_entry(value)) { log_critical("Unable to add smtp bypass entry { entry = %s }", st_char_get(value)); return false; } // Return true so the switch statement below doesn't corrupt the array. return true; } switch (setting->norm.type) { // Strings case (M_TYPE_NULLER): if (!ns_empty(*((char **)(setting->store)))) { ns_free(*((char **)(setting->store))); *((char **)(setting->store)) = NULL; } if (!st_empty(value)) *((char **)(setting->store)) = ns_import(st_char_get(value), st_length_get(value)); else if (!ns_empty(setting->norm.val.ns)) *((char **)(setting->store)) = ns_dupe(setting->norm.val.ns); break; case (M_TYPE_STRINGER): if (!st_empty(*((stringer_t **)(setting->store)))) { st_free(*((stringer_t **)(setting->store))); *((stringer_t **)(setting->store)) = NULL; } if (!st_empty(value)) *((stringer_t **)(setting->store)) = st_dupe_opts(MANAGED_T | CONTIGUOUS | HEAP, value); else if (!st_empty(setting->norm.val.st)) *((stringer_t **)(setting->store)) = st_dupe_opts(MANAGED_T | CONTIGUOUS | HEAP, setting->norm.val.st); break; // Booleans case (M_TYPE_BOOLEAN): if (!st_empty(value)) { if (!st_cmp_ci_eq(value, CONSTANT("true"))) *((bool_t *)(setting->store)) = true; else if (!st_cmp_ci_eq(value, CONSTANT("false"))) *((bool_t *)(setting->store)) = false; else { log_critical("Invalid value for %s.", setting->name); result = false; } } else *((bool_t *)(setting->store)) = setting->norm.val.binary; break; // Integers case (M_TYPE_INT8): if (!st_empty(value)) { if (!int8_conv_st(value, (int8_t *)(setting->store))) { log_critical("Invalid value for %s.", setting->name); result = false; } } else *((int8_t *)(setting->store)) = setting->norm.val.i8; break; case (M_TYPE_INT16): if (!st_empty(value)) { if (!uint16_conv_st(value, (uint16_t *)(setting->store))) { log_critical("Invalid value for %s.", setting->name); result = false; } } else *((int16_t *)(setting->store)) = setting->norm.val.u16; break; case (M_TYPE_INT32): if (!st_empty(value)) { if (!int32_conv_st(value, (int32_t *)(setting->store))) { log_critical("Invalid value for %s.", setting->name); result = false; } } else *((int32_t *)(setting->store)) = setting->norm.val.i32; break; case (M_TYPE_INT64): if (!st_empty(value)) { if (!int64_conv_st(value, (int64_t *)(setting->store))) { log_critical("Invalid value for %s.", setting->name); result = false; } } else *((int64_t *)(setting->store)) = setting->norm.val.i64; break; // Unsigned Integers case (M_TYPE_UINT8): if (!st_empty(value)) { if (!uint8_conv_st(value, (uint8_t *)(setting->store))) { log_critical("Invalid value for %s.", setting->name); result = false; } } else *((uint8_t *)(setting->store)) = setting->norm.val.u8; break; case (M_TYPE_UINT16): if (!st_empty(value)) { if (!uint16_conv_st(value, (uint16_t *)(setting->store))) { log_critical("Invalid value for %s.", setting->name); result = false; } } else *((uint16_t *)(setting->store)) = setting->norm.val.u16; break; case (M_TYPE_UINT32): if (!st_empty(value)) { if (!uint32_conv_st(value, (uint32_t *)(setting->store))) { log_critical("Invalid value for %s.", setting->name); result = false; } } else *((uint32_t *)(setting->store)) = setting->norm.val.u32; break; case (M_TYPE_UINT64): if (!st_empty(value)) { if (!uint64_conv_st(value, (uint64_t *)(setting->store))) { log_critical("Invalid value for %s.", setting->name); result = false; } } else *((uint64_t *)(setting->store)) = setting->norm.val.u64; break; default: log_critical("The %s setting definition is using an invalid type.", setting->name); result = false; break; } return result; }
/** * @brief Output a key name and value in a generic way. * @param prefix a pointer to a null-terminated string containing an optional prefix to be printed before the supplied key name. * @param name a pointer to a null-terminated string containing the name of the key being output. * @param type an M_TYPE value specifying the multi-type of the key value. * @param val a void pointer to the value of the specified key, which will be printed in accordance with the supplied multi-type. * @param required a boolean value specifying whether the specified key is a required configuration option. * @return This function returns no value. */ void config_output_value_generic(chr_t *prefix, chr_t *name, M_TYPE type, void *val, bool_t required) { chr_t *reqstr = ""; if (!prefix) { prefix = ""; } if (required) { reqstr = "*"; } switch (type) { case (M_TYPE_NULLER): if (ns_empty(*((char **)(val)))) log_info("%s%s%s = NULL", prefix, name, reqstr); else log_info("%s%s%s = %s", prefix, name, reqstr, *((char **)(val))); break; case (M_TYPE_STRINGER): // Intercept the blacklist config key-> if (!st_cmp_cs_eq(NULLER(name), PLACER("magma.smtp.blacklist", 20))) { if (!magma.smtp.blacklists.count) { log_info("%s%s%s = NULL", prefix, name, reqstr); } for (uint32_t j = 0; j < magma.smtp.blacklists.count; j++) { log_info("%s%s%s = %.*s", prefix, name, reqstr, st_length_int(magma.smtp.blacklists.domain[j]), st_char_get(magma.smtp.blacklists.domain[j])); } } else if (st_empty(*((stringer_t **)(val)))) log_info("%s%s%s = NULL", prefix, name, reqstr); else log_info("%s%s%s = %.*s", prefix, name, reqstr, st_length_int(*((stringer_t **)(val))), st_char_get(*((stringer_t **)(val)))); break; case (M_TYPE_ENUM): if (!st_cmp_cs_eq(NULLER(name), CONSTANT(".protocol"))) { if (*((M_PROTOCOL *)((char *)val)) == MOLTEN) log_info("%s%s%s = MOLTEN", prefix, name, reqstr); else if (*((M_PROTOCOL *)((char *)val)) == HTTP) log_info("%s%s%s = HTTP", prefix, name, reqstr); else if (*((M_PROTOCOL *)((char *)val)) == POP) log_info("%s%s%s = POP", prefix, name, reqstr); else if (*((M_PROTOCOL *)((char *)val)) == IMAP) log_info("%s%s%s = IMAP", prefix, name, reqstr); else if (*((M_PROTOCOL *)((char *)val)) == SMTP) log_info("%s%s%s = SMTP", prefix, name, reqstr); else if (*((M_PROTOCOL *)((char *)val)) == SUBMISSION) log_info("%s%s%s = SUBMISSION", prefix, name, reqstr); else if (*((M_PROTOCOL *)((char *)val)) == EMPTY) log_info("%s%s%s = EMPTY", prefix, name, reqstr); else log_info("%s%s%s = [UNKNOWN]", prefix, name, reqstr); } else if (!st_cmp_cs_eq(NULLER(name), CONSTANT(".network.type"))) { if (*((M_PORT *)((char *)val)) == TCP_PORT) log_info("%s%s%s = TCP", prefix, name, reqstr); else if (*((M_PORT *)((char *)val)) == SSL_PORT) log_info("%s%s%s = SSL", prefix, name, reqstr); else log_info("%s%s%s = [UNKNOWN]", prefix, name, reqstr); } break; case (M_TYPE_BOOLEAN): log_info("%s%s%s = %s", prefix, name, reqstr, (*((bool_t *)(val)) ? "true" : "false")); break; case (M_TYPE_INT8): log_info("%s%s%s = %hhi", prefix, name, reqstr, *((int8_t *)(val))); break; case (M_TYPE_INT16): log_info("%s%s%s = %hi", prefix, name, reqstr, *((int16_t *)(val))); break; case (M_TYPE_INT32): log_info("%s%s%s = %i", prefix, name, reqstr, *((int32_t *)(val))); break; case (M_TYPE_INT64): log_info("%s%s%s = %li", prefix, name, reqstr, *((int64_t *)(val))); break; case (M_TYPE_UINT8): log_info("%s%s%s = %hhu", prefix, name, reqstr, *((uint8_t *)(val))); break; case (M_TYPE_UINT16): log_info("%s%s%s = %hu", prefix, name, reqstr, *((uint16_t *)(val))); break; case (M_TYPE_UINT32): log_info("%s%s%s = %u", prefix, name, reqstr, *((uint32_t *)(val))); break; case (M_TYPE_UINT64): log_info("%s%s%s = %lu", prefix, name, reqstr, *((uint64_t *)(val))); break; default: log_pedantic("Unexpected type. {type = %u}", type); break; } return; }
/** * @brief Log the contents of a magma configuration option. * @param key a pointer to the magma configuration key to be dumped. * @return This function returns no value. */ void config_output_value(magma_keys_t *key) { switch (key->norm.type) { case (M_TYPE_NULLER): if (ns_empty(*((char **)(key->store)))) log_info("%s = NULL", key->name); else log_info("%s = %s", key->name, *((char **)(key->store))); break; case (M_TYPE_STRINGER): // Intercept the blacklist config key-> if (!st_cmp_cs_eq(NULLER(key->name), PLACER("magma.smtp.blacklist", 20))) { if (!magma.smtp.blacklists.count) { log_info("%s = NULL",key->name); } for (uint32_t j = 0; j < magma.smtp.blacklists.count; j++) { log_info("%s = %.*s",key->name, st_length_int(magma.smtp.blacklists.domain[j]), st_char_get(magma.smtp.blacklists.domain[j])); } } else if (st_empty(*((stringer_t **)(key->store)))) log_info("%s = NULL", key->name); else log_info("%s = %.*s", key->name, st_length_int(*((stringer_t **)(key->store))), st_char_get(*((stringer_t **)(key->store)))); break; case (M_TYPE_BOOLEAN): log_info("%s = %s", key->name, (*((bool_t *)(key->store)) ? "true" : "false")); break; case (M_TYPE_INT8): log_info("%s = %hhi", key->name, *((int8_t *)(key->store))); break; case (M_TYPE_INT16): log_info("%s = %hi", key->name, *((int16_t *)(key->store))); break; case (M_TYPE_INT32): log_info("%s = %i", key->name, *((int32_t *)(key->store))); break; case (M_TYPE_INT64): log_info("%s = %li", key->name, *((int64_t *)(key->store))); break; case (M_TYPE_UINT8): log_info("%s = %hhu", key->name, *((uint8_t *)(key->store))); break; case (M_TYPE_UINT16): log_info("%s = %hu", key->name, *((uint16_t *)(key->store))); break; case (M_TYPE_UINT32): log_info("%s = %u", key->name, *((uint32_t *)(key->store))); break; case (M_TYPE_UINT64): log_info("%s = %lu", key->name, *((uint64_t *)(key->store))); break; default: log_pedantic("Unexpected type. {type = %u}", key->norm.type); break; } return; }