diff --git a/src/constants.rs b/src/constants.rs index 9e74fba86..dfa5960b1 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -13,6 +13,24 @@ pub enum MoveState { Moving = 3, } +// some defaults +pub const DC_E2EE_DEFAULT_ENABLED: i32 = 1; +pub const DC_MDNS_DEFAULT_ENABLED: i32 = 1; +pub const DC_INBOX_WATCH_DEFAULT: i32 = 1; +pub const DC_SENTBOX_WATCH_DEFAULT: i32 = 1; +pub const DC_MVBOX_WATCH_DEFAULT: i32 = 1; +pub const DC_MVBOX_MOVE_DEFAULT: i32 = 1; + +pub const DC_CHAT_NOT_BLOCKED: i32 = 0; +pub const DC_CHAT_MANUALLY_BLOCKED: i32 = 1; +pub const DC_CHAT_DEADDROP_BLOCKED: i32 = 2; + +pub const DC_IMAP_SEEN: u32 = 0x1; + +pub const DC_HANDSHAKE_CONTINUE_NORMAL_PROCESSING: i32 = 0x01; +pub const DC_HANDSHAKE_STOP_NORMAL_PROCESSING: i32 = 0x02; +pub const DC_HANDSHAKE_ADD_DELETE_JOB: i32 = 0x04; + pub const DC_GCL_ARCHIVED_ONLY: usize = 0x01; pub const DC_GCL_NO_SPECIALS: usize = 0x02; pub const DC_GCL_ADD_ALLDONE_HINT: usize = 0x04; diff --git a/src/dc_mimeparser.rs b/src/dc_mimeparser.rs index abd7eba67..325c7f233 100644 --- a/src/dc_mimeparser.rs +++ b/src/dc_mimeparser.rs @@ -161,12 +161,7 @@ pub unsafe fn dc_mimeparser_parse( if !field.is_null() && (*field).fld_type == MAILIMF_FIELD_SUBJECT as libc::c_int { mimeparser.subject = dc_decode_header_words((*(*field).fld_data.fld_subject).sbj_value) } - if !dc_mimeparser_lookup_optional_field( - mimeparser, - b"Chat-Version\x00" as *const u8 as *const libc::c_char, - ) - .is_null() - { + if !dc_mimeparser_lookup_optional_field(mimeparser, "Chat-Version").is_null() { mimeparser.is_send_by_messenger = 1i32 } if !dc_mimeparser_lookup_field(mimeparser, "Autocrypt-Setup-Message").is_null() { @@ -201,10 +196,7 @@ pub unsafe fn dc_mimeparser_parse( } } } else { - optional_field = dc_mimeparser_lookup_optional_field( - mimeparser, - b"Chat-Content\x00" as *const u8 as *const libc::c_char, - ); + optional_field = dc_mimeparser_lookup_optional_field(mimeparser, "Chat-Content"); if !optional_field.is_null() && !(*optional_field).fld_value.is_null() { if strcmp( (*optional_field).fld_value, @@ -312,11 +304,7 @@ pub unsafe fn dc_mimeparser_parse( } if mimeparser.parts.len() == 1 { if mimeparser.parts[0].type_0 == 40i32 { - if !dc_mimeparser_lookup_optional_field( - mimeparser, - b"Chat-Voice-Message\x00" as *const u8 as *const libc::c_char, - ) - .is_null() + if !dc_mimeparser_lookup_optional_field(mimeparser, "Chat-Voice-Message").is_null() { let part_mut = &mut mimeparser.parts[0]; part_mut.type_0 = 41i32 @@ -324,10 +312,7 @@ pub unsafe fn dc_mimeparser_parse( } let part = &mimeparser.parts[0]; if part.type_0 == 40i32 || part.type_0 == 41i32 || part.type_0 == 50i32 { - let field_0 = dc_mimeparser_lookup_optional_field( - mimeparser, - b"Chat-Duration\x00" as *const u8 as *const libc::c_char, - ); + let field_0 = dc_mimeparser_lookup_optional_field(mimeparser, "Chat-Duration"); if !field_0.is_null() { let duration_ms: libc::c_int = dc_atoi_null_is_0((*field_0).fld_value); if duration_ms > 0i32 && duration_ms < 24i32 * 60i32 * 60i32 * 1000i32 { @@ -338,10 +323,8 @@ pub unsafe fn dc_mimeparser_parse( } } if 0 == mimeparser.decrypting_failed { - let dn_field: *const mailimf_optional_field = dc_mimeparser_lookup_optional_field( - mimeparser, - b"Chat-Disposition-Notification-To\x00" as *const u8 as *const libc::c_char, - ); + let dn_field: *const mailimf_optional_field = + dc_mimeparser_lookup_optional_field(mimeparser, "Chat-Disposition-Notification-To"); if !dn_field.is_null() && dc_mimeparser_get_last_nonmeta(mimeparser).is_some() { let mut mb_list: *mut mailimf_mailbox_list = 0 as *mut mailimf_mailbox_list; let mut index_0: size_t = 0i32 as size_t; @@ -459,11 +442,11 @@ pub fn dc_mimeparser_lookup_field( pub unsafe fn dc_mimeparser_lookup_optional_field( mimeparser: &dc_mimeparser_t, - field_name: *const libc::c_char, + field_name: &str, ) -> *mut mailimf_optional_field { let field = mimeparser .header - .get(as_str(field_name)) + .get(field_name) .map(|v| *v) .unwrap_or_else(|| std::ptr::null_mut()); if !field.is_null() && (*field).fld_type == MAILIMF_FIELD_OPTIONAL_FIELD as libc::c_int { @@ -1184,7 +1167,7 @@ unsafe fn dc_mimeparser_add_single_part_if_known( /* check header directly as is_send_by_messenger is not yet set up */ let is_msgrmsg = (!dc_mimeparser_lookup_optional_field( &mimeparser, - b"Chat-Version\x00" as *const u8 as *const libc::c_char, + "Chat-Version", ) .is_null()) as libc::c_int; @@ -1552,10 +1535,8 @@ pub unsafe fn dc_mimeparser_is_mailinglist_message(mimeparser: &dc_mimeparser_t) if !dc_mimeparser_lookup_field(&mimeparser, "List-Id").is_null() { return 1i32; } - let precedence: *mut mailimf_optional_field = dc_mimeparser_lookup_optional_field( - mimeparser, - b"Precedence\x00" as *const u8 as *const libc::c_char, - ); + let precedence: *mut mailimf_optional_field = + dc_mimeparser_lookup_optional_field(mimeparser, "Precedence"); if !precedence.is_null() { if strcasecmp( (*precedence).fld_value, diff --git a/src/dc_receive_imf.rs b/src/dc_receive_imf.rs index c6aceadcf..08197ca9f 100644 --- a/src/dc_receive_imf.rs +++ b/src/dc_receive_imf.rs @@ -22,6 +22,7 @@ use crate::dc_msg::*; use crate::dc_securejoin::*; use crate::dc_strencode::*; use crate::dc_tools::*; +use crate::error::Result; use crate::param::*; use crate::peerstate::*; use crate::sql; @@ -29,48 +30,15 @@ use crate::stock::StockMessage; use crate::types::*; use crate::x::*; +/// Receive a message and add it to the database. pub unsafe fn dc_receive_imf( context: &Context, imf_raw_not_terminated: *const libc::c_char, imf_raw_bytes: size_t, server_folder: impl AsRef, - server_uid: uint32_t, - flags: uint32_t, + server_uid: u32, + flags: u32, ) { - let mut current_block: u64; - /* the function returns the number of created messages in the database */ - let mut incoming: libc::c_int = 1; - let mut incoming_origin = Origin::Unknown; - let mut to_self: libc::c_int = 0; - let mut from_id: uint32_t = 0 as uint32_t; - let mut from_id_blocked: libc::c_int = 0; - let mut to_id: uint32_t = 0 as uint32_t; - let mut chat_id: uint32_t = 0 as uint32_t; - let mut chat_id_blocked: libc::c_int = 0; - let mut state: libc::c_int; - let mut hidden: libc::c_int = 0; - let mut msgrmsg: libc::c_int; - let mut add_delete_job: libc::c_int = 0; - let mut insert_msg_id: uint32_t = 0 as uint32_t; - - /* Message-ID from the header */ - let mut rfc724_mid = 0 as *mut libc::c_char; - let mut sort_timestamp = 0; - let mut sent_timestamp = 0; - let mut rcvd_timestamp = 0; - let mut field: *const mailimf_field; - let mut mime_in_reply_to = 0 as *mut libc::c_char; - let mut mime_references = 0 as *mut libc::c_char; - let mut created_db_entries = Vec::new(); - let mut create_event_to_send = Some(Event::MSGS_CHANGED); - let mut rr_event_to_send = Vec::new(); - let mut txt_raw = 0 as *mut libc::c_char; - - // XXX converting the below "to_ids" to a Vec quickly leads to lots of changes - // so we keep it as a dc_array for now - let to_ids = dc_array_new(16); - assert!(!to_ids.is_null()); - info!( context, 0, @@ -83,756 +51,201 @@ pub unsafe fn dc_receive_imf( server_uid, ); + // Parse the imf to mailimf_message. normally, this is done by mailimf_message_parse(), + // however, as we also need the MIME data, + // we use mailmime_parse() through dc_mimeparser (both call mailimf_struct_multiple_parse() + // somewhen, I did not found out anything that speaks against this approach yet) + let mut mime_parser = dc_mimeparser_new(context); dc_mimeparser_parse(&mut mime_parser, imf_raw_not_terminated, imf_raw_bytes); + if mime_parser.header.is_empty() { - info!(context, 0, "No header.",); - } else { - /* Error - even adding an empty record won't help as we do not know the message ID */ - field = dc_mimeparser_lookup_field(&mut mime_parser, "Date"); - if !field.is_null() && (*field).fld_type == MAILIMF_FIELD_ORIG_DATE as libc::c_int { - let orig_date: *mut mailimf_orig_date = (*field).fld_data.fld_orig_date; - if !orig_date.is_null() { - sent_timestamp = dc_timestamp_from_date((*orig_date).dt_date_time) + // Error - even adding an empty record won't help as we do not know the message ID + info!(context, 0, "No header."); + return; + } + + // the function returns the number of created messages in the database + let mut incoming = 1; + let mut incoming_origin = Origin::Unknown; + let mut to_self = 0; + let mut from_id = 0u32; + let mut from_id_blocked = 0; + let mut to_id = 0u32; + let mut chat_id = 0; + let mut hidden = 0; + + let mut add_delete_job: libc::c_int = 0; + let mut insert_msg_id = 0; + + // Message-ID from the header + let rfc724_mid = std::ptr::null_mut(); + let mut sent_timestamp = 0; + let mut created_db_entries = Vec::new(); + let mut create_event_to_send = Some(Event::MSGS_CHANGED); + let mut rr_event_to_send = Vec::new(); + + // XXX converting the below "to_ids" to a Vec quickly leads to lots of changes + // so we keep it as a dc_array for now + let to_ids = dc_array_new(16); + assert!(!to_ids.is_null()); + + // helper method to handle early exit and memory cleanup + let cleanup = |context: &Context, + rfc724_mid: *mut libc::c_char, + to_ids: *mut dc_array_t, + create_event_to_send: &Option, + created_db_entries: &Vec<(usize, usize)>, + rr_event_to_send: &Vec<(u32, u32)>| { + free(rfc724_mid.cast()); + dc_array_unref(to_ids); + + if let Some(create_event_to_send) = create_event_to_send { + for (msg_id, insert_id) in created_db_entries { + context.call_cb(*create_event_to_send, *msg_id, *insert_id); } } - field = dc_mimeparser_lookup_field(&mime_parser, "From"); - if !field.is_null() && (*field).fld_type == MAILIMF_FIELD_FROM as libc::c_int { - let fld_from: *mut mailimf_from = (*field).fld_data.fld_from; - if !fld_from.is_null() { - let mut check_self: libc::c_int = 0; - let from_list: *mut dc_array_t = dc_array_new(16 as size_t); - dc_add_or_lookup_contacts_by_mailbox_list( - context, - (*fld_from).frm_mb_list, - Origin::IncomingUnknownFrom, - from_list, - &mut check_self, - ); - if 0 != check_self { - incoming = 0; - if 0 != dc_mimeparser_sender_equals_recipient(&mime_parser) { - from_id = 1 as uint32_t - } - } else if dc_array_get_cnt(from_list) >= 1 { - from_id = dc_array_get_id(from_list, 0 as size_t); - incoming_origin = - Contact::get_origin_by_id(context, from_id, &mut from_id_blocked) - } - dc_array_unref(from_list); - } + for (chat_id, msg_id) in rr_event_to_send { + context.call_cb(Event::MSG_READ, *chat_id as uintptr_t, *msg_id as uintptr_t); } - field = dc_mimeparser_lookup_field(&mime_parser, "To"); - if !field.is_null() && (*field).fld_type == MAILIMF_FIELD_TO as libc::c_int { - let fld_to: *mut mailimf_to = (*field).fld_data.fld_to; - if !fld_to.is_null() { - dc_add_or_lookup_contacts_by_address_list( - context, - (*fld_to).to_addr_list, - if 0 == incoming { - Origin::OutgoingTo - } else if incoming_origin.is_verified() { - Origin::IncomingTo - } else { - Origin::IncomingUnknownTo - }, - to_ids, - &mut to_self, - ); - } + }; + + if let Some(field) = lookup_field(&mime_parser, "Date", MAILIMF_FIELD_ORIG_DATE) { + let orig_date = (*field).fld_data.fld_orig_date; + if !orig_date.is_null() { + // is not yet checked against bad times! we do this later if we have the database information. + sent_timestamp = dc_timestamp_from_date((*orig_date).dt_date_time) } - if dc_mimeparser_get_last_nonmeta(&mut mime_parser).is_some() { - field = dc_mimeparser_lookup_field(&mime_parser, "Cc"); - if !field.is_null() && (*field).fld_type == MAILIMF_FIELD_CC as libc::c_int { - let fld_cc: *mut mailimf_cc = (*field).fld_data.fld_cc; - if !fld_cc.is_null() { - dc_add_or_lookup_contacts_by_address_list( - context, - (*fld_cc).cc_addr_list, - if 0 == incoming { - Origin::OutgoingCc - } else if incoming_origin.is_verified() { - Origin::IncomingCc - } else { - Origin::IncomingUnknownCc - }, - to_ids, - 0 as *mut libc::c_int, - ); + } + + // get From: and check if it is known (for known From:'s we add the other To:/Cc: in the 3rd pass) + // or if From: is equal to SELF (in this case, it is any outgoing messages, + // we do not check Return-Path any more as this is unreliable, see issue #150 + if let Some(field) = lookup_field(&mime_parser, "From", MAILIMF_FIELD_FROM) { + let fld_from = (*field).fld_data.fld_from; + if !fld_from.is_null() { + let mut check_self = 0; + let from_list = dc_array_new(16 as size_t); + dc_add_or_lookup_contacts_by_mailbox_list( + context, + (*fld_from).frm_mb_list, + Origin::IncomingUnknownFrom, + from_list, + &mut check_self, + ); + if 0 != check_self { + incoming = 0; + if 0 != dc_mimeparser_sender_equals_recipient(&mime_parser) { + from_id = DC_CONTACT_ID_SELF as u32; } + } else if dc_array_get_cnt(from_list) >= 1 { + // if there is no from given, from_id stays 0 which is just fine. These messages + // are very rare, however, we have to add them to the database (they go to the + // "deaddrop" chat) to avoid a re-download from the server. See also [**] + from_id = dc_array_get_id(from_list, 0); + incoming_origin = Contact::get_origin_by_id(context, from_id, &mut from_id_blocked) } - field = dc_mimeparser_lookup_field(&mime_parser, "Message-ID"); - if !field.is_null() && (*field).fld_type == MAILIMF_FIELD_MESSAGE_ID as libc::c_int { - let fld_message_id: *mut mailimf_message_id = (*field).fld_data.fld_message_id; - if !fld_message_id.is_null() { - rfc724_mid = dc_strdup((*fld_message_id).mid_value) - } - } - if rfc724_mid.is_null() { - rfc724_mid = dc_create_incoming_rfc724_mid(sent_timestamp, from_id, to_ids); - if rfc724_mid.is_null() { - info!(context, 0, "Cannot create Message-ID.",); - current_block = 16282941964262048061; + dc_array_unref(from_list); + } + } + + // Make sure, to_ids starts with the first To:-address (Cc: is added in the loop below pass) + if let Some(field) = lookup_field(&mime_parser, "To", MAILIMF_FIELD_TO) { + let fld_to = (*field).fld_data.fld_to; + if !fld_to.is_null() { + dc_add_or_lookup_contacts_by_address_list( + context, + (*fld_to).to_addr_list, + if 0 == incoming { + Origin::OutgoingTo + } else if incoming_origin.is_verified() { + Origin::IncomingTo } else { - current_block = 777662472977924419; - } - } else { - current_block = 777662472977924419; - } - match current_block { - 16282941964262048061 => {} - _ => { - /* check, if the mail is already in our database - if so, just update the folder/uid (if the mail was moved around) and finish. - (we may get a mail twice eg. if it is moved between folders. make sure, this check is done eg. before securejoin-processing) */ - let mut old_server_folder: *mut libc::c_char = 0 as *mut libc::c_char; - let mut old_server_uid: uint32_t = 0 as uint32_t; - if 0 != dc_rfc724_mid_exists( - context, - rfc724_mid, - &mut old_server_folder, - &mut old_server_uid, - ) { - if as_str(old_server_folder) != server_folder.as_ref() - || old_server_uid != server_uid - { - dc_update_server_uid( - context, - rfc724_mid, - server_folder.as_ref(), - server_uid, - ); - } - free(old_server_folder as *mut libc::c_void); - info!(context, 0, "Message already in DB."); - current_block = 16282941964262048061; - } else { - msgrmsg = mime_parser.is_send_by_messenger; - if msgrmsg == 0 - && 0 != dc_is_reply_to_messenger_message(context, &mime_parser) - { - msgrmsg = 2 - } - /* incoming non-chat messages may be discarded; - maybe this can be optimized later, - by checking the state before the message body is downloaded */ - let mut allow_creation: libc::c_int = 1; - if mime_parser.is_system_message != DC_CMD_AUTOCRYPT_SETUP_MESSAGE - && msgrmsg == 0 - { - let show_emails = context - .sql - .get_config_int(context, "show_emails") - .unwrap_or_default(); - if show_emails == 0 { - chat_id = 3; - allow_creation = 0 - } else if show_emails == 1 { - allow_creation = 0 - } - } - if 0 != incoming { - state = if 0 != flags & 0x1 { 16 } else { 10 }; - to_id = 1 as uint32_t; - if !dc_mimeparser_lookup_field(&mime_parser, "Secure-Join").is_null() { - msgrmsg = 1; - chat_id = 0 as uint32_t; - allow_creation = 1; - let handshake: libc::c_int = - dc_handle_securejoin_handshake(context, &mime_parser, from_id); - if 0 != handshake & 0x2 { - hidden = 1; - add_delete_job = handshake & 0x4; - state = 16 - } - } - let mut test_normal_chat_id: uint32_t = 0 as uint32_t; - let mut test_normal_chat_id_blocked: libc::c_int = 0; - dc_lookup_real_nchat_by_contact_id( - context, - from_id, - &mut test_normal_chat_id, - &mut test_normal_chat_id_blocked, - ); - if chat_id == 0 as libc::c_uint { - let create_blocked: libc::c_int = if 0 != test_normal_chat_id - && test_normal_chat_id_blocked == 0 - || incoming_origin.is_start_new_chat() - { - 0 - } else { - 2 - }; - create_or_lookup_group( - context, - &mut mime_parser, - allow_creation, - create_blocked, - from_id as int32_t, - to_ids, - &mut chat_id, - &mut chat_id_blocked, - ); - if 0 != chat_id && 0 != chat_id_blocked && 0 == create_blocked { - dc_unblock_chat(context, chat_id); - chat_id_blocked = 0 - } - } - if chat_id == 0 as libc::c_uint { - if 0 != dc_mimeparser_is_mailinglist_message(&mime_parser) { - chat_id = 3 as uint32_t; - info!( - context, - 0, "Message belongs to a mailing list and is ignored.", - ); - } - } - if chat_id == 0 as libc::c_uint { - let create_blocked_0: libc::c_int = - if incoming_origin.is_start_new_chat() || from_id == to_id { - 0 - } else { - 2 - }; - if 0 != test_normal_chat_id { - chat_id = test_normal_chat_id; - chat_id_blocked = test_normal_chat_id_blocked - } else if 0 != allow_creation { - dc_create_or_lookup_nchat_by_contact_id( - context, - from_id, - create_blocked_0, - &mut chat_id, - &mut chat_id_blocked, - ); - } - if 0 != chat_id && 0 != chat_id_blocked { - if 0 == create_blocked_0 { - dc_unblock_chat(context, chat_id); - chat_id_blocked = 0 - } else if 0 - != dc_is_reply_to_known_message(context, &mime_parser) - { - Contact::scaleup_origin_by_id( - context, - from_id, - Origin::IncomingReplyTo, - ); - info!( - context, - 0, - "Message is a reply to a known message, mark sender as known.", - ); - incoming_origin = if incoming_origin.is_verified() { - incoming_origin - } else { - Origin::IncomingReplyTo - } - } - } - } - if chat_id == 0 as libc::c_uint { - chat_id = 3 as uint32_t - } - if 0 != chat_id_blocked && state == 10 { - if !incoming_origin.is_verified() && msgrmsg == 0 { - state = 13; - } - } - } else { - state = 26; - from_id = 1 as uint32_t; - if dc_array_get_cnt(to_ids) >= 1 { - to_id = dc_array_get_id(to_ids, 0 as size_t); - if chat_id == 0 as libc::c_uint { - create_or_lookup_group( - context, - &mut mime_parser, - allow_creation, - 0, - from_id as int32_t, - to_ids, - &mut chat_id, - &mut chat_id_blocked, - ); - if 0 != chat_id && 0 != chat_id_blocked { - dc_unblock_chat(context, chat_id); - chat_id_blocked = 0 - } - } - if chat_id == 0 as libc::c_uint && 0 != allow_creation { - let create_blocked_1: libc::c_int = if 0 != msgrmsg - && !Contact::is_blocked_load(context, to_id) - { - 0 - } else { - 2 - }; - dc_create_or_lookup_nchat_by_contact_id( - context, - to_id, - create_blocked_1, - &mut chat_id, - &mut chat_id_blocked, - ); - if 0 != chat_id && 0 != chat_id_blocked && 0 == create_blocked_1 - { - dc_unblock_chat(context, chat_id); - chat_id_blocked = 0 - } - } - } - if chat_id == 0 as libc::c_uint { - if dc_array_get_cnt(to_ids) == 0 && 0 != to_self { - dc_create_or_lookup_nchat_by_contact_id( - context, - 1 as uint32_t, - 0, - &mut chat_id, - &mut chat_id_blocked, - ); - if 0 != chat_id && 0 != chat_id_blocked { - dc_unblock_chat(context, chat_id); - chat_id_blocked = 0 - } - } - } - if chat_id == 0 as libc::c_uint { - chat_id = 3 as uint32_t - } - } - calc_timestamps( - context, - chat_id, - from_id, - sent_timestamp, - if 0 != flags & 0x1 { 0 } else { 1 }, - &mut sort_timestamp, - &mut sent_timestamp, - &mut rcvd_timestamp, - ); - dc_unarchive_chat(context, chat_id); - // if the mime-headers should be saved, find out its size - // (the mime-header ends with an empty line) - let save_mime_headers = context - .sql - .get_config_int(context, "save_mime_headers") - .unwrap_or_default(); - field = dc_mimeparser_lookup_field(&mime_parser, "In-Reply-To"); - if !field.is_null() - && (*field).fld_type == MAILIMF_FIELD_IN_REPLY_TO as libc::c_int - { - let fld_in_reply_to: *mut mailimf_in_reply_to = - (*field).fld_data.fld_in_reply_to; - if !fld_in_reply_to.is_null() { - mime_in_reply_to = dc_str_from_clist( - (*(*field).fld_data.fld_in_reply_to).mid_list, - b" \x00" as *const u8 as *const libc::c_char, - ) - } - } - field = dc_mimeparser_lookup_field(&mime_parser, "References"); - if !field.is_null() - && (*field).fld_type == MAILIMF_FIELD_REFERENCES as libc::c_int - { - let fld_references: *mut mailimf_references = - (*field).fld_data.fld_references; - if !fld_references.is_null() { - mime_references = dc_str_from_clist( - (*(*field).fld_data.fld_references).mid_list, - b" \x00" as *const u8 as *const libc::c_char, - ) - } - } - let icnt = mime_parser.parts.len(); - - context.sql.prepare( - "INSERT INTO msgs \ - (rfc724_mid, server_folder, server_uid, chat_id, from_id, to_id, timestamp, \ - timestamp_sent, timestamp_rcvd, type, state, msgrmsg, txt, txt_raw, param, \ - bytes, hidden, mime_headers, mime_in_reply_to, mime_references) \ - VALUES (?,?,?,?,?,?, ?,?,?,?,?,?, ?,?,?,?,?,?, ?,?);", - |mut stmt, conn| { - let mut i = 0; - loop { - if !(i < icnt) { - current_block = 2756754640271984560; - break; - } - let part = &mut mime_parser.parts[i]; - if part.is_meta == 0 { - if !mime_parser.location_kml.is_none() - && icnt == 1 - && !part.msg.is_null() - && (strcmp( - part.msg, - b"-location-\x00" as *const u8 as *const libc::c_char, - ) == 0 - || *part.msg.offset(0isize) as libc::c_int == 0) - { - hidden = 1; - if state == 10 { - state = 13 - } - } - if part.type_0 == 10 { - txt_raw = dc_mprintf( - b"%s\n\n%s\x00" as *const u8 as *const libc::c_char, - if !mime_parser.subject.is_null() { - mime_parser.subject - } else { - b"\x00" as *const u8 as *const libc::c_char - }, - part.msg_raw, - ) - } - if 0 != mime_parser.is_system_message { - - part.param.set_int( Param::Cmd, - mime_parser.is_system_message, - ); - } - - let res = stmt.execute(params![ - as_str(rfc724_mid), - server_folder.as_ref(), - server_uid as libc::c_int, - chat_id as libc::c_int, - from_id as libc::c_int, - to_id as libc::c_int, - sort_timestamp, - sent_timestamp, - rcvd_timestamp, - part.type_0, - state, - msgrmsg, - if !part.msg.is_null() { - as_str(part.msg) - } else { - "" - }, - // txt_raw might contain invalid utf8 - if !txt_raw.is_null() { - to_string_lossy(txt_raw) - } else { - String::new() - }, - part.param.to_string(), - part.bytes, - hidden, - if 0 != save_mime_headers { - let body_string = std::str::from_utf8(std::slice::from_raw_parts(imf_raw_not_terminated as *const u8, imf_raw_bytes)).unwrap(); - - Some(body_string) - } else { - None - }, - to_string(mime_in_reply_to), - to_string(mime_references), - ]); - - if res.is_err() { - info!(context, 0, "Cannot write DB.",); - /* i/o error - there is nothing more we can do - in other cases, we try to write at least an empty record */ - current_block = 16282941964262048061; - break; - } else { - free(txt_raw as *mut libc::c_void); - txt_raw = 0 as *mut libc::c_char; - insert_msg_id = sql::get_rowid_with_conn( - context, - conn, - "msgs", - "rfc724_mid", - as_str(rfc724_mid), - ); - created_db_entries.push((chat_id as usize, insert_msg_id as usize)); - } - } - i = i.wrapping_add(1) - } - Ok(()) - } - ).unwrap(); // TODO: better error handling - match current_block { - 16282941964262048061 => {} - _ => { - info!( - context, - 0, - "Message has {} parts and is assigned to chat #{}.", - icnt, - chat_id, - ); - if chat_id == 3 as libc::c_uint { - create_event_to_send = None; - } else if 0 != incoming && state == 10 { - if 0 != from_id_blocked { - create_event_to_send = None; - } else if 0 != chat_id_blocked { - create_event_to_send = Some(Event::MSGS_CHANGED); - } else { - create_event_to_send = Some(Event::INCOMING_MSG); - } - } - dc_do_heuristics_moves( - context, - server_folder.as_ref(), - insert_msg_id, - ); - current_block = 18330534242458572360; - } - } - } - } - } - } else { - if sent_timestamp > time() { - sent_timestamp = time() - } - current_block = 18330534242458572360; + Origin::IncomingUnknownTo + }, + to_ids, + &mut to_self, + ); } - match current_block { - 16282941964262048061 => {} - _ => { - if !mime_parser.reports.is_empty() { - let mdns_enabled = context - .sql - .get_config_int(context, "mdns_enabled") - .unwrap_or_else(|| 1); - for report_root in mime_parser.reports { - let mut mdn_consumed: libc::c_int = 0; - let report_type: *mut mailmime_parameter = mailmime_find_ct_parameter( - report_root, - b"report-type\x00" as *const u8 as *const libc::c_char, - ); - if !(report_root.is_null() - || report_type.is_null() - || (*report_type).pa_value.is_null()) - { - if strcmp( - (*report_type).pa_value, - b"disposition-notification\x00" as *const u8 as *const libc::c_char, - ) == 0 - && (*(*report_root).mm_data.mm_multipart.mm_mp_list).count >= 2 - { - if 0 != mdns_enabled { - let report_data: *mut mailmime = - (if !if !(*(*report_root).mm_data.mm_multipart.mm_mp_list) - .first - .is_null() - { - (*(*(*report_root).mm_data.mm_multipart.mm_mp_list) - .first) - .next - } else { - 0 as *mut clistcell - } - .is_null() - { - (*if !(*(*report_root).mm_data.mm_multipart.mm_mp_list) - .first - .is_null() - { - (*(*(*report_root).mm_data.mm_multipart.mm_mp_list) - .first) - .next - } else { - 0 as *mut clistcell - }) - .data - } else { - 0 as *mut libc::c_void - }) as *mut mailmime; - if !report_data.is_null() - && (*(*(*report_data).mm_content_type).ct_type).tp_type - == MAILMIME_TYPE_COMPOSITE_TYPE as libc::c_int - && (*(*(*(*report_data).mm_content_type).ct_type) - .tp_data - .tp_composite_type) - .ct_type - == MAILMIME_COMPOSITE_TYPE_MESSAGE as libc::c_int - && strcmp( - (*(*report_data).mm_content_type).ct_subtype, - b"disposition-notification\x00" as *const u8 - as *const libc::c_char, - ) == 0 - { - let mut report_body: *const libc::c_char = - 0 as *const libc::c_char; - let mut report_body_bytes: size_t = 0 as size_t; - let mut to_mmap_string_unref: *mut libc::c_char = - 0 as *mut libc::c_char; - if 0 != mailmime_transfer_decode( - report_data, - &mut report_body, - &mut report_body_bytes, - &mut to_mmap_string_unref, - ) { - let mut report_parsed: *mut mailmime = - 0 as *mut mailmime; - let mut dummy: size_t = 0 as size_t; - if mailmime_parse( - report_body, - report_body_bytes, - &mut dummy, - &mut report_parsed, - ) == MAIL_NO_ERROR as libc::c_int - && !report_parsed.is_null() - { - let report_fields: *mut mailimf_fields = - mailmime_find_mailimf_fields(report_parsed); - if !report_fields.is_null() { - let of_disposition: - *mut mailimf_optional_field = - mailimf_find_optional_field(report_fields, - b"Disposition\x00" - as - *const u8 - as - *const libc::c_char); - let of_org_msgid: *mut mailimf_optional_field = - mailimf_find_optional_field( - report_fields, - b"Original-Message-ID\x00" as *const u8 - as *const libc::c_char, - ); - if !of_disposition.is_null() - && !(*of_disposition).fld_value.is_null() - && !of_org_msgid.is_null() - && !(*of_org_msgid).fld_value.is_null() - { - let mut rfc724_mid_0: *mut libc::c_char = - 0 as *mut libc::c_char; - dummy = 0 as size_t; - if mailimf_msg_id_parse( - (*of_org_msgid).fld_value, - strlen((*of_org_msgid).fld_value), - &mut dummy, - &mut rfc724_mid_0, - ) == MAIL_NO_ERROR as libc::c_int - && !rfc724_mid_0.is_null() - { - let mut chat_id_0: uint32_t = - 0 as uint32_t; - let mut msg_id: uint32_t = - 0 as uint32_t; - if 0 != dc_mdn_from_ext( - context, - from_id, - rfc724_mid_0, - sent_timestamp, - &mut chat_id_0, - &mut msg_id, - ) { - rr_event_to_send - .push((chat_id_0, msg_id)); - } - mdn_consumed = (msg_id - != 0 as libc::c_uint) - as libc::c_int; - free(rfc724_mid_0 as *mut libc::c_void); - } - } - } - mailmime_free(report_parsed); - } - if !to_mmap_string_unref.is_null() { - mmap_string_unref(to_mmap_string_unref); - } - } - } - } - if 0 != mime_parser.is_send_by_messenger || 0 != mdn_consumed { - let mut param = Params::new(); - param.set(Param::ServerFolder, server_folder.as_ref()); - param.set_int(Param::ServerUid, server_uid as i32); - if 0 != mime_parser.is_send_by_messenger - && 0 != context - .sql - .get_config_int(context, "mvbox_move") - .unwrap_or_else(|| 1) - { - param.set_int(Param::AlsoMove, 1); - } - dc_job_add(context, 120, 0, param, 0); - } - } - } - } - } - if !mime_parser.message_kml.is_none() && chat_id > 9 as libc::c_uint { - let mut location_id_written = false; - let mut send_event = false; + } - if !mime_parser.message_kml.is_none() - && chat_id > DC_CHAT_ID_LAST_SPECIAL as libc::c_uint - { - let newest_location_id: uint32_t = dc_save_locations( - context, - chat_id, - from_id, - &mime_parser.message_kml.unwrap().locations, - 1, - ); - if 0 != newest_location_id && 0 == hidden { - dc_set_msg_location_id(context, insert_msg_id, newest_location_id); - location_id_written = true; - send_event = true; - } - } + // Add parts + if dc_mimeparser_get_last_nonmeta(&mut mime_parser).is_some() { + if let Err(err) = add_parts( + context, + &mut mime_parser, + imf_raw_not_terminated, + imf_raw_bytes, + incoming, + &mut incoming_origin, + server_folder.as_ref(), + server_uid, + to_ids, + rfc724_mid, + &mut sent_timestamp, + &mut from_id, + from_id_blocked, + &mut hidden, + &mut chat_id, + &mut to_id, + flags, + &mut add_delete_job, + to_self, + &mut insert_msg_id, + &mut created_db_entries, + &mut create_event_to_send, + ) { + info!(context, 0, "{}", err); - if !mime_parser.location_kml.is_none() - && chat_id > DC_CHAT_ID_LAST_SPECIAL as libc::c_uint - { - if !mime_parser.location_kml.as_ref().unwrap().addr.is_null() { - if let Ok(contact) = Contact::get_by_id(context, from_id) { - if !contact.get_addr().is_empty() - && contact.get_addr().to_lowercase() - == as_str(mime_parser.location_kml.as_ref().unwrap().addr) - .to_lowercase() - { - let newest_location_id = dc_save_locations( - context, - chat_id, - from_id, - &mime_parser.location_kml.as_ref().unwrap().locations, - 0, - ); - if newest_location_id != 0 - && hidden == 0 - && !location_id_written - { - dc_set_msg_location_id( - context, - insert_msg_id, - newest_location_id, - ); - } - send_event = true; - } - } - } - } - if send_event { - context.call_cb( - Event::LOCATION_CHANGED, - from_id as uintptr_t, - 0 as uintptr_t, - ); - } - } - - if 0 != add_delete_job && !created_db_entries.is_empty() { - dc_job_add( - context, - DC_JOB_DELETE_MSG_ON_IMAP, - created_db_entries[0].1 as i32, - Params::new(), - 0, - ); - } - } + cleanup( + context, + rfc724_mid, + to_ids, + &create_event_to_send, + &created_db_entries, + &rr_event_to_send, + ); + return; } + } else { + // there are no non-meta data in message, do some basic calculations so that the varaiables + // are correct in the further processing + if sent_timestamp > time() { + sent_timestamp = time() + } + } + + if !mime_parser.reports.is_empty() { + handle_reports( + context, + &mime_parser, + from_id, + sent_timestamp, + &mut rr_event_to_send, + server_folder, + server_uid, + ); + } + + if !mime_parser.message_kml.is_none() && chat_id > DC_CHAT_ID_LAST_SPECIAL as u32 { + save_locations( + context, + &mime_parser, + chat_id, + from_id, + insert_msg_id, + hidden, + ); + } + + if 0 != add_delete_job && !created_db_entries.is_empty() { + dc_job_add( + context, + DC_JOB_DELETE_MSG_ON_IMAP, + created_db_entries[0].1 as i32, + Params::new(), + 0, + ); } info!( @@ -843,30 +256,753 @@ pub unsafe fn dc_receive_imf( to_string(rfc724_mid) ); - free(rfc724_mid as *mut libc::c_void); - free(mime_in_reply_to as *mut libc::c_void); - free(mime_references as *mut libc::c_void); - dc_array_unref(to_ids); - - if let Some(create_event_to_send) = create_event_to_send { - for (msg_id, insert_id) in &created_db_entries { - context.call_cb(create_event_to_send, *msg_id, *insert_id); - } - } - for (chat_id, msg_id) in &rr_event_to_send { - context.call_cb(Event::MSG_READ, *chat_id as uintptr_t, *msg_id as uintptr_t); - } - - free(txt_raw as *mut libc::c_void); + cleanup( + context, + rfc724_mid, + to_ids, + &create_event_to_send, + &created_db_entries, + &rr_event_to_send, + ); +} + +unsafe fn add_parts( + context: &Context, + mut mime_parser: &mut dc_mimeparser_t, + imf_raw_not_terminated: *const libc::c_char, + imf_raw_bytes: size_t, + incoming: i32, + incoming_origin: &mut Origin, + server_folder: impl AsRef, + server_uid: u32, + to_ids: *mut dc_array_t, + mut rfc724_mid: *mut libc::c_char, + sent_timestamp: &mut i64, + from_id: &mut u32, + from_id_blocked: i32, + hidden: &mut libc::c_int, + chat_id: &mut u32, + to_id: &mut u32, + flags: u32, + add_delete_job: &mut libc::c_int, + to_self: i32, + insert_msg_id: &mut u32, + created_db_entries: &mut Vec<(usize, usize)>, + create_event_to_send: &mut Option, +) -> Result<()> { + let mut state: libc::c_int; + let mut msgrmsg: libc::c_int; + let mut chat_id_blocked = 0; + let mut sort_timestamp = 0; + let mut rcvd_timestamp = 0; + let mut mime_in_reply_to = std::ptr::null_mut(); + let mut mime_references = std::ptr::null_mut(); + let mut txt_raw = std::ptr::null_mut(); + + let cleanup = |mime_in_reply_to: *mut libc::c_char, + mime_references: *mut libc::c_char, + txt_raw: *mut libc::c_char| { + free(mime_in_reply_to.cast()); + free(mime_references.cast()); + free(txt_raw.cast()); + }; + + // collect the rest information, CC: is added to the to-list, BCC: is ignored + // (we should not add BCC to groups as this would split groups. We could add them as "known contacts", + // however, the benefit is very small and this may leak data that is expected to be hidden) + if let Some(field) = lookup_field(mime_parser, "Cc", MAILIMF_FIELD_CC) { + let fld_cc = (*field).fld_data.fld_cc; + if !fld_cc.is_null() { + dc_add_or_lookup_contacts_by_address_list( + context, + (*fld_cc).cc_addr_list, + if 0 == incoming { + Origin::OutgoingCc + } else if incoming_origin.is_verified() { + Origin::IncomingCc + } else { + Origin::IncomingUnknownCc + }, + to_ids, + std::ptr::null_mut(), + ); + } + } + + // get Message-ID; if the header is lacking one, generate one based on fields that do never + // change. (missing Message-IDs may come if the mail was set from this account with another + // client that relies in the SMTP server to generate one. + // true eg. for the Webmailer used in all-inkl-KAS) + if let Some(field) = lookup_field(mime_parser, "Message-ID", MAILIMF_FIELD_MESSAGE_ID) { + let fld_message_id = (*field).fld_data.fld_message_id; + if !fld_message_id.is_null() { + rfc724_mid = dc_strdup((*fld_message_id).mid_value) + } + } + + if rfc724_mid.is_null() { + rfc724_mid = dc_create_incoming_rfc724_mid(*sent_timestamp, *from_id, to_ids); + if rfc724_mid.is_null() { + cleanup(mime_in_reply_to, mime_references, txt_raw); + bail!("Cannot create Message-ID"); + } + } + + // check, if the mail is already in our database - if so, just update the folder/uid + // (if the mail was moved around) and finish. (we may get a mail twice eg. if it is + // moved between folders. make sure, this check is done eg. before securejoin-processing) */ + let mut old_server_folder = std::ptr::null_mut(); + let mut old_server_uid = 0; + + if 0 != dc_rfc724_mid_exists( + context, + rfc724_mid, + &mut old_server_folder, + &mut old_server_uid, + ) { + if as_str(old_server_folder) != server_folder.as_ref() || old_server_uid != server_uid { + dc_update_server_uid(context, rfc724_mid, server_folder.as_ref(), server_uid); + } + + free(old_server_folder.cast()); + cleanup(mime_in_reply_to, mime_references, txt_raw); + bail!("Message already in DB"); + } + + // 1 or 0 for yes/no + msgrmsg = mime_parser.is_send_by_messenger; + if msgrmsg == 0 && 0 != dc_is_reply_to_messenger_message(context, mime_parser) { + // 2=no, but is reply to messenger message + msgrmsg = 2; + } + // incoming non-chat messages may be discarded; + // maybe this can be optimized later, by checking the state before the message body is downloaded + let mut allow_creation = 1; + if mime_parser.is_system_message != DC_CMD_AUTOCRYPT_SETUP_MESSAGE && msgrmsg == 0 { + let show_emails = context + .sql + .get_config_int(context, "show_emails") + .unwrap_or_default(); + if show_emails == 0 { + *chat_id = 3; + allow_creation = 0 + } else if show_emails == 1 { + allow_creation = 0 + } + } + + // check if the message introduces a new chat: + // - outgoing messages introduce a chat with the first to: address if they are sent by a messenger + // - incoming messages introduce a chat only for known contacts if they are sent by a messenger + // (of course, the user can add other chats manually later) + if 0 != incoming { + state = if 0 != flags & DC_IMAP_SEEN { + DC_STATE_IN_SEEN + } else { + DC_STATE_IN_FRESH + }; + *to_id = 1; + // handshake messages must be processed _before_ chats are created + // (eg. contacs may be marked as verified) + if !dc_mimeparser_lookup_field(mime_parser, "Secure-Join").is_null() { + // avoid discarding by show_emails setting + msgrmsg = 1; + *chat_id = 0; + allow_creation = 1; + let handshake = dc_handle_securejoin_handshake(context, mime_parser, *from_id); + if 0 != handshake & DC_HANDSHAKE_STOP_NORMAL_PROCESSING { + *hidden = 1; + *add_delete_job = handshake & DC_HANDSHAKE_ADD_DELETE_JOB; + state = DC_STATE_IN_SEEN; + } + } + let mut test_normal_chat_id = 0; + let mut test_normal_chat_id_blocked = 0; + + dc_lookup_real_nchat_by_contact_id( + context, + *from_id, + &mut test_normal_chat_id, + &mut test_normal_chat_id_blocked, + ); + + // get the chat_id - a chat_id here is no indicator that the chat is displayed in the normal list, + // it might also be blocked and displayed in the deaddrop as a result + if *chat_id == 0 { + // try to create a group + // (groups appear automatically only if the _sender_ is known, see core issue #54) + + let create_blocked = if 0 != test_normal_chat_id + && test_normal_chat_id_blocked == DC_CHAT_NOT_BLOCKED + || incoming_origin.is_start_new_chat() + { + DC_CHAT_NOT_BLOCKED + } else { + DC_CHAT_DEADDROP_BLOCKED + }; + + create_or_lookup_group( + context, + &mut mime_parser, + allow_creation, + create_blocked, + *from_id as i32, + to_ids, + chat_id, + &mut chat_id_blocked, + ); + if 0 != *chat_id && 0 != chat_id_blocked && 0 == create_blocked { + dc_unblock_chat(context, *chat_id); + chat_id_blocked = 0; + } + } + + if *chat_id == 0 { + // check if the message belongs to a mailing list + if 0 != dc_mimeparser_is_mailinglist_message(mime_parser) { + *chat_id = 3; + info!( + context, + 0, "Message belongs to a mailing list and is ignored.", + ); + } + } + + if *chat_id == 0 { + // try to create a normal chat + let create_blocked = if incoming_origin.is_start_new_chat() || *from_id == *to_id { + DC_CHAT_NOT_BLOCKED + } else { + DC_CHAT_DEADDROP_BLOCKED + }; + + if 0 != test_normal_chat_id { + *chat_id = test_normal_chat_id; + chat_id_blocked = test_normal_chat_id_blocked + } else if 0 != allow_creation { + dc_create_or_lookup_nchat_by_contact_id( + context, + *from_id, + create_blocked, + chat_id, + &mut chat_id_blocked, + ); + } + if 0 != *chat_id && 0 != chat_id_blocked { + if 0 == create_blocked { + dc_unblock_chat(context, *chat_id); + chat_id_blocked = 0; + } else if 0 != dc_is_reply_to_known_message(context, mime_parser) { + // we do not want any chat to be created implicitly. Because of the origin-scale-up, + // the contact requests will pop up and this should be just fine. + Contact::scaleup_origin_by_id(context, *from_id, Origin::IncomingReplyTo); + info!( + context, + 0, "Message is a reply to a known message, mark sender as known.", + ); + if !incoming_origin.is_verified() { + *incoming_origin = Origin::IncomingReplyTo; + } + } + } + } + if *chat_id == 0 { + // maybe from_id is null or sth. else is suspicious, move message to trash + *chat_id = DC_CHAT_ID_TRASH as u32; + } + + // if the chat_id is blocked, + // for unknown senders and non-delta messages set the state to NOTICED + // to not result in a contact request (this would require the state FRESH) + if 0 != chat_id_blocked && state == DC_STATE_IN_FRESH { + if !incoming_origin.is_verified() && msgrmsg == 0 { + state = DC_STATE_IN_NOTICED; + } + } + } else { + // Outgoing + + // the mail is on the IMAP server, probably it is also delivered. + // We cannot recreate other states (read, error). + state = DC_STATE_OUT_DELIVERED; + *from_id = DC_CONTACT_ID_SELF as u32; + if dc_array_get_cnt(to_ids) >= 1 { + *to_id = dc_array_get_id(to_ids, 0); + if *chat_id == 0 { + create_or_lookup_group( + context, + &mut mime_parser, + allow_creation, + 0, + *from_id as i32, + to_ids, + chat_id, + &mut chat_id_blocked, + ); + if 0 != *chat_id && 0 != chat_id_blocked { + dc_unblock_chat(context, *chat_id); + chat_id_blocked = 0 + } + } + if *chat_id == 0 && 0 != allow_creation { + let create_blocked = if 0 != msgrmsg && !Contact::is_blocked_load(context, *to_id) { + DC_CHAT_NOT_BLOCKED + } else { + DC_CHAT_DEADDROP_BLOCKED + }; + dc_create_or_lookup_nchat_by_contact_id( + context, + *to_id, + create_blocked, + chat_id, + &mut chat_id_blocked, + ); + if 0 != *chat_id && 0 != chat_id_blocked && 0 == create_blocked { + dc_unblock_chat(context, *chat_id); + chat_id_blocked = 0 + } + } + } + if *chat_id == 0 { + if dc_array_get_cnt(to_ids) == 0 && 0 != to_self { + // from_id==to_id==DC_CONTACT_ID_SELF - this is a self-sent messages, + // maybe an Autocrypt Setup Messag + dc_create_or_lookup_nchat_by_contact_id( + context, + 1, + 0, + chat_id, + &mut chat_id_blocked, + ); + if 0 != *chat_id && 0 != chat_id_blocked { + dc_unblock_chat(context, *chat_id); + chat_id_blocked = 0; + } + } + } + if *chat_id == 0 { + *chat_id = DC_CHAT_ID_TRASH as u32; + } + } + // correct message_timestamp, it should not be used before, + // however, we cannot do this earlier as we need from_id to be set + calc_timestamps( + context, + *chat_id, + *from_id, + *sent_timestamp, + if 0 != flags & DC_IMAP_SEEN { 0 } else { 1 }, + &mut sort_timestamp, + sent_timestamp, + &mut rcvd_timestamp, + ); + + // unarchive chat + dc_unarchive_chat(context, *chat_id); + + // if the mime-headers should be saved, find out its size + // (the mime-header ends with an empty line) + let save_mime_headers = context + .sql + .get_config_int(context, "save_mime_headers") + .unwrap_or_default(); + if let Some(field) = lookup_field(mime_parser, "In-Reply-To", MAILIMF_FIELD_IN_REPLY_TO) { + let fld_in_reply_to = (*field).fld_data.fld_in_reply_to; + if !fld_in_reply_to.is_null() { + mime_in_reply_to = dc_str_from_clist( + (*(*field).fld_data.fld_in_reply_to).mid_list, + b" \x00" as *const u8 as *const libc::c_char, + ) + } + } + + if let Some(field) = lookup_field(mime_parser, "References", MAILIMF_FIELD_REFERENCES) { + let fld_references = (*field).fld_data.fld_references; + if !fld_references.is_null() { + mime_references = dc_str_from_clist( + (*(*field).fld_data.fld_references).mid_list, + b" \x00" as *const u8 as *const libc::c_char, + ) + } + } + + // fine, so far. now, split the message into simple parts usable as "short messages" + // and add them to the database (mails sent by other messenger clients should result + // into only one message; mails sent by other clients may result in several messages + // (eg. one per attachment)) + let icnt = mime_parser.parts.len(); + let is_ok = context + .sql + .prepare( + "INSERT INTO msgs \ + (rfc724_mid, server_folder, server_uid, chat_id, from_id, to_id, timestamp, \ + timestamp_sent, timestamp_rcvd, type, state, msgrmsg, txt, txt_raw, param, \ + bytes, hidden, mime_headers, mime_in_reply_to, mime_references) \ + VALUES (?,?,?,?,?,?, ?,?,?,?,?,?, ?,?,?,?,?,?, ?,?);", + |mut stmt, conn| { + for i in 0..icnt { + let part = &mut mime_parser.parts[i]; + if part.is_meta != 0 { + continue; + } + + if !mime_parser.location_kml.is_none() + && icnt == 1 + && !part.msg.is_null() + && (strcmp( + part.msg, + b"-location-\x00" as *const u8 as *const libc::c_char, + ) == 0 + || *part.msg.offset(0) as libc::c_int == 0) + { + *hidden = 1; + if state == DC_STATE_IN_FRESH { + state = DC_STATE_IN_NOTICED; + } + } + if part.type_0 == Viewtype::Text as i32 { + txt_raw = dc_mprintf( + b"%s\n\n%s\x00" as *const u8 as *const libc::c_char, + if !mime_parser.subject.is_null() { + mime_parser.subject + } else { + b"\x00" as *const u8 as *const libc::c_char + }, + part.msg_raw, + ) + } + if 0 != mime_parser.is_system_message { + part.param + .set_int(Param::Cmd, mime_parser.is_system_message); + } + + stmt.execute(params![ + as_str(rfc724_mid), + server_folder.as_ref(), + server_uid as libc::c_int, + *chat_id as libc::c_int, + *from_id as libc::c_int, + *to_id as libc::c_int, + sort_timestamp, + *sent_timestamp, + rcvd_timestamp, + part.type_0, + state, + msgrmsg, + if !part.msg.is_null() { + as_str(part.msg) + } else { + "" + }, + // txt_raw might contain invalid utf8 + if !txt_raw.is_null() { + to_string_lossy(txt_raw) + } else { + String::new() + }, + part.param.to_string(), + part.bytes, + *hidden, + if 0 != save_mime_headers { + let body_string = std::str::from_utf8(std::slice::from_raw_parts( + imf_raw_not_terminated as *const u8, + imf_raw_bytes, + )) + .unwrap(); + + Some(body_string) + } else { + None + }, + to_string(mime_in_reply_to), + to_string(mime_references), + ])?; + + free(txt_raw as *mut libc::c_void); + txt_raw = 0 as *mut libc::c_char; + *insert_msg_id = sql::get_rowid_with_conn( + context, + conn, + "msgs", + "rfc724_mid", + as_str(rfc724_mid), + ); + created_db_entries.push((*chat_id as usize, *insert_msg_id as usize)); + } + Ok(()) + }, + ) + .is_ok(); + + if !is_ok { + // i/o error - there is nothing more we can do - in other cases, we try to write at least an empty record + cleanup(mime_in_reply_to, mime_references, txt_raw); + bail!("Cannot write DB."); + } + + info!( + context, + 0, "Message has {} parts and is assigned to chat #{}.", icnt, *chat_id, + ); + + // check event to send + if *chat_id == DC_CHAT_ID_TRASH as u32 { + *create_event_to_send = None; + } else if 0 != incoming && state == DC_STATE_IN_FRESH { + if 0 != from_id_blocked { + *create_event_to_send = None; + } else if 0 != chat_id_blocked { + *create_event_to_send = Some(Event::MSGS_CHANGED); + } else { + *create_event_to_send = Some(Event::INCOMING_MSG); + } + } + + dc_do_heuristics_moves(context, server_folder.as_ref(), *insert_msg_id); + cleanup(mime_in_reply_to, mime_references, txt_raw); + + Ok(()) +} + +/// Lookup a mime field given its name and type. +unsafe fn lookup_field( + parser: &dc_mimeparser_t, + name: &str, + typ: u32, +) -> Option<*const mailimf_field> { + let field = dc_mimeparser_lookup_field(parser, name); + if !field.is_null() && (*field).fld_type == typ as libc::c_int { + return Some(field); + } else { + None + } +} + +// Handle reports (mainly MDNs) +unsafe fn handle_reports( + context: &Context, + mime_parser: &dc_mimeparser_t, + from_id: u32, + sent_timestamp: i64, + rr_event_to_send: &mut Vec<(u32, u32)>, + server_folder: impl AsRef, + server_uid: u32, +) { + let mdns_enabled = context + .sql + .get_config_int(context, "mdns_enabled") + .unwrap_or_else(|| DC_MDNS_DEFAULT_ENABLED); + + for report_root in &mime_parser.reports { + let report_root = *report_root; + let mut mdn_consumed = 0; + let report_type = mailmime_find_ct_parameter( + report_root, + b"report-type\x00" as *const u8 as *const libc::c_char, + ); + + if report_root.is_null() || report_type.is_null() || (*report_type).pa_value.is_null() { + continue; + } + + // the first part is for humans, the second for machines + if strcmp( + (*report_type).pa_value, + b"disposition-notification\x00" as *const u8 as *const libc::c_char, + ) == 0 + && (*(*report_root).mm_data.mm_multipart.mm_mp_list).count >= 2 + { + // to get a clear functionality, do not show incoming MDNs if the options is disabled + if 0 != mdns_enabled { + let report_data = (if !if !(*(*report_root).mm_data.mm_multipart.mm_mp_list) + .first + .is_null() + { + (*(*(*report_root).mm_data.mm_multipart.mm_mp_list).first).next + } else { + 0 as *mut clistcell + } + .is_null() + { + (*if !(*(*report_root).mm_data.mm_multipart.mm_mp_list) + .first + .is_null() + { + (*(*(*report_root).mm_data.mm_multipart.mm_mp_list).first).next + } else { + 0 as *mut clistcell + }) + .data + } else { + 0 as *mut libc::c_void + }) as *mut mailmime; + + if !report_data.is_null() + && (*(*(*report_data).mm_content_type).ct_type).tp_type + == MAILMIME_TYPE_COMPOSITE_TYPE as libc::c_int + && (*(*(*(*report_data).mm_content_type).ct_type) + .tp_data + .tp_composite_type) + .ct_type + == MAILMIME_COMPOSITE_TYPE_MESSAGE as libc::c_int + && strcmp( + (*(*report_data).mm_content_type).ct_subtype, + b"disposition-notification\x00" as *const u8 as *const libc::c_char, + ) == 0 + { + let mut report_body = std::ptr::null(); + let mut report_body_bytes = 0; + let mut to_mmap_string_unref = std::ptr::null_mut(); + + if 0 != mailmime_transfer_decode( + report_data, + &mut report_body, + &mut report_body_bytes, + &mut to_mmap_string_unref, + ) { + let mut report_parsed = std::ptr::null_mut(); + let mut dummy = 0; + + if mailmime_parse( + report_body, + report_body_bytes, + &mut dummy, + &mut report_parsed, + ) == MAIL_NO_ERROR as libc::c_int + && !report_parsed.is_null() + { + let report_fields = mailmime_find_mailimf_fields(report_parsed); + if !report_fields.is_null() { + let of_disposition = mailimf_find_optional_field( + report_fields, + b"Disposition\x00" as *const u8 as *const libc::c_char, + ); + let of_org_msgid = mailimf_find_optional_field( + report_fields, + b"Original-Message-ID\x00" as *const u8 as *const libc::c_char, + ); + if !of_disposition.is_null() + && !(*of_disposition).fld_value.is_null() + && !of_org_msgid.is_null() + && !(*of_org_msgid).fld_value.is_null() + { + let mut rfc724_mid_0 = std::ptr::null_mut(); + dummy = 0; + + if mailimf_msg_id_parse( + (*of_org_msgid).fld_value, + strlen((*of_org_msgid).fld_value), + &mut dummy, + &mut rfc724_mid_0, + ) == MAIL_NO_ERROR as libc::c_int + && !rfc724_mid_0.is_null() + { + let mut chat_id_0 = 0; + let mut msg_id = 0; + + if 0 != dc_mdn_from_ext( + context, + from_id, + rfc724_mid_0, + sent_timestamp, + &mut chat_id_0, + &mut msg_id, + ) { + rr_event_to_send.push((chat_id_0, msg_id)); + } + mdn_consumed = (msg_id != 0) as libc::c_int; + free(rfc724_mid_0.cast()); + } + } + } + mailmime_free(report_parsed); + } + if !to_mmap_string_unref.is_null() { + mmap_string_unref(to_mmap_string_unref); + } + } + } + } + + if 0 != mime_parser.is_send_by_messenger || 0 != mdn_consumed { + let mut param = Params::new(); + param.set(Param::ServerFolder, server_folder.as_ref()); + param.set_int(Param::ServerUid, server_uid as i32); + if 0 != mime_parser.is_send_by_messenger + && 0 != context + .sql + .get_config_int(context, "mvbox_move") + .unwrap_or_else(|| 1) + { + param.set_int(Param::AlsoMove, 1); + } + dc_job_add(context, 120, 0, param, 0); + } + } + } +} + +unsafe fn save_locations( + context: &Context, + mime_parser: &dc_mimeparser_t, + chat_id: u32, + from_id: u32, + insert_msg_id: u32, + hidden: i32, +) { + let mut location_id_written = false; + let mut send_event = false; + + if !mime_parser.message_kml.is_none() && chat_id > DC_CHAT_ID_LAST_SPECIAL as libc::c_uint { + let newest_location_id: uint32_t = dc_save_locations( + context, + chat_id, + from_id, + &mime_parser.message_kml.as_ref().unwrap().locations, + 1, + ); + if 0 != newest_location_id && 0 == hidden { + dc_set_msg_location_id(context, insert_msg_id, newest_location_id); + location_id_written = true; + send_event = true; + } + } + + if !mime_parser.location_kml.is_none() && chat_id > DC_CHAT_ID_LAST_SPECIAL as libc::c_uint { + if !mime_parser.location_kml.as_ref().unwrap().addr.is_null() { + if let Ok(contact) = Contact::get_by_id(context, from_id) { + if !contact.get_addr().is_empty() + && contact.get_addr().to_lowercase() + == as_str(mime_parser.location_kml.as_ref().unwrap().addr).to_lowercase() + { + let newest_location_id = dc_save_locations( + context, + chat_id, + from_id, + &mime_parser.location_kml.as_ref().unwrap().locations, + 0, + ); + if newest_location_id != 0 && hidden == 0 && !location_id_written { + dc_set_msg_location_id(context, insert_msg_id, newest_location_id); + } + send_event = true; + } + } + } + } + if send_event { + context.call_cb( + Event::LOCATION_CHANGED, + from_id as uintptr_t, + 0 as uintptr_t, + ); + } } -/* ****************************************************************************** - * Misc. Tools - ******************************************************************************/ unsafe fn calc_timestamps( context: &Context, - chat_id: uint32_t, - from_id: uint32_t, + chat_id: u32, + from_id: u32, message_timestamp: i64, is_fresh_msg: libc::c_int, sort_timestamp: *mut i64, @@ -899,18 +1035,17 @@ unsafe fn calc_timestamps( } } -/* the function tries extracts the group-id from the message and returns the -corresponding chat_id. If the chat_id is not existent, it is created. -If the message contains groups commands (name, profile image, changed members), -they are executed as well. - -if no group-id could be extracted from the message, create_or_lookup_adhoc_group() is called -which tries to create or find out the chat_id by: -- is there a group with the same recipients? if so, use this (if there are multiple, use the most recent one) -- create an ad-hoc group based on the recipient list - -So when the function returns, the caller has the group id matching the current -state of the group. */ +/// This function tries extracts the group-id from the message and returns the +/// corresponding chat_id. If the chat_id is not existent, it is created. +/// If the message contains groups commands (name, profile image, changed members), +/// they are executed as well. +/// +/// if no group-id could be extracted from the message, create_or_lookup_adhoc_group() is called +/// which tries to create or find out the chat_id by: +/// - is there a group with the same recipients? if so, use this (if there are multiple, use the most recent one) +/// - create an ad-hoc group based on the recipient list +/// +/// So when the function returns, the caller has the group id matching the current state of the group. #[allow(non_snake_case)] unsafe fn create_or_lookup_group( context: &Context, @@ -923,70 +1058,84 @@ unsafe fn create_or_lookup_group( ret_chat_id_blocked: *mut libc::c_int, ) { let group_explicitly_left: libc::c_int; - let mut current_block: u64; - let mut chat_id: uint32_t = 0 as uint32_t; - let mut chat_id_blocked: libc::c_int = 0; - let mut chat_id_verified: libc::c_int = 0; - let mut grpid: *mut libc::c_char = 0 as *mut libc::c_char; - let mut grpname: *mut libc::c_char = 0 as *mut libc::c_char; - let mut i: libc::c_int; - let to_ids_cnt: libc::c_int = dc_array_get_cnt(to_ids) as libc::c_int; - let mut recreate_member_list: libc::c_int = 0; - let mut send_EVENT_CHAT_MODIFIED: libc::c_int = 0; - /* pointer somewhere into mime_parser, must not be freed */ - let mut X_MrRemoveFromGrp: *mut libc::c_char = 0 as *mut libc::c_char; - /* pointer somewhere into mime_parser, must not be freed */ - let mut X_MrAddToGrp: *mut libc::c_char = 0 as *mut libc::c_char; - let mut X_MrGrpNameChanged: libc::c_int = 0; - let mut X_MrGrpImageChanged: *const libc::c_char = 0 as *const libc::c_char; + let mut chat_id = 0; + let mut chat_id_blocked = 0; + let mut chat_id_verified = 0; + let mut grpid = std::ptr::null_mut(); + let mut grpname = std::ptr::null_mut(); + let to_ids_cnt = dc_array_get_cnt(to_ids); + let mut recreate_member_list = 0; + let mut send_EVENT_CHAT_MODIFIED = 0; + // pointer somewhere into mime_parser, must not be freed + let mut X_MrRemoveFromGrp = std::ptr::null_mut(); + // pointer somewhere into mime_parser, must not be freed + let mut X_MrAddToGrp = std::ptr::null_mut(); + let mut X_MrGrpNameChanged = 0; + let mut X_MrGrpImageChanged = std::ptr::null(); let mut better_msg: String = From::from(""); - let mut failure_reason: *mut libc::c_char = 0 as *mut libc::c_char; - if mime_parser.is_system_message == 8i32 { + let mut failure_reason = std::ptr::null_mut(); + + let cleanup = |grpid: *mut libc::c_char, + grpname: *mut libc::c_char, + failure_reason: *mut libc::c_char, + ret_chat_id: *mut uint32_t, + ret_chat_id_blocked: *mut libc::c_int, + chat_id: u32, + chat_id_blocked: i32| { + free(grpid.cast()); + free(grpname.cast()); + free(failure_reason.cast()); + + if !ret_chat_id.is_null() { + *ret_chat_id = chat_id; + } + if !ret_chat_id_blocked.is_null() { + *ret_chat_id_blocked = if 0 != chat_id { chat_id_blocked } else { 0 }; + } + }; + + if mime_parser.is_system_message == DC_CMD_LOCATION_STREAMING_ENABLED { better_msg = context.stock_system_msg(StockMessage::MsgLocationEnabled, "", "", from_id as u32) } set_better_msg(mime_parser, &better_msg); - /* search the grpid in the header */ - let mut field: *mut mailimf_field; - let mut optional_field: *mut mailimf_optional_field; - optional_field = dc_mimeparser_lookup_optional_field( - mime_parser, - b"Chat-Group-ID\x00" as *const u8 as *const libc::c_char, - ); + + // search the grpid in the header + let optional_field = dc_mimeparser_lookup_optional_field(mime_parser, "Chat-Group-ID"); if !optional_field.is_null() { grpid = dc_strdup((*optional_field).fld_value) } if grpid.is_null() { - field = dc_mimeparser_lookup_field(mime_parser, "Message-ID"); - if !field.is_null() && (*field).fld_type == MAILIMF_FIELD_MESSAGE_ID as libc::c_int { - let fld_message_id: *mut mailimf_message_id = (*field).fld_data.fld_message_id; + if let Some(field) = lookup_field(mime_parser, "Message-ID", MAILIMF_FIELD_MESSAGE_ID) { + let fld_message_id = (*field).fld_data.fld_message_id; if !fld_message_id.is_null() { if let Some(extracted_grpid) = dc_extract_grpid_from_rfc724_mid(as_str((*fld_message_id).mid_value)) { grpid = extracted_grpid.strdup(); } else { - grpid = 0 as *mut libc::c_char; + grpid = std::ptr::null_mut(); } } } if grpid.is_null() { - field = dc_mimeparser_lookup_field(mime_parser, "In-Reply-To"); - if !field.is_null() && (*field).fld_type == MAILIMF_FIELD_IN_REPLY_TO as libc::c_int { - let fld_in_reply_to: *mut mailimf_in_reply_to = (*field).fld_data.fld_in_reply_to; + if let Some(field) = lookup_field(mime_parser, "In-Reply-To", MAILIMF_FIELD_IN_REPLY_TO) + { + let fld_in_reply_to = (*field).fld_data.fld_in_reply_to; if !fld_in_reply_to.is_null() { grpid = dc_extract_grpid_from_rfc724_mid_list((*fld_in_reply_to).mid_list) } } if grpid.is_null() { - field = dc_mimeparser_lookup_field(mime_parser, "References"); - if !field.is_null() && (*field).fld_type == MAILIMF_FIELD_REFERENCES as libc::c_int + if let Some(field) = + lookup_field(mime_parser, "References", MAILIMF_FIELD_REFERENCES) { - let fld_references: *mut mailimf_references = (*field).fld_data.fld_references; + let fld_references = (*field).fld_data.fld_references; if !fld_references.is_null() { grpid = dc_extract_grpid_from_rfc724_mid_list((*fld_references).mid_list) } } + if grpid.is_null() { create_or_lookup_adhoc_group( context, @@ -998,361 +1147,336 @@ unsafe fn create_or_lookup_group( &mut chat_id, &mut chat_id_blocked, ); - current_block = 281803052766328415; - } else { - current_block = 18435049525520518667; + cleanup( + grpid, + grpname, + failure_reason, + ret_chat_id, + ret_chat_id_blocked, + chat_id, + chat_id_blocked, + ); + return; } - } else { - current_block = 18435049525520518667; } - } else { - current_block = 18435049525520518667; } - } else { - current_block = 18435049525520518667; } - match current_block { - 18435049525520518667 => { - optional_field = dc_mimeparser_lookup_optional_field( - mime_parser, - b"Chat-Group-Name\x00" as *const u8 as *const libc::c_char, - ); + + let optional_field = dc_mimeparser_lookup_optional_field(mime_parser, "Chat-Group-Name"); + if !optional_field.is_null() { + grpname = dc_decode_header_words((*optional_field).fld_value) + } + let optional_field = + dc_mimeparser_lookup_optional_field(mime_parser, "Chat-Group-Member-Removed"); + if !optional_field.is_null() { + X_MrRemoveFromGrp = (*optional_field).fld_value; + mime_parser.is_system_message = DC_CMD_MEMBER_REMOVED_FROM_GROUP; + let left_group = (Contact::lookup_id_by_addr(context, as_str(X_MrRemoveFromGrp)) + == from_id as u32) as libc::c_int; + better_msg = context.stock_system_msg( + if 0 != left_group { + StockMessage::MsgGroupLeft + } else { + StockMessage::MsgDelMember + }, + as_str(X_MrRemoveFromGrp), + "", + from_id as u32, + ) + } else { + let optional_field = + dc_mimeparser_lookup_optional_field(mime_parser, "Chat-Group-Member-Added"); + if !optional_field.is_null() { + X_MrAddToGrp = (*optional_field).fld_value; + mime_parser.is_system_message = DC_CMD_MEMBER_ADDED_TO_GROUP; + let optional_field = + dc_mimeparser_lookup_optional_field(mime_parser, "Chat-Group-Image"); if !optional_field.is_null() { - grpname = dc_decode_header_words((*optional_field).fld_value) + X_MrGrpImageChanged = (*optional_field).fld_value } - optional_field = dc_mimeparser_lookup_optional_field( - mime_parser, - b"Chat-Group-Member-Removed\x00" as *const u8 as *const libc::c_char, - ); + better_msg = context.stock_system_msg( + StockMessage::MsgAddMember, + as_str(X_MrAddToGrp), + "", + from_id as u32, + ) + } else { + let optional_field = + dc_mimeparser_lookup_optional_field(mime_parser, "Chat-Group-Name-Changed"); if !optional_field.is_null() { - X_MrRemoveFromGrp = (*optional_field).fld_value; - mime_parser.is_system_message = 5; - let left_group = (Contact::lookup_id_by_addr(context, as_str(X_MrRemoveFromGrp)) - == from_id as u32) as libc::c_int; + X_MrGrpNameChanged = 1; + mime_parser.is_system_message = DC_CMD_GROUPNAME_CHANGED; better_msg = context.stock_system_msg( - if 0 != left_group { - StockMessage::MsgGroupLeft - } else { - StockMessage::MsgDelMember - }, - as_str(X_MrRemoveFromGrp), - "", + StockMessage::MsgGrpName, + as_str((*optional_field).fld_value), + as_str(grpname), from_id as u32, ) } else { - optional_field = dc_mimeparser_lookup_optional_field( - mime_parser, - b"Chat-Group-Member-Added\x00" as *const u8 as *const libc::c_char, - ); + let optional_field = + dc_mimeparser_lookup_optional_field(mime_parser, "Chat-Group-Image"); if !optional_field.is_null() { - X_MrAddToGrp = (*optional_field).fld_value; - mime_parser.is_system_message = 4; - optional_field = dc_mimeparser_lookup_optional_field( - mime_parser, - b"Chat-Group-Image\x00" as *const u8 as *const libc::c_char, - ); - if !optional_field.is_null() { - X_MrGrpImageChanged = (*optional_field).fld_value - } + X_MrGrpImageChanged = (*optional_field).fld_value; + mime_parser.is_system_message = DC_CMD_GROUPIMAGE_CHANGED; better_msg = context.stock_system_msg( - StockMessage::MsgAddMember, - as_str(X_MrAddToGrp), + if strcmp( + X_MrGrpImageChanged, + b"0\x00" as *const u8 as *const libc::c_char, + ) == 0 + { + StockMessage::MsgGrpImgDeleted + } else { + StockMessage::MsgGrpImgChanged + }, + "", "", from_id as u32, ) - } else { - optional_field = dc_mimeparser_lookup_optional_field( - mime_parser, - b"Chat-Group-Name-Changed\x00" as *const u8 as *const libc::c_char, - ); - if !optional_field.is_null() { - X_MrGrpNameChanged = 1i32; - mime_parser.is_system_message = 2i32; - better_msg = context.stock_system_msg( - StockMessage::MsgGrpName, - as_str((*optional_field).fld_value), - as_str(grpname), - from_id as u32, - ) - } else { - optional_field = dc_mimeparser_lookup_optional_field( - mime_parser, - b"Chat-Group-Image\x00" as *const u8 as *const libc::c_char, - ); - if !optional_field.is_null() { - X_MrGrpImageChanged = (*optional_field).fld_value; - mime_parser.is_system_message = 3; - better_msg = context.stock_system_msg( - if strcmp( - X_MrGrpImageChanged, - b"0\x00" as *const u8 as *const libc::c_char, - ) == 0 - { - StockMessage::MsgGrpImgDeleted - } else { - StockMessage::MsgGrpImgChanged - }, - "", - "", - from_id as u32, - ) - } - } - } - } - set_better_msg(mime_parser, &better_msg); - chat_id = dc_get_chat_id_by_grpid( - context, - grpid, - &mut chat_id_blocked, - &mut chat_id_verified, - ); - if chat_id != 0 as libc::c_uint { - if 0 != chat_id_verified - && 0 == check_verified_properties( - context, - mime_parser, - from_id as uint32_t, - to_ids, - &mut failure_reason, - ) - { - dc_mimeparser_repl_msg_by_error(mime_parser, failure_reason); - } - } - if chat_id != 0 as libc::c_uint - && 0 == dc_is_contact_in_chat(context, chat_id, from_id as uint32_t) - { - recreate_member_list = 1 - } - /* check if the group does not exist but should be created */ - group_explicitly_left = dc_is_group_explicitly_left(context, grpid); - let self_addr = context - .sql - .get_config(context, "configured_addr") - .unwrap_or_default(); - if chat_id == 0 as libc::c_uint - && 0 == dc_mimeparser_is_mailinglist_message(mime_parser) - && !grpid.is_null() - && !grpname.is_null() - && X_MrRemoveFromGrp.is_null() - && (0 == group_explicitly_left - || !X_MrAddToGrp.is_null() && addr_cmp(&self_addr, as_str(X_MrAddToGrp))) - { - /*otherwise, a pending "quit" message may pop up*/ - /*re-create explicitly left groups only if ourself is re-added*/ - let mut create_verified: libc::c_int = 0; - if !dc_mimeparser_lookup_field(mime_parser, "Chat-Verified").is_null() { - create_verified = 1; - if 0 == check_verified_properties( - context, - mime_parser, - from_id as uint32_t, - to_ids, - &mut failure_reason, - ) { - dc_mimeparser_repl_msg_by_error(mime_parser, failure_reason); - } - } - if 0 == allow_creation { - current_block = 281803052766328415; - } else { - chat_id = create_group_record( - context, - grpid, - grpname, - create_blocked, - create_verified, - ); - chat_id_blocked = create_blocked; - recreate_member_list = 1; - current_block = 200744462051969938; - } - } else { - current_block = 200744462051969938; - } - match current_block { - 281803052766328415 => {} - _ => { - /* again, check chat_id */ - if chat_id <= 9 as libc::c_uint { - chat_id = 0 as uint32_t; - if 0 != group_explicitly_left { - chat_id = 3 as uint32_t - } else { - create_or_lookup_adhoc_group( - context, - mime_parser, - allow_creation, - create_blocked, - from_id, - to_ids, - &mut chat_id, - &mut chat_id_blocked, - ); - } - } else { - if !X_MrAddToGrp.is_null() || !X_MrRemoveFromGrp.is_null() { - recreate_member_list = 1 - } else if 0 != X_MrGrpNameChanged - && !grpname.is_null() - && strlen(grpname) < 200 - { - if sql::execute( - context, - &context.sql, - "UPDATE chats SET name=? WHERE id=?;", - params![as_str(grpname), chat_id as i32], - ) - .is_ok() - { - context.call_cb(Event::CHAT_MODIFIED, chat_id as uintptr_t, 0); - } - } - if !X_MrGrpImageChanged.is_null() { - let mut ok = 0; - let mut grpimage = 0 as *mut libc::c_char; - if strcmp( - X_MrGrpImageChanged, - b"0\x00" as *const u8 as *const libc::c_char, - ) == 0 - { - ok = 1 - } else { - for part in &mut mime_parser.parts { - if part.type_0 == 20 { - grpimage = part - .param - .get(Param::File) - .map(|s| s.strdup()) - .unwrap_or_else(|| std::ptr::null_mut()); - ok = 1 - } - } - } - if 0 != ok { - let chat = dc_chat_new(context); - info!( - context, - 0, - "New group image set to {}.", - if !grpimage.is_null() { - "DELETED".to_string() - } else { - to_string(grpimage) - }, - ); - dc_chat_load_from_db(chat, chat_id); - if grpimage.is_null() { - (*chat).param.remove(Param::ProfileImage); - } else { - (*chat).param.set(Param::ProfileImage, as_str(grpimage)); - } - dc_chat_update_param(chat); - dc_chat_unref(chat); - free(grpimage as *mut libc::c_void); - send_EVENT_CHAT_MODIFIED = 1 - } - } - if 0 != recreate_member_list { - let skip = if !X_MrRemoveFromGrp.is_null() { - X_MrRemoveFromGrp - } else { - 0 as *mut libc::c_char - }; - sql::execute( - context, - &context.sql, - "DELETE FROM chats_contacts WHERE chat_id=?;", - params![chat_id as i32], - ) - .ok(); - if skip.is_null() || !addr_cmp(&self_addr, as_str(skip)) { - dc_add_to_chat_contacts_table(context, chat_id, 1); - } - if from_id > 9 { - if !Contact::addr_equals_contact( - context, - &self_addr, - from_id as u32, - ) && (skip.is_null() - || !Contact::addr_equals_contact( - context, - to_string(skip), - from_id as u32, - )) - { - dc_add_to_chat_contacts_table( - context, - chat_id, - from_id as uint32_t, - ); - } - } - i = 0; - while i < to_ids_cnt { - let to_id = dc_array_get_id(to_ids, i as size_t); - if !Contact::addr_equals_contact(context, &self_addr, to_id) - && (skip.is_null() - || !Contact::addr_equals_contact( - context, - to_string(skip), - to_id, - )) - { - dc_add_to_chat_contacts_table(context, chat_id, to_id); - } - i += 1 - } - send_EVENT_CHAT_MODIFIED = 1; - dc_reset_gossiped_timestamp(context, chat_id); - } - if 0 != send_EVENT_CHAT_MODIFIED { - context.call_cb( - Event::CHAT_MODIFIED, - chat_id as uintptr_t, - 0 as uintptr_t, - ); - } - /* check the number of receivers - - the only critical situation is if the user hits "Reply" instead of "Reply all" in a non-messenger-client */ - if to_ids_cnt == 1 && mime_parser.is_send_by_messenger == 0 { - let is_contact_cnt: libc::c_int = - dc_get_chat_contact_cnt(context, chat_id); - if is_contact_cnt > 3 { - /* to_ids_cnt==1 may be "From: A, To: B, SELF" as SELF is not counted in to_ids_cnt. So everything up to 3 is no error. */ - chat_id = 0 as uint32_t; - create_or_lookup_adhoc_group( - context, - mime_parser, - allow_creation, - create_blocked, - from_id, - to_ids, - &mut chat_id, - &mut chat_id_blocked, - ); - } - } - } } } } - _ => {} } - free(grpid as *mut libc::c_void); - free(grpname as *mut libc::c_void); - free(failure_reason as *mut libc::c_void); - if !ret_chat_id.is_null() { - *ret_chat_id = chat_id + set_better_msg(mime_parser, &better_msg); + + // check, if we have a chat with this group ID + chat_id = dc_get_chat_id_by_grpid(context, grpid, &mut chat_id_blocked, &mut chat_id_verified); + if chat_id != 0 { + if 0 != chat_id_verified + && 0 == check_verified_properties( + context, + mime_parser, + from_id as uint32_t, + to_ids, + &mut failure_reason, + ) + { + dc_mimeparser_repl_msg_by_error(mime_parser, failure_reason); + } } - if !ret_chat_id_blocked.is_null() { - *ret_chat_id_blocked = if 0 != chat_id { chat_id_blocked } else { 0 } - }; + + // check if the sender is a member of the existing group - + // if not, we'll recreate the group list + if chat_id != 0 && 0 == dc_is_contact_in_chat(context, chat_id, from_id as u32) { + recreate_member_list = 1; + } + + // check if the group does not exist but should be created + group_explicitly_left = dc_is_group_explicitly_left(context, grpid); + + let self_addr = context + .sql + .get_config(context, "configured_addr") + .unwrap_or_default(); + if chat_id == 0 + && 0 == dc_mimeparser_is_mailinglist_message(mime_parser) + && !grpid.is_null() + && !grpname.is_null() + // otherwise, a pending "quit" message may pop up + && X_MrRemoveFromGrp.is_null() + // re-create explicitly left groups only if ourself is re-added + && (0 == group_explicitly_left + || !X_MrAddToGrp.is_null() && addr_cmp(&self_addr, as_str(X_MrAddToGrp))) + { + let mut create_verified: libc::c_int = 0; + if !dc_mimeparser_lookup_field(mime_parser, "Chat-Verified").is_null() { + create_verified = 1; + if 0 == check_verified_properties( + context, + mime_parser, + from_id as uint32_t, + to_ids, + &mut failure_reason, + ) { + dc_mimeparser_repl_msg_by_error(mime_parser, failure_reason); + } + } + if 0 == allow_creation { + cleanup( + grpid, + grpname, + failure_reason, + ret_chat_id, + ret_chat_id_blocked, + chat_id, + chat_id_blocked, + ); + return; + } + chat_id = create_group_record(context, grpid, grpname, create_blocked, create_verified); + chat_id_blocked = create_blocked; + recreate_member_list = 1; + } + + // again, check chat_id + if chat_id <= DC_CHAT_ID_LAST_SPECIAL as u32 { + chat_id = 0; + if 0 != group_explicitly_left { + chat_id = DC_CHAT_ID_TRASH as u32; + } else { + create_or_lookup_adhoc_group( + context, + mime_parser, + allow_creation, + create_blocked, + from_id, + to_ids, + &mut chat_id, + &mut chat_id_blocked, + ); + } + cleanup( + grpid, + grpname, + failure_reason, + ret_chat_id, + ret_chat_id_blocked, + chat_id, + chat_id_blocked, + ); + return; + } + + // execute group commands + if !X_MrAddToGrp.is_null() || !X_MrRemoveFromGrp.is_null() { + recreate_member_list = 1; + } else if 0 != X_MrGrpNameChanged && !grpname.is_null() && strlen(grpname) < 200 { + if sql::execute( + context, + &context.sql, + "UPDATE chats SET name=? WHERE id=?;", + params![as_str(grpname), chat_id as i32], + ) + .is_ok() + { + context.call_cb(Event::CHAT_MODIFIED, chat_id as uintptr_t, 0); + } + } + if !X_MrGrpImageChanged.is_null() { + let mut ok = 0; + let mut grpimage = 0 as *mut libc::c_char; + if strcmp( + X_MrGrpImageChanged, + b"0\x00" as *const u8 as *const libc::c_char, + ) == 0 + { + ok = 1 + } else { + for part in &mut mime_parser.parts { + if part.type_0 == 20 { + grpimage = part + .param + .get(Param::File) + .map(|s| s.strdup()) + .unwrap_or_else(|| std::ptr::null_mut()); + ok = 1 + } + } + } + if 0 != ok { + let chat = dc_chat_new(context); + info!( + context, + 0, + "New group image set to {}.", + if !grpimage.is_null() { + "DELETED".to_string() + } else { + to_string(grpimage) + }, + ); + dc_chat_load_from_db(chat, chat_id); + if grpimage.is_null() { + (*chat).param.remove(Param::ProfileImage); + } else { + (*chat).param.set(Param::ProfileImage, as_str(grpimage)); + } + dc_chat_update_param(chat); + dc_chat_unref(chat); + free(grpimage as *mut libc::c_void); + send_EVENT_CHAT_MODIFIED = 1 + } + } + + // add members to group/check members + // for recreation: we should add a timestamp + if 0 != recreate_member_list { + // TODO: the member list should only be recreated if the corresponding message is newer + // than the one that is responsible for the current member list, see + // https://github.com/deltachat/deltachat-core/issues/127 + + let skip = if !X_MrRemoveFromGrp.is_null() { + X_MrRemoveFromGrp + } else { + 0 as *mut libc::c_char + }; + sql::execute( + context, + &context.sql, + "DELETE FROM chats_contacts WHERE chat_id=?;", + params![chat_id as i32], + ) + .ok(); + if skip.is_null() || !addr_cmp(&self_addr, as_str(skip)) { + dc_add_to_chat_contacts_table(context, chat_id, DC_CONTACT_ID_SELF as u32); + } + if from_id > DC_CHAT_ID_LAST_SPECIAL as i32 { + if !Contact::addr_equals_contact(context, &self_addr, from_id as u32) + && (skip.is_null() + || !Contact::addr_equals_contact(context, to_string(skip), from_id as u32)) + { + dc_add_to_chat_contacts_table(context, chat_id, from_id as u32); + } + } + for i in 0..to_ids_cnt { + let to_id = dc_array_get_id(to_ids, i as size_t); + if !Contact::addr_equals_contact(context, &self_addr, to_id) + && (skip.is_null() + || !Contact::addr_equals_contact(context, to_string(skip), to_id)) + { + dc_add_to_chat_contacts_table(context, chat_id, to_id); + } + } + send_EVENT_CHAT_MODIFIED = 1; + dc_reset_gossiped_timestamp(context, chat_id); + } + + if 0 != send_EVENT_CHAT_MODIFIED { + context.call_cb(Event::CHAT_MODIFIED, chat_id as uintptr_t, 0 as uintptr_t); + } + + // check the number of receivers - + // the only critical situation is if the user hits "Reply" instead of "Reply all" in a non-messenger-client */ + if to_ids_cnt == 1 && mime_parser.is_send_by_messenger == 0 { + let is_contact_cnt = dc_get_chat_contact_cnt(context, chat_id); + if is_contact_cnt > 3 { + // to_ids_cnt==1 may be "From: A, To: B, SELF" as SELF is not counted in to_ids_cnt. + // So everything up to 3 is no error. + chat_id = 0; + create_or_lookup_adhoc_group( + context, + mime_parser, + allow_creation, + create_blocked, + from_id, + to_ids, + &mut chat_id, + &mut chat_id_blocked, + ); + } + } + + cleanup( + grpid, + grpname, + failure_reason, + ret_chat_id, + ret_chat_id_blocked, + chat_id, + chat_id_blocked, + ); } -/* ****************************************************************************** - * Handle groups for received messages - ******************************************************************************/ + +/// Handle groups for received messages unsafe fn create_or_lookup_adhoc_group( context: &Context, mime_parser: &dc_mimeparser_t, @@ -1363,112 +1487,180 @@ unsafe fn create_or_lookup_adhoc_group( ret_chat_id: *mut uint32_t, ret_chat_id_blocked: *mut libc::c_int, ) { - let current_block: u64; - /* if we're here, no grpid was found, check there is an existing ad-hoc - group matching the to-list or if we can create one */ - let mut member_ids: *mut dc_array_t = 0 as *mut dc_array_t; - let mut chat_id: uint32_t = 0 as uint32_t; + // if we're here, no grpid was found, check there is an existing ad-hoc + // group matching the to-list or if we can create one + let mut member_ids = 0 as *mut dc_array_t; + let mut chat_id = 0; let mut chat_id_blocked = 0; - let mut i; - let mut chat_ids: *mut dc_array_t = 0 as *mut dc_array_t; - let mut chat_ids_str: *mut libc::c_char = 0 as *mut libc::c_char; - let mut grpid: *mut libc::c_char = 0 as *mut libc::c_char; - let mut grpname: *mut libc::c_char = 0 as *mut libc::c_char; - /* build member list from the given ids */ - if !(dc_array_get_cnt(to_ids) == 0 || 0 != dc_mimeparser_is_mailinglist_message(mime_parser)) { - /* too few contacts or a mailinglist */ - member_ids = dc_array_duplicate(to_ids); - if !dc_array_search_id(member_ids, from_id as uint32_t, 0 as *mut size_t) { - dc_array_add_id(member_ids, from_id as uint32_t); - } - if !dc_array_search_id(member_ids, 1 as uint32_t, 0 as *mut size_t) { - dc_array_add_id(member_ids, 1 as uint32_t); - } - if !(dc_array_get_cnt(member_ids) < 3) { - /* too few contacts given */ - chat_ids = search_chat_ids_by_contact_ids(context, member_ids); - if dc_array_get_cnt(chat_ids) > 0 { - chat_ids_str = dc_array_get_string(chat_ids, b",\x00" as *const u8 as *const _); - let res = context.sql.query_row( - format!( - "SELECT c.id, c.blocked FROM chats c \ - LEFT JOIN msgs m ON m.chat_id=c.id WHERE c.id IN({}) ORDER BY m.timestamp DESC, m.id DESC LIMIT 1;", - as_str(chat_ids_str), - ), - params![], - |row| { - Ok((row.get::<_, i32>(0)?, row.get::<_, Option>(1)?.unwrap_or_default())) - } - ); + let mut chat_ids = 0 as *mut dc_array_t; + let mut chat_ids_str = 0 as *mut libc::c_char; + let mut grpid = 0 as *mut libc::c_char; + let mut grpname = 0 as *mut libc::c_char; - if let Ok((id, id_blocked)) = res { - chat_id = id as u32; - chat_id_blocked = id_blocked; - /* success, chat found */ - current_block = 11334989263469503965; - } else { - current_block = 11194104282611034094; - } - } else { - current_block = 11194104282611034094; - } - match current_block { - 11334989263469503965 => {} - _ => { - if !(0 == allow_creation) { - /* we do not check if the message is a reply to another group, this may result in - chats with unclear member list. instead we create a new group in the following lines ... */ - /* create a new ad-hoc group - - there is no need to check if this group exists; otherwise we would have caught it above */ - grpid = create_adhoc_grp_id(context, member_ids); - if !grpid.is_null() { - if !mime_parser.subject.is_null() - && 0 != *mime_parser.subject.offset(0isize) as libc::c_int - { - grpname = dc_strdup(mime_parser.subject) - } else { - grpname = context - .stock_string_repl_int( - StockMessage::Member, - dc_array_get_cnt(member_ids) as libc::c_int, - ) - .strdup(); - } - chat_id = - create_group_record(context, grpid, grpname, create_blocked, 0); - chat_id_blocked = create_blocked; - i = 0; - while i < dc_array_get_cnt(member_ids) { - dc_add_to_chat_contacts_table( - context, - chat_id, - dc_array_get_id(member_ids, i as size_t), - ); - i += 1 - } - context.call_cb( - Event::CHAT_MODIFIED, - chat_id as uintptr_t, - 0 as uintptr_t, - ); - } - } - } - } - } - } - dc_array_unref(member_ids); - dc_array_unref(chat_ids); - free(chat_ids_str as *mut libc::c_void); - free(grpid as *mut libc::c_void); - free(grpname as *mut libc::c_void); + let cleanup = |grpid: *mut libc::c_char, + grpname: *mut libc::c_char, + chat_ids_str: *mut libc::c_char, + member_ids: *mut dc_array_t, + chat_ids: *mut dc_array_t, + ret_chat_id: *mut uint32_t, + ret_chat_id_blocked: *mut libc::c_int, + chat_id: u32, + chat_id_blocked: i32| { + dc_array_unref(member_ids); + dc_array_unref(chat_ids); + free(chat_ids_str as *mut libc::c_void); + free(grpid as *mut libc::c_void); + free(grpname as *mut libc::c_void); - if !ret_chat_id.is_null() { - *ret_chat_id = chat_id - } - if !ret_chat_id_blocked.is_null() { - *ret_chat_id_blocked = chat_id_blocked + if !ret_chat_id.is_null() { + *ret_chat_id = chat_id + } + if !ret_chat_id_blocked.is_null() { + *ret_chat_id_blocked = chat_id_blocked + }; }; + + // build member list from the given ids + if dc_array_get_cnt(to_ids) == 0 || 0 != dc_mimeparser_is_mailinglist_message(mime_parser) { + // too few contacts or a mailinglist + cleanup( + grpid, + grpname, + chat_ids_str, + member_ids, + chat_ids, + ret_chat_id, + ret_chat_id_blocked, + chat_id, + chat_id_blocked, + ); + return; + } + + member_ids = dc_array_duplicate(to_ids); + if !dc_array_search_id(member_ids, from_id as uint32_t, 0 as *mut size_t) { + dc_array_add_id(member_ids, from_id as uint32_t); + } + if !dc_array_search_id(member_ids, 1 as uint32_t, 0 as *mut size_t) { + dc_array_add_id(member_ids, 1 as uint32_t); + } + if dc_array_get_cnt(member_ids) < 3 { + // too few contacts given + cleanup( + grpid, + grpname, + chat_ids_str, + member_ids, + chat_ids, + ret_chat_id, + ret_chat_id_blocked, + chat_id, + chat_id_blocked, + ); + return; + } + + chat_ids = search_chat_ids_by_contact_ids(context, member_ids); + if dc_array_get_cnt(chat_ids) > 0 { + chat_ids_str = dc_array_get_string(chat_ids, b",\x00" as *const u8 as *const _); + let res = context.sql.query_row( + format!( + "SELECT c.id, c.blocked FROM chats c \ + LEFT JOIN msgs m ON m.chat_id=c.id WHERE c.id IN({}) ORDER BY m.timestamp DESC, m.id DESC LIMIT 1;", + as_str(chat_ids_str), + ), + params![], + |row| { + Ok((row.get::<_, i32>(0)?, row.get::<_, Option>(1)?.unwrap_or_default())) + } + ); + + if let Ok((id, id_blocked)) = res { + chat_id = id as u32; + chat_id_blocked = id_blocked; + /* success, chat found */ + cleanup( + grpid, + grpname, + chat_ids_str, + member_ids, + chat_ids, + ret_chat_id, + ret_chat_id_blocked, + chat_id, + chat_id_blocked, + ); + return; + } + } + + if 0 == allow_creation { + cleanup( + grpid, + grpname, + chat_ids_str, + member_ids, + chat_ids, + ret_chat_id, + ret_chat_id_blocked, + chat_id, + chat_id_blocked, + ); + return; + } + // we do not check if the message is a reply to another group, this may result in + // chats with unclear member list. instead we create a new group in the following lines ... + + // create a new ad-hoc group + // - there is no need to check if this group exists; otherwise we would have caught it above + grpid = create_adhoc_grp_id(context, member_ids); + if grpid.is_null() { + cleanup( + grpid, + grpname, + chat_ids_str, + member_ids, + chat_ids, + ret_chat_id, + ret_chat_id_blocked, + chat_id, + chat_id_blocked, + ); + return; + } + + // use subject as initial chat name + if !mime_parser.subject.is_null() && 0 != *mime_parser.subject.offset(0isize) as libc::c_int { + grpname = dc_strdup(mime_parser.subject) + } else { + grpname = context + .stock_string_repl_int( + StockMessage::Member, + dc_array_get_cnt(member_ids) as libc::c_int, + ) + .strdup(); + } + + // create group record + chat_id = create_group_record(context, grpid, grpname, create_blocked, 0); + chat_id_blocked = create_blocked; + for i in 0..dc_array_get_cnt(member_ids) { + dc_add_to_chat_contacts_table(context, chat_id, dc_array_get_id(member_ids, i as size_t)); + } + + context.call_cb(Event::CHAT_MODIFIED, chat_id as uintptr_t, 0 as uintptr_t); + + cleanup( + grpid, + grpname, + chat_ids_str, + member_ids, + chat_ids, + ret_chat_id, + ret_chat_id_blocked, + chat_id, + chat_id_blocked, + ); } fn create_group_record( @@ -1521,7 +1713,7 @@ unsafe fn create_adhoc_grp_id(context: &Context, member_ids: *mut dc_array_t) -> params![], |row| row.get::<_, String>(0), |rows| { - let mut addrs = rows.collect::, _>>()?; + let mut addrs = rows.collect::, _>>()?; addrs.sort(); let mut acc = member_cs.clone(); for addr in &addrs { @@ -1668,7 +1860,10 @@ unsafe fn check_verified_properties( ), params![], |row| Ok((row.get::<_, String>(0)?, row.get::<_, i32>(1)?)), - |rows| rows.collect::, _>>().map_err(Into::into), + |rows| { + rows.collect::, _>>() + .map_err(Into::into) + }, ); if rows.is_err() { @@ -1725,16 +1920,14 @@ unsafe fn set_better_msg>(mime_parser: &mut dc_mimeparser_t, bette } }; } + unsafe fn dc_is_reply_to_known_message( context: &Context, mime_parser: &dc_mimeparser_t, ) -> libc::c_int { /* check if the message is a reply to a known message; the replies are identified by the Message-ID from `In-Reply-To`/`References:` (to support non-Delta-Clients) or from `Chat-Predecessor:` (Delta clients, see comment in dc_chat.c) */ - let optional_field = dc_mimeparser_lookup_optional_field( - mime_parser, - b"Chat-Predecessor\x00" as *const u8 as *const libc::c_char, - ); + let optional_field = dc_mimeparser_lookup_optional_field(mime_parser, "Chat-Predecessor"); if !optional_field.is_null() { if 0 != is_known_rfc724_mid(context, (*optional_field).fld_value) { return 1; @@ -1766,6 +1959,7 @@ unsafe fn dc_is_reply_to_known_message( } return 0; } + unsafe fn is_known_rfc724_mid_in_list(context: &Context, mid_list: *const clist) -> libc::c_int { if !mid_list.is_null() { let mut cur: *mut clistiter; @@ -1791,10 +1985,7 @@ unsafe fn is_known_rfc724_mid_in_list(context: &Context, mid_list: *const clist) return 0; } -/* ****************************************************************************** - * Check if a message is a reply to a known message (messenger or non-messenger) - ******************************************************************************/ - +/// Check if a message is a reply to a known message (messenger or non-messenger). fn is_known_rfc724_mid(context: &Context, rfc724_mid: *const libc::c_char) -> libc::c_int { if rfc724_mid.is_null() { return 0; @@ -1846,6 +2037,7 @@ unsafe fn dc_is_reply_to_messenger_message( } return 0; } + unsafe fn is_msgrmsg_rfc724_mid_in_list(context: &Context, mid_list: *const clist) -> libc::c_int { if !mid_list.is_null() { let mut cur: *mut clistiter = (*mid_list).first; @@ -1869,9 +2061,8 @@ unsafe fn is_msgrmsg_rfc724_mid_in_list(context: &Context, mid_list: *const clis } return 0; } -/* ****************************************************************************** - * Check if a message is a reply to any messenger message - ******************************************************************************/ + +/// Check if a message is a reply to any messenger message. fn is_msgrmsg_rfc724_mid(context: &Context, rfc724_mid: *const libc::c_char) -> libc::c_int { if rfc724_mid.is_null() { return 0; @@ -1935,6 +2126,7 @@ unsafe fn dc_add_or_lookup_contacts_by_address_list( } } } + unsafe fn dc_add_or_lookup_contacts_by_mailbox_list( context: &Context, mb_list: *const mailimf_mailbox_list, @@ -1969,9 +2161,8 @@ unsafe fn dc_add_or_lookup_contacts_by_mailbox_list( } } } -/* ****************************************************************************** - * Add contacts to database on receiving messages - ******************************************************************************/ + +/// Add contacts to database on receiving messages. unsafe fn add_or_lookup_contact_by_addr( context: &Context, display_name_enc: *const libc::c_char, diff --git a/tests/stress.rs b/tests/stress.rs index 22a8427fc..72192732a 100644 --- a/tests/stress.rs +++ b/tests/stress.rs @@ -742,22 +742,14 @@ fn test_dc_mimeparser_with_context() { "inner-subject", ); - let mut of: *mut mailimf_optional_field = dc_mimeparser_lookup_optional_field( - &mimeparser, - b"X-Special-A\x00" as *const u8 as *const libc::c_char, - ); + let mut of: *mut mailimf_optional_field = + dc_mimeparser_lookup_optional_field(&mimeparser, "X-Special-A"); assert_eq!(as_str((*of).fld_value as *const libc::c_char), "special-a",); - of = dc_mimeparser_lookup_optional_field( - &mimeparser, - b"Foo\x00" as *const u8 as *const libc::c_char, - ); + of = dc_mimeparser_lookup_optional_field(&mimeparser, "Foo"); assert_eq!(as_str((*of).fld_value as *const libc::c_char), "Bar",); - of = dc_mimeparser_lookup_optional_field( - &mimeparser, - b"Chat-Version\x00" as *const u8 as *const libc::c_char, - ); + of = dc_mimeparser_lookup_optional_field(&mimeparser, "Chat-Version"); assert_eq!(as_str((*of).fld_value as *const libc::c_char), "1.0",); assert_eq!(mimeparser.parts.len(), 1);