bool_t check_encoding_qp(void) { stringer_t *qp, *binary; byte_t buffer[QP_CHECK_SIZE]; for (uint64_t i = 0; status() && i < QP_CHECK_ITERATIONS; i++) { // Fill the buffer with random data and convert the buffer to hex. if (rand_write(PLACER(buffer, QP_CHECK_SIZE)) != QP_CHECK_SIZE) { return false; } else if (!(qp = qp_encode(PLACER(buffer, QP_CHECK_SIZE)))) { return false; } //log_pedantic("qp = %.*s", st_length_int(qp), st_char_get(qp)); // Convert the buffer back to binary and compare it with the original array. if (!(binary = qp_decode(qp))) { st_free(qp); return false; } else if (st_cmp_cs_eq(binary, PLACER(buffer, QP_CHECK_SIZE))) { st_free(binary); st_free(qp); return false; } st_free(binary); st_free(qp); } return true; }
/** * @brief Encode a MIME part for a provided block of data (file attachment) with the specified filename. * @note This function will look up the media type based on the supplied filename, and use that media type as a determination * of whether the content is to be encoded as either quoted-printable or base64. * @param data a pointer to a managed string containing the body of the data to be encoded. * @param filename a pointer to a managed string containing the filename of the attachment for which the data was provided. * @param boundary a pointer to a managed string containing the boundary that will be used to separate the individual MIME parts. * @return NULL on failure, or a pointer to a managed string containing the file attachment encoded as a MIME part on success. */ stringer_t * mail_mime_encode_part(stringer_t *data, stringer_t *filename, stringer_t *boundary) { stringer_t *result, *encoded; media_type_t *mtype; chr_t *fstart, *extptr = NULL, *ctype; size_t flen; if (!data) { return NULL; } // First get the extension of the filename so we can look up the media type. if (!st_empty_out(filename, (uchr_t **)&fstart, &flen)) { extptr = fstart + flen + 1; while (extptr >= fstart) { if (*extptr == '.') { break; } extptr--; } if (extptr < fstart) { extptr = NULL; } } mtype = mail_mime_get_media_type (extptr); if (mtype->bin) { encoded = base64_encode(data, NULL); ctype = "base64"; } else { encoded = qp_encode(data); ctype = "quoted-printable"; } if (!encoded) { log_pedantic("Unable to encode MIME part data."); return NULL; } // What we return is: boundary/CRLF, Content-Type/CRLF, Content-Transfer-Encoding/CRLF, Content-Disposition/CRLF, data/CRLF if (!(result = st_merge("nsnnnnnnnsns", "--------------", boundary, "\r\n", "Content-Type: ", mtype->name, ";\r\n", "Content-Transfer-Encoding: ", ctype, "\r\nContent-Disposition: attachment; filename=\"", filename, "\"\r\n\r\n", encoded))) { log_pedantic("Unable to generate MIME part data."); return NULL; } st_free(encoded); return result; }
int qp_encode_from_file( char *fname ) { size_t bc; struct stat st; int stat_result; char *in_buffer; char *out_buffer; size_t in_size, out_size; FILE *f; stat_result = stat( fname, &st ); if (stat_result != 0){ QPD fprintf(stderr, "Cannot locate file '%s' for loading and QP encoding (%s)\n", fname, strerror(errno)); return -1; } in_size = st.st_size; out_size = in_size *3; in_buffer = malloc( sizeof(char) *in_size +1); if (in_buffer == NULL) { QPD fprintf(stdout,"Error allocating %d bytes for input buffer\n", in_size); return -1; } out_buffer = malloc( sizeof(char) *out_size *3 +1); if (in_buffer == NULL) { QPD fprintf(stdout,"Error allocating %d bytes for output buffer\n", out_size); return -1; } f = fopen( fname, "r" ); bc = fread( in_buffer, 1, in_size, f ); if (bc != in_size) LOGGER_log("%s:%d:qp_encode_from_file:ERROR: Read %d bytes but requested %d", FL, bc, in_size); fclose(f); /** zero terminate the buffer -- uhuh, if you forget that you'll wonder why ** we segfault ;) **/ *(in_buffer +in_size) = '\0'; QPD fprintf(stdout,"file %s is loaded, size = %d\n", fname, in_size); qp_encode( out_buffer, out_size, in_buffer, in_size ); fprintf( stdout, "%s", out_buffer ); free(in_buffer); free(out_buffer); return 0; }
/* * It encodes if needed and folds */ StringBuffer encodeHeader(StringBuffer line){ if(isAscii(line)) return line; StringBuffer ret; StringBuffer tmp; StringBuffer startPattern("=?utf-8?Q?"); StringBuffer endPattern("?="); StringBuffer foldingPattern("\r\n "); int foldingLen = 64; char* qp = 0; qp = qp_encode(line); tmp += startPattern; tmp += qp; delete [] qp; // folding action unsigned long p = 0; while(p + foldingLen < tmp.length()) { ret.append(tmp.substr(p, foldingLen)); ret.append(foldingPattern); ret.append(startPattern); p += foldingLen; } if (ret.length() > 0) tmp.append(tmp.substr(p, tmp.length() - p)); ret = tmp; ret.append(endPattern); return ret; }
/** * @brief Build a spam text signature for insertion into a message body. * @param server the server object of the web server where the teacher application is hosted. * @param type MESSAGE_TYPE_HTML to generate an html-based signature, or any other value for plain text. * @param content_encoding if MESSAGE_ENCODING_QUOTED_PRINTABLE, set the encoding type to qp. * @param signum the spam signature number referenced by the teacher url. * @param sigkey the spam signature key for client verification in the teacher app. * @param disposition if 0, the message disposition is "innocent"; otherwise, the disposition specifies "spam". * @return NULL on failure, or a newly allocated managed string containing the desired mail signature on success. */ stringer_t * mail_build_signature(server_t *server, int_t content_type, int_t content_encoding, uint64_t signum, uint64_t sigkey, int_t disposition) { size_t length; stringer_t *holder; stringer_t *result = NULL; stringer_t *spam_text = NULL; static const chr_t *line = "\r\n____________________________________________________________________________________\r\n"; // Build the spam signature. if (signum && sigkey) { // This is the format for spam signatures. if (content_type == MESSAGE_TYPE_HTML) { holder = st_merge("nnnnnsnsn", "\r\n<div style='display: block; text-transform: none; text-indent: 0px; letter-spacing: normal; " "line-height: normal; text-align: left; white-space: normal; height: auto; visibility: visible; border-bottom: 1px solid black; border-collapse: collapse; " "width: 50em; font-size: 12px; color: black; font-family: sans-serif; padding: 0px 0px 4px 0px; clear: both; font-weight: normal;" "text-decoration: none; background: white; ", "margin: 20px 2px 10px 2px; border-top: 1px solid black;", "'>\r\n\tUse the link below to report this message as ", !disposition ? "spam" : "innocent", ".<br />\r\n\t<a style='font-size: 12px; font-family: sans-serif; color: blue; background: white; text-decoration: underline; font-weight: normal;' href='https://", server->domain, "/apps/teacher?sig=%lu&key=%lu'>https://", server->domain, "/apps/teacher?sig=%lu&key=%lu</a>\r\n</div>\r\n"); } else { holder = st_merge("nnsn", "Use the link below to report this message as ", !disposition ? "spam.\r\nhttps://" : "innocent.\r\nhttps://", server->domain, "/apps/teacher?sig=%lu&key=%lu"); } if (!holder) { log_pedantic("Unable to build the spam signature."); return NULL; } // How big is the signature with the numbers inserted. length = st_length_get(holder) + uint64_digits(signum) + uint64_digits(sigkey) + uint64_digits(signum) + uint64_digits(sigkey); if (!(spam_text = st_alloc(length))) { log_pedantic("Unable to build the spam signature."); st_free(holder); return NULL; } // Print the spam signature text. if (content_type == MESSAGE_TYPE_HTML) { length = st_sprint(spam_text, st_char_get(holder), signum, sigkey, signum, sigkey); } else { length = st_sprint(spam_text, st_char_get(holder), signum, sigkey); } st_free(holder); if (!length) { log_pedantic("Unable to build the spam signature."); st_free(spam_text); return NULL; } } // Error check. if (!spam_text) { log_pedantic("Could not build the signature."); return NULL; } // Build the output signature. if (content_type == MESSAGE_TYPE_HTML) { result = spam_text; spam_text = NULL; } else { result = st_merge("nnsn", line, (spam_text == NULL) ? "" : line, spam_text, line); } if (!result) { log_pedantic("An error occurred while attempting to merge the signature."); } // Cleanup. st_cleanup(spam_text); // Check for quoted printable encodings. if (content_encoding == MESSAGE_ENCODING_QUOTED_PRINTABLE) { holder = qp_encode(result); if (holder && result) { st_free(result); result = holder; } } return result; }