Added recursive parsing

Signed-off-by: Tyrolyean <tyrolyean@tyrolyean.net>
This commit is contained in:
Tyrolyean 2020-04-29 14:47:50 +02:00
parent 8742db0b36
commit 8ca48344a8
No known key found for this signature in database
GPG key ID: 81EC9BAC5E9667C6
5 changed files with 94 additions and 4 deletions

View file

@ -23,7 +23,8 @@
#include "mail.h"
struct email_t* mail_from_text(char* message, size_t length);
struct email_t* mail_from_text(char* message, size_t length,
struct email_t* parent_mail);
void redetect_body_head(struct email_t* mail);
void unravel_multipart_mail(struct email_t* mail);

View file

@ -41,6 +41,7 @@ struct email_t{
char* boundary;
size_t submes_cnt;
struct email_t** submes;
struct email_t* parent;
};
int append_header(struct email_t* mail, const char* key, const char* value);

View file

@ -31,4 +31,7 @@ char* get_value_from_key(size_t* val_len, size_t key_offset,
char* get_multipart_boundary(char* content_type, size_t content_len,
size_t* boundary_len);
const char* get_next_line(const char* message, size_t len);
const char* get_prev_line(const char* message, size_t len_neg);
#endif /* TOOLS_H */

View file

@ -28,7 +28,12 @@
#include <ctype.h>
#include <stdlib.h>
struct email_t* mail_from_text(char* message, size_t length){
/* Generates an email struct from the given eml text. If the content is
* multipart, it will be slit up into several email_ts. This expansion is done
* recursively. For the root message set parent_mail to NULL
*/
struct email_t* mail_from_text(char* message, size_t length,
struct email_t* parent_mail){
struct email_t* mail = malloc(sizeof(struct email_t));;
memset(mail, 0, sizeof(struct email_t));
@ -39,6 +44,7 @@ struct email_t* mail_from_text(char* message, size_t length){
mail->is_multipart = false;
mail->boundary = NULL;
mail->boundary_len = 0;
mail->parent = parent_mail;
redetect_body_head(mail);
char* cont_type = search_header_key(mail, "Content-Type");
@ -157,6 +163,28 @@ void unravel_multipart_mail(struct email_t* mail){
"submessages\n", mb_cnt, mb_cnt-1);
}
for(ssize_t i = 0; i < ((ssize_t)mb_cnt)-1; i++){
const char * begin_pointer = get_next_line(mail_boundarys[i],
mail->message_length -
(mail->message - mail_boundarys[i]));
if(begin_pointer == NULL){
continue;
}
const char* end_pointer = get_prev_line(mail_boundarys[i+1],
(mail_boundarys[i+1] - begin_pointer));
if(end_pointer == NULL){
continue;
}
struct email_t *submail = mail_from_text((char*)begin_pointer,
end_pointer - begin_pointer, mail);
mail->submes = realloc(mail->submes, ++mail->submes_cnt *
(sizeof(struct email_t)));
mail->submes[mail->submes_cnt - 1] = submail;
}
free(mail_boundarys);
free(boundary);
return;
@ -177,6 +205,27 @@ void free_submails(struct email_t* mail){
}
void print_mail_structure(struct email_t *email, unsigned int level){
for(unsigned int i = 0; i < level; i++){
printf(" ");
}
if(email->is_multipart){
printf("Multipart Message with %lu submessages:\n",
email->submes_cnt);
for(size_t i = 0; i < email->submes_cnt; i++){
print_mail_structure(email->submes[i], level+1);
}
}else{
printf("Final message with length %lu\n",
email->message_length);
}
return;
}
/* Message is required to be a null terminated string, length is the mail body.
* One may leave something behind the body. len is without the '\0'
* Attempts to replace files inside the email with links to it on a webserver
@ -184,8 +233,13 @@ void free_submails(struct email_t* mail){
char* attach_files(char* message, size_t len){
char* mess;
struct email_t *email = mail_from_text(message,len);
struct email_t *email = mail_from_text(message,len, NULL);
if(email == NULL){
return NULL;
}
if(verbose){
print_mail_structure(email, 0);
}
/* Check if mails are signed/encrypted, and abort if nescessary */
if(abort_on_pgp && detect_pgp(email)){
printf("PGP detected, aborting...");

View file

@ -150,3 +150,34 @@ char* get_multipart_boundary(char* content_type, size_t content_len,
*boundary_len = 0;
return NULL;
}
/* Returns a character pointer to the first character of the next line. */
const char* get_next_line(const char* message, size_t len){
for(size_t i = 0; i < len-1; i++){
if(message[i] == '\n'){
return &message[i+1];
}
}
return NULL;
}
/* Returns a character pointer to the last character of the last line which was
* NOT part of a cr lf. The len_neg attribute specifies how far we can go to
* the left.
*/
const char* get_prev_line(const char* message, size_t len_neg){
for(size_t i = 0; i < len_neg-2; i++){
if(message[-i] == '\n'){
if(message[-(i+1)] == '\r'){
return &message[i+2];
}else{
return &message[i+2];
}
}
}
return NULL;
}