2020-04-25 01:37:15 +02:00
|
|
|
/*
|
|
|
|
* attach.c - Core mechanix behind attachment replacing
|
|
|
|
* I know how mechanics is spelt, let me have my fun :D
|
|
|
|
* The author licenses this file
|
|
|
|
* to you under the Apache License, Version 2.0 (the
|
|
|
|
* "License"); you may not use this file except in compliance
|
|
|
|
* with the License. You may obtain a copy of the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing,
|
|
|
|
* software distributed under the License is distributed on an
|
|
|
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
|
|
* KIND, either express or implied. See the License for the
|
|
|
|
* specific language governing permissions and limitations
|
|
|
|
* under the License.
|
|
|
|
*/
|
|
|
|
|
2020-04-25 01:50:44 +02:00
|
|
|
#include "attach.h"
|
2020-04-28 20:42:34 +02:00
|
|
|
#include "detect.h"
|
|
|
|
#include "config.h"
|
2020-04-29 00:32:25 +02:00
|
|
|
#include "mail.h"
|
2020-04-29 02:01:35 +02:00
|
|
|
#include "tools.h"
|
2020-04-30 00:27:03 +02:00
|
|
|
#include "file.h"
|
2020-04-28 20:42:34 +02:00
|
|
|
|
2020-04-25 01:37:15 +02:00
|
|
|
#include <string.h>
|
2020-04-28 18:50:30 +02:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdbool.h>
|
|
|
|
#include <ctype.h>
|
2020-04-25 01:37:15 +02:00
|
|
|
#include <stdlib.h>
|
2020-04-30 01:31:47 +02:00
|
|
|
#include <sys/stat.h>
|
2020-04-25 01:37:15 +02:00
|
|
|
|
2020-04-29 14:47:50 +02:00
|
|
|
/* 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){
|
2020-04-28 18:50:30 +02:00
|
|
|
|
2020-04-29 13:43:45 +02:00
|
|
|
struct email_t* mail = malloc(sizeof(struct email_t));;
|
|
|
|
memset(mail, 0, sizeof(struct email_t));
|
|
|
|
mail->message = message;
|
|
|
|
mail->message_length = length;
|
|
|
|
mail->submes_cnt = 0;
|
|
|
|
mail->submes = NULL;
|
|
|
|
mail->is_multipart = false;
|
|
|
|
mail->boundary = NULL;
|
|
|
|
mail->boundary_len = 0;
|
2020-04-29 15:42:24 +02:00
|
|
|
mail->ct_len = 0;
|
|
|
|
mail->content_type = 0;
|
2020-04-29 14:47:50 +02:00
|
|
|
mail->parent = parent_mail;
|
2020-05-01 00:39:18 +02:00
|
|
|
mail->saved_filename = NULL;
|
2020-04-28 18:50:30 +02:00
|
|
|
|
2020-04-29 13:43:45 +02:00
|
|
|
redetect_body_head(mail);
|
|
|
|
char* cont_type = search_header_key(mail, "Content-Type");
|
2020-04-29 02:01:35 +02:00
|
|
|
if(cont_type == NULL){
|
|
|
|
/* Halleluja, I've got nothing to do! WOO */
|
2020-04-29 15:16:35 +02:00
|
|
|
if(verbose){
|
2020-04-29 15:42:24 +02:00
|
|
|
printf("Mail found without content type!\n");
|
2020-04-29 15:16:35 +02:00
|
|
|
}
|
2020-04-29 13:43:45 +02:00
|
|
|
mail->is_multipart = false;
|
2020-04-29 02:01:35 +02:00
|
|
|
return mail;
|
|
|
|
}else{
|
|
|
|
size_t value_length = 0;
|
|
|
|
char * mime_type = get_value_from_key(&value_length,
|
2020-04-29 13:43:45 +02:00
|
|
|
cont_type - mail->message, mail);
|
2020-04-29 02:01:35 +02:00
|
|
|
if(mime_type != NULL){
|
2020-04-29 15:42:24 +02:00
|
|
|
mail->ct_len = value_length;
|
|
|
|
mail->content_type = mime_type;
|
2020-04-29 16:29:36 +02:00
|
|
|
|
2020-04-29 15:09:51 +02:00
|
|
|
if(verbose){
|
|
|
|
printf("Found content type: %.*s\n",
|
2020-04-29 15:42:24 +02:00
|
|
|
(int)value_length, mime_type);
|
2020-04-29 15:09:51 +02:00
|
|
|
}
|
2020-04-29 16:29:36 +02:00
|
|
|
|
2020-04-29 03:00:12 +02:00
|
|
|
if(strncasecmp(mime_type, MULTIPART_MIME,
|
|
|
|
strlen(MULTIPART_MIME)) == 0){
|
|
|
|
/* We have multiple messages cramped inside this
|
|
|
|
* one. Let's unravel em!
|
|
|
|
*/
|
2020-04-29 13:43:45 +02:00
|
|
|
mail->is_multipart = true;
|
2020-04-29 03:00:12 +02:00
|
|
|
size_t bd_len = 0;
|
2020-04-29 20:18:10 +02:00
|
|
|
char* bd = get_value_equals(
|
|
|
|
mime_type, value_length, &bd_len,
|
|
|
|
"boundary");
|
2020-04-29 13:43:45 +02:00
|
|
|
|
2020-04-29 03:00:12 +02:00
|
|
|
if(bd != NULL){
|
2020-04-29 13:43:45 +02:00
|
|
|
mail->boundary = bd;
|
|
|
|
mail->boundary_len = bd_len;
|
|
|
|
|
|
|
|
if(verbose){
|
|
|
|
printf("Received boundary: "
|
|
|
|
"[%.*s]\n",
|
|
|
|
(int)bd_len, bd);
|
|
|
|
}
|
2020-04-29 03:00:12 +02:00
|
|
|
}
|
2020-04-29 16:29:36 +02:00
|
|
|
/* Expands the mail message to multiple ones */
|
2020-04-29 13:43:45 +02:00
|
|
|
unravel_multipart_mail(mail);
|
2020-04-29 03:00:12 +02:00
|
|
|
|
|
|
|
}
|
2020-04-29 02:01:35 +02:00
|
|
|
}
|
|
|
|
}
|
2020-04-29 19:19:38 +02:00
|
|
|
mail->base64_encoded = detect_base64(mail);
|
2020-04-29 22:18:08 +02:00
|
|
|
|
|
|
|
mail->file_info = get_mime_file_info(mail);
|
2020-04-25 01:37:15 +02:00
|
|
|
|
2020-04-28 18:50:30 +02:00
|
|
|
return mail;
|
|
|
|
}
|
|
|
|
|
|
|
|
void redetect_body_head(struct email_t* mail){
|
|
|
|
|
|
|
|
char* last_lf = NULL;
|
|
|
|
char* body_start = NULL;
|
|
|
|
bool found_alnum = false;
|
|
|
|
for(size_t i = 0; i < mail->message_length; i++){
|
|
|
|
if(mail->message[i] == '\n' && !found_alnum){
|
|
|
|
body_start = &(mail->message[i+1]);
|
|
|
|
break;
|
|
|
|
|
|
|
|
}else if(mail->message[i] == '\n'){
|
|
|
|
last_lf = &(mail->message[i]);
|
|
|
|
found_alnum = false;
|
|
|
|
}else if(isalnum(mail->message[i])){
|
|
|
|
found_alnum = true;
|
|
|
|
}
|
2020-04-25 01:37:15 +02:00
|
|
|
}
|
2020-04-28 18:50:30 +02:00
|
|
|
|
2020-04-29 15:09:51 +02:00
|
|
|
/* Really this is something that SHOULD NOT HAPPEN during transport, but
|
|
|
|
* enigmail produces a weirdly formatted signing here which has ONLY a
|
|
|
|
* header and no body. So we need that for multipart messages.
|
2020-04-28 18:50:30 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
if(body_start == NULL) {
|
2020-04-29 15:09:51 +02:00
|
|
|
mail->header_len = mail->message_length;
|
2020-04-28 18:50:30 +02:00
|
|
|
mail->body_offset = 0;
|
|
|
|
return;
|
2020-04-25 01:50:44 +02:00
|
|
|
}
|
2020-04-28 18:50:30 +02:00
|
|
|
|
|
|
|
mail->body_offset = body_start - mail->message;
|
2020-04-28 20:00:11 +02:00
|
|
|
mail->header_len = last_lf - mail->message - 1 /* for the CR */;
|
2020-04-28 18:50:30 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2020-04-29 13:43:45 +02:00
|
|
|
/* This function creates the submail-messages from the boundary defined for
|
|
|
|
* multipart messages. This function doesN'T perform header checks for that
|
|
|
|
* boundary!
|
|
|
|
*/
|
|
|
|
void unravel_multipart_mail(struct email_t* mail){
|
|
|
|
|
|
|
|
if(mail == NULL || !mail->is_multipart || mail->boundary == NULL){
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
char ** mail_boundarys = NULL;
|
|
|
|
size_t mb_cnt = 0;
|
|
|
|
char* boundary = malloc(mail->boundary_len+1);
|
|
|
|
memset(boundary, 0, mail->boundary_len+1);
|
|
|
|
memcpy(boundary,mail->boundary, mail->boundary_len);
|
|
|
|
|
|
|
|
char* newloc = mail->message + mail->body_offset;
|
2020-04-29 03:00:12 +02:00
|
|
|
|
2020-04-29 13:43:45 +02:00
|
|
|
for(;newloc < mail->message + mail->message_length;){
|
|
|
|
newloc = strstr(newloc,
|
|
|
|
boundary);
|
|
|
|
if(newloc == NULL || newloc >
|
|
|
|
(mail->message + mail->message_length)){
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
}else{
|
|
|
|
mail_boundarys = realloc(mail_boundarys,
|
|
|
|
++mb_cnt*(sizeof(char*)));
|
|
|
|
mail_boundarys[mb_cnt-1] = newloc;
|
|
|
|
}
|
|
|
|
newloc++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(verbose){
|
|
|
|
printf("Found %lu boundarys inside mail, which means %li "
|
|
|
|
"submessages\n", mb_cnt, mb_cnt-1);
|
|
|
|
}
|
|
|
|
|
2020-04-29 14:47:50 +02:00
|
|
|
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,
|
2020-05-01 02:12:34 +02:00
|
|
|
end_pointer - begin_pointer, mail);
|
2020-04-29 14:47:50 +02:00
|
|
|
mail->submes = realloc(mail->submes, ++mail->submes_cnt *
|
|
|
|
(sizeof(struct email_t)));
|
|
|
|
mail->submes[mail->submes_cnt - 1] = submail;
|
|
|
|
}
|
|
|
|
|
2020-04-29 13:43:45 +02:00
|
|
|
free(mail_boundarys);
|
|
|
|
free(boundary);
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void free_submails(struct email_t* mail){
|
|
|
|
|
2020-04-30 19:43:44 +02:00
|
|
|
free(mail->file_info.name);
|
|
|
|
free(mail->file_info.mime_type);
|
|
|
|
|
2020-04-29 13:43:45 +02:00
|
|
|
if(!mail->is_multipart){
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
for(size_t i = 0; i < mail->submes_cnt; i++){
|
|
|
|
free_submails(mail->submes[i]);
|
|
|
|
free(mail->submes[i]);
|
|
|
|
}
|
|
|
|
free(mail->submes);
|
2020-04-29 03:00:12 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2020-04-29 14:47:50 +02:00
|
|
|
void print_mail_structure(struct email_t *email, unsigned int level){
|
|
|
|
|
|
|
|
for(unsigned int i = 0; i < level; i++){
|
|
|
|
printf(" ");
|
|
|
|
}
|
|
|
|
|
2020-04-29 19:29:13 +02:00
|
|
|
if(email->base64_encoded){
|
|
|
|
printf("Base64 encoded ");
|
|
|
|
}
|
|
|
|
|
2020-04-29 14:47:50 +02:00
|
|
|
if(email->is_multipart){
|
2020-04-29 19:29:13 +02:00
|
|
|
printf("multipart Message with %lu submessages:\n",
|
2020-04-29 14:47:50 +02:00
|
|
|
email->submes_cnt);
|
|
|
|
for(size_t i = 0; i < email->submes_cnt; i++){
|
|
|
|
print_mail_structure(email->submes[i], level+1);
|
|
|
|
}
|
|
|
|
}else{
|
2020-04-29 22:18:08 +02:00
|
|
|
if( email->file_info.mime_type == NULL){
|
|
|
|
|
|
|
|
printf("final message with length %lu and type "
|
|
|
|
"[%.*s] \n",
|
|
|
|
email->message_length, (int)email->ct_len,
|
|
|
|
email->content_type);
|
|
|
|
}else{
|
|
|
|
printf("final message with length %lu and type [%s] \n",
|
|
|
|
email->message_length,
|
|
|
|
email->file_info.mime_type);
|
|
|
|
|
|
|
|
}
|
2020-04-29 14:47:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2020-04-28 20:42:34 +02:00
|
|
|
/* 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
|
|
|
|
*/
|
2020-04-28 18:50:30 +02:00
|
|
|
char* attach_files(char* message, size_t len){
|
2020-04-29 13:43:45 +02:00
|
|
|
|
|
|
|
char* mess;
|
2020-04-29 14:47:50 +02:00
|
|
|
struct email_t *email = mail_from_text(message,len, NULL);
|
|
|
|
if(email == NULL){
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
if(verbose){
|
|
|
|
print_mail_structure(email, 0);
|
|
|
|
}
|
2020-04-28 20:42:34 +02:00
|
|
|
/* Check if mails are signed/encrypted, and abort if nescessary */
|
2020-04-29 13:43:45 +02:00
|
|
|
if(abort_on_pgp && detect_pgp(email)){
|
2020-04-29 15:09:51 +02:00
|
|
|
printf("PGP detected, aborting...\n");
|
2020-04-29 13:43:45 +02:00
|
|
|
goto finish;
|
2020-04-28 20:42:34 +02:00
|
|
|
}
|
2020-04-28 23:43:09 +02:00
|
|
|
/* Check if mails are signed/encrypted, and abort if nescessary */
|
2020-04-29 13:43:45 +02:00
|
|
|
if(abort_on_dkim && detect_dkim(email)){
|
2020-04-29 15:09:51 +02:00
|
|
|
printf("DKIM signature detected, aborting...\n");
|
2020-04-29 13:43:45 +02:00
|
|
|
goto finish;
|
2020-04-28 23:43:09 +02:00
|
|
|
}
|
2020-04-25 01:50:44 +02:00
|
|
|
|
2020-04-29 00:32:25 +02:00
|
|
|
/* Now we can start the real work! */
|
2020-04-30 01:31:47 +02:00
|
|
|
char* storage_dir = generate_safe_dirname();
|
2020-04-30 00:27:03 +02:00
|
|
|
if(storage_dir == NULL){
|
|
|
|
fprintf(stderr,"Failed to get mail storage directory!\n");
|
|
|
|
goto finish;
|
|
|
|
}
|
|
|
|
if(verbose){
|
|
|
|
printf("Storing mail messages into directory [%s]\n",
|
|
|
|
storage_dir);
|
|
|
|
}
|
2020-04-30 22:58:07 +02:00
|
|
|
bool dir_cre = false;
|
|
|
|
if(replace_files(email, storage_dir, &dir_cre) < 0){
|
2020-04-30 00:27:03 +02:00
|
|
|
fprintf(stderr, "Failed to store base64 messages!\n");
|
|
|
|
goto finish;
|
|
|
|
}
|
2020-04-29 00:32:25 +02:00
|
|
|
|
2020-04-30 01:31:47 +02:00
|
|
|
free(storage_dir);
|
2020-04-30 00:27:03 +02:00
|
|
|
|
2020-04-29 00:32:25 +02:00
|
|
|
/* Announce our presence via header */
|
2020-04-29 13:43:45 +02:00
|
|
|
if(append_header(email,"X-Mailattached", instance_id) < 0){
|
2020-04-29 00:36:14 +02:00
|
|
|
fprintf(stderr, "Failed to attach header!\n");
|
2020-04-29 13:43:45 +02:00
|
|
|
goto finish;
|
2020-04-29 00:36:14 +02:00
|
|
|
}
|
2020-04-29 19:19:38 +02:00
|
|
|
|
2020-04-29 13:43:45 +02:00
|
|
|
finish:
|
|
|
|
mess = email->message;
|
|
|
|
free_submails(email);
|
|
|
|
free(email);
|
|
|
|
return mess;
|
2020-04-25 01:37:15 +02:00
|
|
|
}
|
|
|
|
|
2020-05-01 01:11:44 +02:00
|
|
|
/* This function returns the first message where it makes sense to append the
|
|
|
|
* attachment message to. To differentiate between text and html the mime type
|
|
|
|
* is sent along
|
|
|
|
*/
|
|
|
|
struct email_t* get_appendable_mail(struct email_t* mail,
|
|
|
|
const char* mime_type){
|
|
|
|
|
|
|
|
if(mail->is_multipart){
|
|
|
|
struct email_t* ret = NULL;
|
|
|
|
for(size_t i = 0; i < mail->submes_cnt; i++){
|
|
|
|
struct email_t* ret2 =
|
|
|
|
get_appendable_mail(mail->submes[i], mime_type);
|
|
|
|
if(ret2 != NULL){
|
|
|
|
ret = ret2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if(mail->base64_encoded || mail->file_info.mime_type == NULL ||
|
|
|
|
mail->file_info.name != NULL){
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(strcasecmp(mail->file_info.mime_type, mime_type) == 0){
|
|
|
|
return mail;
|
|
|
|
}else{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2020-04-30 00:27:03 +02:00
|
|
|
/* This function RECURSIVELY replaces ALL base 64 encoded messages above the
|
|
|
|
* threshold set in the config file with links to that file in the HTML format.
|
|
|
|
* Call this function with the mail ROOT object if you want to replace all
|
2020-04-30 22:58:07 +02:00
|
|
|
* base64 files, or only one when you want to replace only one. Created is a
|
|
|
|
* boolean wether the directory to store files has already been created.
|
2020-04-30 00:27:03 +02:00
|
|
|
*/
|
2020-04-30 22:58:07 +02:00
|
|
|
int replace_files(struct email_t* mail, const char* dirname, bool* created){
|
2020-04-30 00:27:03 +02:00
|
|
|
|
|
|
|
if(mail->is_multipart){
|
|
|
|
|
|
|
|
for(size_t i = 0; i < mail->submes_cnt; i++){
|
2020-05-01 02:12:34 +02:00
|
|
|
int n = replace_files(mail->submes[i], dirname,
|
|
|
|
created) ;
|
|
|
|
if(n < 0){
|
2020-04-30 22:58:07 +02:00
|
|
|
|
2020-04-30 00:27:03 +02:00
|
|
|
return -1;
|
2020-05-01 02:12:34 +02:00
|
|
|
} else if(n == 1){
|
|
|
|
i--;
|
2020-04-30 00:27:03 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
}
|
2020-04-30 19:43:44 +02:00
|
|
|
if(mail->file_info.name == NULL){
|
|
|
|
return 0;
|
|
|
|
}
|
2020-04-30 22:38:33 +02:00
|
|
|
if((mail->message_length - mail->body_offset) < (unsigned long)
|
|
|
|
min_filesize ){
|
|
|
|
return 0;
|
|
|
|
}
|
2020-04-30 23:09:13 +02:00
|
|
|
/* Create the directory for the file */
|
|
|
|
if(!(*created)){
|
|
|
|
*created = true;
|
|
|
|
if(mkdir(dirname, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)
|
|
|
|
< 0){
|
2020-04-30 22:58:07 +02:00
|
|
|
|
|
|
|
perror("Failed to create storage directory!");
|
|
|
|
return -1;
|
2020-04-30 23:09:13 +02:00
|
|
|
|
2020-04-30 22:58:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2020-05-01 01:11:44 +02:00
|
|
|
struct email_t* root = get_root_mail(mail);
|
|
|
|
if(root == NULL){
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
struct email_t* txt_app = get_appendable_mail(root, "text/plain");
|
|
|
|
struct email_t* html_app = get_appendable_mail(root, "text/html");
|
|
|
|
if(txt_app == NULL && html_app == NULL){
|
|
|
|
return -1;
|
|
|
|
}
|
2020-05-01 00:39:18 +02:00
|
|
|
char* chosen_filename = NULL;
|
2020-04-30 02:08:33 +02:00
|
|
|
if(mail->base64_encoded){
|
2020-05-01 00:39:18 +02:00
|
|
|
if(base64_decode_file(dirname, mail, &chosen_filename) < 0){
|
2020-05-01 02:13:48 +02:00
|
|
|
fprintf(stderr, "Failed to decode base64 file!\n");
|
2020-04-30 02:08:33 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}else{
|
|
|
|
if(decode_file(dirname, (mail->message+mail->body_offset),
|
|
|
|
(mail->message_length - mail->body_offset),
|
2020-05-01 00:39:18 +02:00
|
|
|
mail->file_info.name, &chosen_filename) < 0){
|
2020-04-30 02:08:33 +02:00
|
|
|
|
2020-05-01 02:13:48 +02:00
|
|
|
fprintf(stderr, "Failed to decode regular file!\n");
|
2020-04-30 02:08:33 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2020-04-30 01:31:47 +02:00
|
|
|
}
|
2020-04-30 22:58:07 +02:00
|
|
|
/* Insert a message telling you what has happened to the attachment */
|
2020-04-30 00:27:03 +02:00
|
|
|
|
2020-04-30 21:12:29 +02:00
|
|
|
/* Delete old attachment */
|
|
|
|
if(mail->parent != NULL){
|
|
|
|
if(remove_mail(mail) < 0){
|
2020-05-01 00:39:18 +02:00
|
|
|
fprintf(stderr, "Failed to remove old attachment!\n");
|
|
|
|
free(chosen_filename);
|
2020-04-30 21:12:29 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
2020-05-01 00:39:18 +02:00
|
|
|
static const char* html_filler_pref =
|
2020-05-01 02:23:08 +02:00
|
|
|
"<br><h1>MAIL ATTACHED</h1> The following attachment of this mail has "
|
2020-05-01 00:39:18 +02:00
|
|
|
"been remotely stored: <br>\r\n"
|
2020-05-01 02:24:34 +02:00
|
|
|
"<p> File \"%s of type \"%s\" as <a href=\"%s%s\">%s%s</a></p>\r\n";
|
2020-04-30 22:58:07 +02:00
|
|
|
|
2020-05-01 00:39:18 +02:00
|
|
|
static const char* text_filler_pref =
|
|
|
|
" --- MAIL ATTACHED ---\r\n The following attachment of this mail has "
|
|
|
|
"been remotely stored:\r\n"
|
2020-05-01 02:24:34 +02:00
|
|
|
"File \"%s\" of type \"%s\" as %s%s\r\n";
|
2020-05-01 00:39:18 +02:00
|
|
|
|
2020-05-01 00:42:31 +02:00
|
|
|
size_t directory_len = strlen(directory);
|
2020-05-01 00:39:18 +02:00
|
|
|
size_t url_len = strlen(url_base);
|
|
|
|
size_t mime_len = 0;
|
|
|
|
if(mail->file_info.mime_type != NULL){
|
|
|
|
mime_len = strlen(mail->file_info.mime_type);
|
|
|
|
}
|
2020-04-30 22:58:07 +02:00
|
|
|
|
2020-05-01 00:44:14 +02:00
|
|
|
size_t html_buffer_len = strlen(html_filler_pref) + 2*url_len + 100 +
|
2020-05-01 00:39:18 +02:00
|
|
|
mime_len + 2*strlen(mail->file_info.name);
|
|
|
|
|
|
|
|
size_t text_buffer_len = strlen(html_filler_pref) + url_len + 50 +
|
|
|
|
mime_len + strlen(mail->file_info.name);
|
|
|
|
|
|
|
|
char* html_buffer = malloc(html_buffer_len);
|
|
|
|
memset(html_buffer, 0, html_buffer_len);
|
|
|
|
|
|
|
|
char* text_buffer = malloc(text_buffer_len);
|
|
|
|
memset(text_buffer, 0, text_buffer_len);
|
|
|
|
|
|
|
|
snprintf(html_buffer, html_buffer_len - 1, html_filler_pref,
|
|
|
|
mail->file_info.name,
|
|
|
|
mail->file_info.mime_type,
|
|
|
|
url_base, chosen_filename+directory_len,
|
|
|
|
url_base, chosen_filename+directory_len);
|
|
|
|
|
|
|
|
snprintf(text_buffer, text_buffer_len - 1, text_filler_pref,
|
|
|
|
mail->file_info.name,
|
|
|
|
mail->file_info.mime_type,
|
|
|
|
url_base, chosen_filename+directory_len);
|
|
|
|
|
2020-05-01 01:11:44 +02:00
|
|
|
|
|
|
|
if(txt_app != NULL){
|
|
|
|
append_to_body(txt_app, text_buffer);
|
|
|
|
}
|
|
|
|
if(html_app != NULL){
|
2020-05-01 11:28:35 +02:00
|
|
|
append_to_html_body(html_app, html_buffer);
|
2020-05-01 01:11:44 +02:00
|
|
|
|
|
|
|
}
|
2020-05-01 00:39:18 +02:00
|
|
|
|
|
|
|
free(html_buffer);
|
|
|
|
free(text_buffer);
|
|
|
|
free(chosen_filename);
|
2020-04-30 22:58:07 +02:00
|
|
|
free_submails(mail);
|
|
|
|
free(mail);
|
2020-05-01 02:12:34 +02:00
|
|
|
return 1;
|
2020-04-30 00:27:03 +02:00
|
|
|
}
|
2020-04-30 01:31:47 +02:00
|
|
|
|