/** * @brief Check to see if the specified command line option specified an optional parameter, and adjust the index accordingly. * @note This function will automatically generate an error through display_usage() if the parameters are incorrect. * @param xargv a pointer to the main function's argv array. * @param iptr a pointer to the xargv option index to be checked and updated. * @param xargc the number of items in the xargv array. * @return a pointer to the value of the current index's optional parameter if specified, or NULL if one wasn't. */ chr_t * check_next_opt(char *xargv[], int *iptr, int xargc) { chr_t *result; // If this is an optional parameter then there still must be a config file specified after it. if (*iptr == (xargc-1)) { check_display_usage(xargv[0]); } // If the next argument begins with '-' then our option has a null parameter. else if (!mm_cmp_cs_eq(xargv[*iptr+1], "-", 1)) { (*iptr)++; return NULL; } // If the following parameter is the last one, it must be the config file and this is a null option. if (*iptr+1 == (xargc-1)) { (*iptr)++; return NULL; } (*iptr) += 2; if (!(result = ns_dupe(xargv[*iptr-1]))) { log_unit("Memory allocation encountered while preparing checks. Exiting.\n"); } return result; }
/** * @brief Count the number of instances of a boundary string inside a MIME body. * @note The search is terminated if "--" is found right after the boundary string. * @param body a placer containing the body text to be parsed. * @param boundary a pointer to a managed string containing the boundary string for the MIME content. * @return 0 on failure, or the number of times the boundary string was located in the MIME body on success. */ uint32_t mail_mime_count(placer_t body, stringer_t *boundary) { uint32_t result = 0; chr_t *stream, *bounddata; size_t increment = 0, length, boundlen; if (pl_empty(body) || st_empty(boundary)) { return 0; } // Figure out the lengths. if (!(length = st_length_get(&body))) { log_pedantic("Cannot count boundary marker in zero-length MIME body.."); return 0; } else if (!(boundlen = st_length_get(boundary))) { log_pedantic("Cannot count zero-length MIME boundary."); return 0; } // Setup. stream = st_char_get(&body); bounddata = st_char_get(boundary); // Find the start of the first part. while (increment + boundlen <= length) { if (mm_cmp_cs_eq(stream, bounddata, boundlen) == 0) { stream += boundlen + 1; increment += boundlen + 1; // Two dashes indicate the end of this mime sections. if (increment + 1 <= length && mm_cmp_cs_eq(stream, "--", 2) == 0) { increment = length + 1; } else { result++; } } else { stream++; increment++; } } return result; }
/** * @brief Get a specified chunk (mime part) of a multipart mime message. * @param message a managed string containing the mime message to be parsed. * @param boundary a managed string containing the boundary used to split the multipart mime message. * @param chunk the one-index based chunk to be retrieved from the multipart message * @return NULL on failure or a placer containing the specified chunk on success. */ stringer_t * mail_get_chunk(stringer_t *message, stringer_t *boundary, int_t chunk) { int_t found = 0; stringer_t *result; size_t start = 0, length = 0, input = 0; while (chunk != 0) { // So on repeats we don't have to start all over again. if (length != 0) { start += length - 1; } found = 0; while (found == 0) { // Get the start of the MIME message part. if (!st_search_cs(PLACER(st_char_get(message) + start, st_length_get(message) - start), boundary, &input)) { log_pedantic("The boundary doesn't appear to be part of this message."); return NULL; } // Skip the boundary before searching again. start += input + st_length_get(boundary); // This will detect the section ending. if (st_length_get(message) - start >= 2 && mm_cmp_cs_eq(st_char_get(message) + start, "--", 2) == 1) { return NULL; } // Some broken implementations use similar boundaries. This should detect those. else if (st_length_get(message) - start > 0 && (*(st_char_get(message) + start) < '!' || *(st_char_get(message) + start) > '~')) { found = 1; } } found = 0; while (found == 0) { // Get the end. if (!st_search_cs(PLACER(st_char_get(message) + start, st_length_get(message) - start), boundary, &length)) { length = st_length_get(message) - start; found = 1; } else if (st_length_get(message) - start - length > 0 && (*(st_char_get(message) + start) < '!' || *(st_char_get(message) + start) > '~')) { found = 1; } } chunk--; } // Setup a placer with the chunk. result = PLACER(st_char_get(message) + start, length); return result; }
/** * @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 = 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])); }
/* modeled closely after args_parse() */ void check_args_parse(int argc, char *argv[]) { int_t i = 1; while (i < argc) { if (!st_cmp_cs_eq(NULLER(argv[i]), PLACER("-v", 2))) { if (!(virus_check_data_path = check_next_opt(argv, &i, argc))) { do_virus_check = false; } } else if (!st_cmp_cs_eq(NULLER(argv[i]), PLACER("-t", 2))) { if (!(tank_check_data_path = check_next_opt(argv, &i, argc))) { do_tank_check = false; } } else if (!st_cmp_cs_eq(NULLER(argv[i]), PLACER("-d", 2))) { if (!(dspam_check_data_path = check_next_opt(argv, &i, argc))) { do_dspam_check = false; } } else if (!st_cmp_cs_eq(NULLER(argv[i]), PLACER("-s", 2))) { do_spf_check = false; i++; } // See if it's an illegal parameter beginning with "-" else if (!mm_cmp_cs_eq(argv[i], "-", 1)) { check_display_usage(argv[0]); } // Otherwise it's the config file else if (i == (argc-1)) { snprintf(magma.config.file, MAGMA_FILEPATH_MAX, "%s", argv[i]); i++; } else { check_display_usage(argv[0]); } } return; }
/** * @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 Get a placer pointing to the specified child inside a MIME body. * @param body a placer containing the body text to be parsed. * @param boundary a pointer to a managed string containing the boundary string to split the MIME content. * @param child the zero-based index of the MIME child to be located in the body text. * @return pl_null() on failure, or a placer containing the specified MIME child on success. */ placer_t mail_mime_child(placer_t body, stringer_t *boundary, uint32_t child) { uint32_t result = 0; chr_t *start, *stream, *bounddata; size_t increment = 0, length, boundlen; if (pl_empty(body) || st_empty(boundary)) { return pl_null(); } // Figure out the lengths. if (!(length = st_length_get(&body))) { log_pedantic("Cannot parse children from zero-length MIME body.."); return pl_null(); } else if (!(boundlen = st_length_get(boundary))) { log_pedantic("Cannot parse children from MIME body with zero-length boundary."); return pl_null();; } // Setup. stream = st_char_get(&body); bounddata = st_char_get(boundary); // Find the start of the first part. while (increment + boundlen <= length && result < child) { if (mm_cmp_cs_eq(stream, bounddata, boundlen) == 0 && (increment + boundlen == length || *(stream + boundlen) < '!' || *(stream + boundlen) > '~')) { stream += boundlen; increment += boundlen; // Two dashes indicate the end of this mime sections. if (increment < length && mm_cmp_cs_eq(stream, "--", 2) == 0) { increment = length + 1; } else { result++; } } else { stream++; increment++; } } // The requested child wasn't found. if (increment + boundlen >= length) { return pl_null(); } // This will skip a line break after the boundary marker. if (length - increment > 0 && *stream == '\r') { stream++; increment++; } if (length - increment > 0 && *stream == '\n') { stream++; increment++; } // Store the start position. start = stream; // Find the end. while (increment < length) { if (increment + boundlen < length && mm_cmp_cs_eq(stream, bounddata, boundlen) == 0) { increment = length; } else { stream++; increment++; } } // Make sure we advanced. if (stream == start) { return pl_null(); } return pl_init(start, stream - start); }