diff --git a/crates/common/src/lib.rs b/crates/common/src/lib.rs index 7a04b830..914aca31 100644 --- a/crates/common/src/lib.rs +++ b/crates/common/src/lib.rs @@ -844,7 +844,7 @@ impl MailboxCache { } } -pub const DEFAULT_LOGO: &str = r#" +pub const DEFAULT_LOGO_RAW: &str = r#" @@ -853,3 +853,61 @@ pub const DEFAULT_LOGO: &str = r#" "#; + +pub const DEFAULT_LOGO_BASE64: &str = + "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 +AElFTkSuQmCC"; diff --git a/crates/directory/src/backend/internal/manage.rs b/crates/directory/src/backend/internal/manage.rs index b950ca82..47a38ebb 100644 --- a/crates/directory/src/backend/internal/manage.rs +++ b/crates/directory/src/backend/internal/manage.rs @@ -1149,7 +1149,7 @@ impl ManageDirectory for Store { } ( PrincipalAction::Set, - PrincipalField::Description | PrincipalField::Picture, + PrincipalField::Description, PrincipalValue::String(value), ) => { if !value.is_empty() { @@ -1158,6 +1158,14 @@ impl ManageDirectory for Store { principal.description = None; } } + (PrincipalAction::Set, PrincipalField::Picture, PrincipalValue::String(value)) => { + principal + .data + .retain(|v| !matches!(v, PrincipalData::Picture(_))); + if !value.is_empty() { + principal.data.push(PrincipalData::Picture(value)); + } + } (PrincipalAction::Set, PrincipalField::Quota, PrincipalValue::Integer(quota)) if matches!( principal_type, diff --git a/crates/services/src/task_manager/alarm.rs b/crates/services/src/task_manager/alarm.rs index 59e19e3c..e62549c5 100644 --- a/crates/services/src/task_manager/alarm.rs +++ b/crates/services/src/task_manager/alarm.rs @@ -11,7 +11,7 @@ use calcard::{ }; use chrono::{DateTime, Locale}; use common::{ - DEFAULT_LOGO, Server, + DEFAULT_LOGO_BASE64, Server, auth::AccessToken, config::groupware::CalendarTemplateVariable, i18n, @@ -136,11 +136,20 @@ async fn send_alarm( None } }; - let (logo_content_type, logo_contents) = if let Some(logo) = &logo { - (logo.content_type.as_ref(), logo.contents.as_slice()) + let logo = if let Some(logo) = &logo { + MimePart::new( + ContentType::new(logo.content_type.as_ref()), + BodyPart::Binary(logo.contents.as_slice().into()), + ) } else { - ("image/svg+xml", DEFAULT_LOGO.as_bytes()) - }; + MimePart::new( + ContentType::new("image/png"), + BodyPart::Binary(DEFAULT_LOGO_BASE64.as_bytes().into()), + ) + .transfer_encoding("base64") + } + .inline() + .cid(&logo_cid); // Build message let mail_from = if let Some(from_email) = &server.core.groupware.alarms_from_email { @@ -158,7 +167,7 @@ async fn send_alarm( .header("Reply-To", HeaderType::Text(account_main_email.into())) .subject(tpl.subject) .body(MimePart::new( - ContentType::new("multipart/mixed"), + ContentType::new("multipart/related"), BodyPart::Multipart(vec![ MimePart::new( ContentType::new("multipart/alternative"), @@ -173,12 +182,7 @@ async fn send_alarm( ), ]), ), - MimePart::new( - ContentType::new(logo_content_type), - BodyPart::Binary(logo_contents.into()), - ) - .inline() - .cid(&logo_cid), + logo, ]), )) .write_to_vec() diff --git a/crates/services/src/task_manager/imip.rs b/crates/services/src/task_manager/imip.rs index bc6d7b43..5d1f1158 100644 --- a/crates/services/src/task_manager/imip.rs +++ b/crates/services/src/task_manager/imip.rs @@ -15,7 +15,7 @@ use calcard::{ }; use chrono::{DateTime, Locale}; use common::{ - DEFAULT_LOGO, Server, + DEFAULT_LOGO_BASE64, Server, auth::AccessToken, config::groupware::CalendarTemplateVariable, i18n, @@ -124,12 +124,21 @@ async fn send_imip( None } }; - let (logo_content_type, logo_contents) = if let Some(logo) = &logo { - (logo.content_type.as_ref(), logo.contents.as_slice()) - } else { - ("image/svg+xml", DEFAULT_LOGO.as_bytes()) - }; let logo_cid = format!("logo.{}@{sender_domain}", now()); + let logo = if let Some(logo) = &logo { + MimePart::new( + ContentType::new(logo.content_type.as_ref()), + BodyPart::Binary(logo.contents.as_slice().into()), + ) + } else { + MimePart::new( + ContentType::new("image/png"), + BodyPart::Binary(DEFAULT_LOGO_BASE64.as_bytes().into()), + ) + .transfer_encoding("base64") + } + .inline() + .cid(&logo_cid); for itip_message in imip.messages.iter() { for recipient in itip_message.to.iter() { @@ -148,7 +157,13 @@ async fn send_imip( // Build message let message = MessageBuilder::new() - .from((access_token.name.as_str(), itip_message.from.as_str())) + .from(( + access_token + .description + .as_deref() + .unwrap_or(access_token.name.as_str()), + itip_message.from.as_str(), + )) .to(recipient.as_str()) .header("Auto-Submitted", HeaderType::Text("auto-generated".into())) .header( @@ -160,16 +175,22 @@ async fn send_imip( ContentType::new("multipart/mixed"), BodyPart::Multipart(vec![ MimePart::new( - ContentType::new("multipart/alternative"), + ContentType::new("multipart/related"), BodyPart::Multipart(vec![ MimePart::new( - ContentType::new("text/plain"), - BodyPart::Text(txt_body.into()), - ), - MimePart::new( - ContentType::new("text/html"), - BodyPart::Text(tpl.body.as_str().into()), + ContentType::new("multipart/alternative"), + BodyPart::Multipart(vec![ + MimePart::new( + ContentType::new("text/plain"), + BodyPart::Text(txt_body.into()), + ), + MimePart::new( + ContentType::new("text/html"), + BodyPart::Text(tpl.body.as_str().into()), + ), + ]), ), + logo.clone(), ]), ), MimePart::new( @@ -179,12 +200,6 @@ async fn send_imip( BodyPart::Text(itip_message.message.as_str().into()), ) .attachment("event.ics"), - MimePart::new( - ContentType::new(logo_content_type), - BodyPart::Binary(logo_contents.into()), - ) - .inline() - .cid(logo_cid.as_str()), ]), )) .write_to_vec()