diff --git a/README.md b/README.md index 181aa77ef..b9da68c01 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,3 @@ # Delta Chat Rust -Current commit on deltachat/deltachate-core: `b9fcace18ebb6db2937fee1e7f5bd5b583829a33`. +Current commit on deltachat/deltachate-core: `12ef73c8e76185f9b78e844ea673025f56a959ab`. diff --git a/src/constants.rs b/src/constants.rs index 18a561ad5..15e671e75 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -1,6 +1,6 @@ //! Constants -pub const VERSION: &'static [u8; 7] = b"0.42.0\x00"; +pub const VERSION: &'static [u8; 7] = b"0.43.0\x00"; pub const DC_GCL_ARCHIVED_ONLY: usize = 0x01; pub const DC_GCL_NO_SPECIALS: usize = 0x02; diff --git a/src/dc_array.rs b/src/dc_array.rs index 4390821db..2bc3e9636 100644 --- a/src/dc_array.rs +++ b/src/dc_array.rs @@ -1,7 +1,7 @@ use c2rust_bitfields::BitfieldStruct; use libc; -use crate::dc_context::dc_context_t; +use crate::dc_context::*; use crate::dc_lot::dc_lot_t; use crate::dc_sqlite3::*; use crate::dc_tools::*; @@ -20,21 +20,6 @@ pub struct dc_array_t { pub array: *mut uintptr_t, } -// location handling -#[derive(Copy, Clone)] -#[repr(C)] -pub struct _dc_location { - pub location_id: uint32_t, - pub latitude: libc::c_double, - pub longitude: libc::c_double, - pub accuracy: libc::c_double, - pub timestamp: time_t, - pub contact_id: uint32_t, - pub msg_id: uint32_t, - pub chat_id: uint32_t, - pub marker: *mut libc::c_char, -} - /* * * @class dc_array_t * @@ -232,6 +217,30 @@ pub unsafe fn dc_array_get_marker( (*(*(*array).array.offset(index as isize) as *mut _dc_location)).marker, ); } + +/** + * Return the independent-state of the location at the given index. + * Independent locations do not belong to the track of the user. + * + * @memberof dc_array_t + * @param array The array object. + * @param index Index of the item. Must be between 0 and dc_array_get_cnt()-1. + * @return 0=Location belongs to the track of the user, + * 1=Location was reported independently. + */ +pub unsafe fn dc_array_is_independent(array: *const dc_array_t, index: size_t) -> libc::c_int { + if array.is_null() + || (*array).magic != 0xa11aai32 as libc::c_uint + || index >= (*array).count + || (*array).type_0 != 1i32 + || *(*array).array.offset(index as isize) == 0i32 as libc::c_ulong + { + return 0; + } + + (*(*(*array).array.offset(index as isize) as *mut _dc_location)).independent as libc::c_int +} + pub unsafe fn dc_array_search_id( mut array: *const dc_array_t, mut needle: uint32_t, diff --git a/src/dc_chat.rs b/src/dc_chat.rs index 30e806d2a..3246d72f7 100644 --- a/src/dc_chat.rs +++ b/src/dc_chat.rs @@ -1,7 +1,7 @@ use c2rust_bitfields::BitfieldStruct; use libc; -use crate::constants::Event; +use crate::constants::*; use crate::dc_array::*; use crate::dc_chatlist::*; use crate::dc_contact::*; @@ -572,6 +572,8 @@ unsafe fn prepare_msg_raw( let mut stmt: *mut sqlite3_stmt = 0 as *mut sqlite3_stmt; let mut msg_id: uint32_t = 0i32 as uint32_t; let mut to_id: uint32_t = 0i32 as uint32_t; + let mut location_id: uint32_t = 0i32 as uint32_t; + if !((*chat).type_0 == 100i32 || (*chat).type_0 == 120i32 || (*chat).type_0 == 130i32) { dc_log_error( context, @@ -759,9 +761,57 @@ unsafe fn prepare_msg_raw( new_references = dc_strdup(parent_in_reply_to) } } + + // add independent location to database + + if 0 != dc_param_exists((*msg).param, DC_PARAM_SET_LATITUDE as libc::c_int) { + stmt = dc_sqlite3_prepare( + (*context).sql, + b"INSERT INTO locations \ + (timestamp,from_id,chat_id, latitude,longitude,independent)\ + VALUES (?,?,?, ?,?,1);\x00" as *const u8 + as *const libc::c_char, + ); + sqlite3_bind_int64(stmt, 1, timestamp); + sqlite3_bind_int(stmt, 2, DC_CONTACT_ID_SELF as libc::c_int); + sqlite3_bind_int(stmt, 3, (*chat).id as libc::c_int); + sqlite3_bind_double( + stmt, + 4, + dc_param_get_float( + (*msg).param, + DC_PARAM_SET_LATITUDE as libc::c_int, + 0.0, + ), + ); + sqlite3_bind_double( + stmt, + 5, + dc_param_get_float( + (*msg).param, + DC_PARAM_SET_LONGITUDE as libc::c_int, + 0.0, + ), + ); + sqlite3_step(stmt); + sqlite3_finalize(stmt); + stmt = 0 as *mut sqlite3_stmt; + + location_id = dc_sqlite3_get_rowid2( + (*context).sql, + b"locations\x00" as *const u8 as *const libc::c_char, + b"timestamp\x00" as *const u8 as *const libc::c_char, + timestamp as u64, + b"from_id\x00" as *const u8 as *const libc::c_char, + DC_CONTACT_ID_SELF as u32, + ); + } + + // add message to the database + stmt = dc_sqlite3_prepare((*context).sql, - b"INSERT INTO msgs (rfc724_mid, chat_id, from_id, to_id, timestamp, type, state, txt, param, hidden, mime_in_reply_to, mime_references) VALUES (?,?,?,?,?, ?,?,?,?,?, ?,?);\x00" + b"INSERT INTO msgs (rfc724_mid, chat_id, from_id, to_id, timestamp, type, state, txt, param, hidden, mime_in_reply_to, mime_references, location_id) VALUES (?,?,?,?,?, ?,?,?,?,?, ?,?,?);\x00" as *const u8 as *const libc::c_char); sqlite3_bind_text(stmt, 1i32, new_rfc724_mid, -1i32, None); @@ -786,6 +836,7 @@ unsafe fn prepare_msg_raw( sqlite3_bind_int(stmt, 10i32, (*msg).hidden); sqlite3_bind_text(stmt, 11i32, new_in_reply_to, -1i32, None); sqlite3_bind_text(stmt, 12i32, new_references, -1i32, None); + sqlite3_bind_int(stmt, 13i32, location_id as libc::c_int); if sqlite3_step(stmt) != 101i32 { dc_log_error( context, @@ -974,6 +1025,16 @@ pub unsafe fn dc_send_msg( (*msg).chat_id as uintptr_t, (*msg).id as uintptr_t, ); + + if 0 != dc_param_exists((*msg).param, DC_PARAM_SET_LATITUDE as libc::c_int) { + (*context).cb.expect("non-null function pointer")( + context, + Event::LOCATION_CHANGED, + DC_CONTACT_ID_SELF as u64, + 0, + ); + } + if 0 == chat_id { let mut forwards: *mut libc::c_char = dc_param_get((*msg).param, 'P' as i32, 0 as *const libc::c_char); diff --git a/src/dc_context.rs b/src/dc_context.rs index 8348e1acc..70b473748 100644 --- a/src/dc_context.rs +++ b/src/dc_context.rs @@ -63,6 +63,22 @@ pub struct dc_context_t { unsafe impl Send for dc_context_t {} unsafe impl Sync for dc_context_t {} +// location handling +#[derive(Copy, Clone)] +#[repr(C)] +pub struct _dc_location { + pub location_id: uint32_t, + pub latitude: libc::c_double, + pub longitude: libc::c_double, + pub accuracy: libc::c_double, + pub timestamp: time_t, + pub contact_id: uint32_t, + pub msg_id: uint32_t, + pub chat_id: uint32_t, + pub marker: *mut libc::c_char, + pub independent: uint32_t, +} + // create/open/config/information pub unsafe fn dc_context_new( mut cb: dc_callback_t, diff --git a/src/dc_location.rs b/src/dc_location.rs index 831eaa25d..b165cac02 100644 --- a/src/dc_location.rs +++ b/src/dc_location.rs @@ -4,7 +4,7 @@ use libc; use crate::constants::Event; use crate::dc_array::*; use crate::dc_chat::*; -use crate::dc_context::dc_context_t; +use crate::dc_context::*; use crate::dc_job::*; use crate::dc_log::*; use crate::dc_lot::dc_lot_t; @@ -226,10 +226,16 @@ pub unsafe fn dc_get_locations( if timestamp_to == 0i32 as libc::c_long { timestamp_to = time(0 as *mut time_t) + 10i32 as libc::c_long } - stmt = - dc_sqlite3_prepare((*context).sql, - b"SELECT l.id, l.latitude, l.longitude, l.accuracy, l.timestamp, m.id, l.from_id, l.chat_id, m.txt FROM locations l LEFT JOIN msgs m ON l.id=m.location_id WHERE (? OR l.chat_id=?) AND (? OR l.from_id=?) AND l.timestamp>=? AND l.timestamp<=? ORDER BY l.timestamp DESC, l.id DESC, m.id DESC;\x00" - as *const u8 as *const libc::c_char); + stmt = dc_sqlite3_prepare( + (*context).sql, + b"SELECT l.id, l.latitude, l.longitude, l.accuracy, l.timestamp, l.independent \ + m.id, l.from_id, l.chat_id, m.txt \ + FROM locations l LEFT JOIN msgs m ON l.id=m.location_id WHERE (? OR l.chat_id=?) \ + AND (? OR l.from_id=?) \ + AND (l.independent=1 OR (l.timestamp>=? AND l.timestamp<=?)) \ + ORDER BY l.timestamp DESC, l.id DESC, m.id DESC;\x00" as *const u8 + as *const libc::c_char, + ); sqlite3_bind_int( stmt, 1i32, @@ -265,12 +271,14 @@ pub unsafe fn dc_get_locations( (*loc).longitude = sqlite3_column_double(stmt, 2i32); (*loc).accuracy = sqlite3_column_double(stmt, 3i32); (*loc).timestamp = sqlite3_column_int64(stmt, 4i32) as time_t; - (*loc).msg_id = sqlite3_column_int(stmt, 5i32) as uint32_t; - (*loc).contact_id = sqlite3_column_int(stmt, 6i32) as uint32_t; - (*loc).chat_id = sqlite3_column_int(stmt, 7i32) as uint32_t; + (*loc).independent = sqlite3_column_int(stmt, 5i32) as uint32_t; + (*loc).msg_id = sqlite3_column_int(stmt, 6i32) as uint32_t; + (*loc).contact_id = sqlite3_column_int(stmt, 7i32) as uint32_t; + (*loc).chat_id = sqlite3_column_int(stmt, 8i32) as uint32_t; + if 0 != (*loc).msg_id { let mut txt: *const libc::c_char = - sqlite3_column_text(stmt, 8i32) as *const libc::c_char; + sqlite3_column_text(stmt, 9i32) as *const libc::c_char; if 0 != is_marker(txt) { (*loc).marker = strdup(txt) } @@ -349,11 +357,18 @@ pub unsafe fn dc_get_location_kml( b"\n\n\n\x00" as *const u8 as *const libc::c_char, self_addr); - stmt = - dc_sqlite3_prepare((*context).sql, - b"SELECT id, latitude, longitude, accuracy, timestamp FROM locations WHERE from_id=? AND timestamp>=? AND (timestamp>=? OR timestamp=(SELECT MAX(timestamp) FROM locations WHERE from_id=?)) GROUP BY timestamp ORDER BY timestamp;\x00" - as *const u8 as - *const libc::c_char); + stmt = dc_sqlite3_prepare( + (*context).sql, + b"SELECT id, latitude, longitude, accuracy, timestamp\ + FROM locations WHERE from_id=? \ + AND timestamp>=? \ + AND (timestamp>=? OR timestamp=(SELECT MAX(timestamp) FROM locations WHERE from_id=?)) \ + AND independent=0 \ + GROUP BY timestamp \ + ORDER BY timestamp;\x00" as *const u8 + as *const libc::c_char, + ); + sqlite3_bind_int(stmt, 1i32, 1i32); sqlite3_bind_int64(stmt, 2i32, locations_send_begin as sqlite3_int64); sqlite3_bind_int64(stmt, 3i32, locations_last_sent as sqlite3_int64); @@ -436,6 +451,43 @@ unsafe fn get_kml_timestamp(mut utc: time_t) -> *mut libc::c_char { wanted_struct.tm_sec as libc::c_int, ); } + +pub unsafe fn dc_get_message_kml( + context: *const dc_context_t, + timestamp: time_t, + latitude: libc::c_double, + longitude: libc::c_double, +) -> *mut libc::c_char { + if !(context.is_null() || (*context).magic != 0x11a11807i32 as libc::c_uint) { + return std::ptr::null_mut(); + } + + let timestamp_str = get_kml_timestamp(timestamp); + let latitude_str = dc_ftoa(latitude); + let longitude_str = dc_ftoa(longitude); + + let ret = dc_mprintf( + b"\n\ + \n\ + \n\ + \ + %s\ + %s,%s\ + \n\ + \n\ + \x00" as *const u8 as *const libc::c_char, + timestamp_str, + longitude_str, // reverse order! + latitude_str, + ); + + free(latitude_str as *mut libc::c_void); + free(longitude_str as *mut libc::c_void); + free(timestamp_str as *mut libc::c_void); + + ret +} + pub unsafe fn dc_set_kml_sent_timestamp( mut context: *mut dc_context_t, mut chat_id: uint32_t, @@ -472,6 +524,7 @@ pub unsafe fn dc_save_locations( mut chat_id: uint32_t, mut contact_id: uint32_t, mut locations: *const dc_array_t, + independent: libc::c_int, ) -> uint32_t { let mut stmt_test: *mut sqlite3_stmt = 0 as *mut sqlite3_stmt; let mut stmt_insert: *mut sqlite3_stmt = 0 as *mut sqlite3_stmt; @@ -487,10 +540,12 @@ pub unsafe fn dc_save_locations( b"SELECT id FROM locations WHERE timestamp=? AND from_id=?\x00" as *const u8 as *const libc::c_char, ); - stmt_insert = - dc_sqlite3_prepare((*context).sql, - b"INSERT INTO locations (timestamp, from_id, chat_id, latitude, longitude, accuracy) VALUES (?,?,?,?,?,?);\x00" - as *const u8 as *const libc::c_char); + stmt_insert = dc_sqlite3_prepare( + (*context).sql, + b"INSERT INTO locations\ + (timestamp, from_id, chat_id, latitude, longitude, accuracy, independent) \ + VALUES (?,?,?,?,?,?,?);\x00" as *const u8 as *const libc::c_char, + ); let mut i: libc::c_int = 0i32; while (i as libc::c_ulong) < dc_array_get_cnt(locations) { let mut location: *mut dc_location_t = @@ -498,7 +553,7 @@ pub unsafe fn dc_save_locations( sqlite3_reset(stmt_test); sqlite3_bind_int64(stmt_test, 1i32, (*location).timestamp as sqlite3_int64); sqlite3_bind_int(stmt_test, 2i32, contact_id as libc::c_int); - if sqlite3_step(stmt_test) != 100i32 { + if independent | sqlite3_step(stmt_test) != 100i32 { sqlite3_reset(stmt_insert); sqlite3_bind_int64(stmt_insert, 1i32, (*location).timestamp as sqlite3_int64); sqlite3_bind_int(stmt_insert, 2i32, contact_id as libc::c_int); @@ -506,6 +561,7 @@ pub unsafe fn dc_save_locations( sqlite3_bind_double(stmt_insert, 4i32, (*location).latitude); sqlite3_bind_double(stmt_insert, 5i32, (*location).longitude); sqlite3_bind_double(stmt_insert, 6i32, (*location).accuracy); + sqlite3_bind_double(stmt_insert, 7i32, independent as libc::c_double); sqlite3_step(stmt_insert); } if (*location).timestamp > newest_timestamp { @@ -733,10 +789,12 @@ pub unsafe fn dc_job_do_DC_JOB_MAYBE_SEND_LOCATIONS( b" ----------------- MAYBE_SEND_LOCATIONS -------------- \x00" as *const u8 as *const libc::c_char, ); - stmt_chats = - dc_sqlite3_prepare((*context).sql, - b"SELECT id, locations_send_begin, locations_last_sent FROM chats WHERE locations_send_until>?;\x00" - as *const u8 as *const libc::c_char); + stmt_chats = dc_sqlite3_prepare( + (*context).sql, + b"SELECT id, locations_send_begin, locations_last_sent\ + FROM chats\ + WHERE locations_send_until>?;\x00" as *const u8 as *const libc::c_char, + ); sqlite3_bind_int64(stmt_chats, 1i32, now as sqlite3_int64); while sqlite3_step(stmt_chats) == 100i32 { let mut chat_id: uint32_t = sqlite3_column_int(stmt_chats, 0i32) as uint32_t; @@ -748,10 +806,16 @@ pub unsafe fn dc_job_do_DC_JOB_MAYBE_SEND_LOCATIONS( continue; } if stmt_locations.is_null() { - stmt_locations = - dc_sqlite3_prepare((*context).sql, - b"SELECT id FROM locations WHERE from_id=? AND timestamp>=? AND timestamp>? ORDER BY timestamp;\x00" - as *const u8 as *const libc::c_char) + stmt_locations = dc_sqlite3_prepare( + (*context).sql, + b"SELECT id \ + FROM locations \ + WHERE from_id=? \ + AND timestamp>=? \ + AND timestamp>? \ + AND independent=0 \ + ORDER BY timestamp;\x00" as *const u8 as *const libc::c_char, + ); } else { sqlite3_reset(stmt_locations); } diff --git a/src/dc_mimefactory.rs b/src/dc_mimefactory.rs index edfba9eb6..e24d9af85 100644 --- a/src/dc_mimefactory.rs +++ b/src/dc_mimefactory.rs @@ -850,6 +850,44 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc: mailmime_smart_add_part(message, meta_part); parts += 1 } + if 0 != dc_param_exists((*msg).param, DC_PARAM_SET_LATITUDE as libc::c_int) + { + let latitude = dc_param_get_float( + (*msg).param, + DC_PARAM_SET_LATITUDE as libc::c_int, + 0.0, + ); + let longitude = dc_param_get_float( + (*msg).param, + DC_PARAM_SET_LONGITUDE as libc::c_int, + 0.0, + ); + let kml_file = dc_get_message_kml( + (*msg).context, + (*msg).timestamp_sort, + latitude, + longitude, + ); + if !kml_file.is_null() { + let content_type = mailmime_content_new_with_str( + b"application/vnd.google-earth.kml+xml\x00" as *const u8 + as *const libc::c_char, + ); + let mime_fields = mailmime_fields_new_filename( + MAILMIME_DISPOSITION_TYPE_ATTACHMENT as libc::c_int, + dc_strdup( + b"message.kml\x00" as *const u8 as *const libc::c_char, + ), + MAILMIME_MECHANISM_8BIT as libc::c_int, + ); + let kml_mime_part = mailmime_new_empty(content_type, mime_fields); + mailmime_set_body_text(kml_mime_part, kml_file, strlen(kml_file)); + + mailmime_smart_add_part(message, kml_mime_part); + parts += 1; + } + } + if 0 != dc_is_sending_locations_to_chat((*msg).context, (*msg).chat_id) { let mut last_added_location_id: uint32_t = 0i32 as uint32_t; let mut kml_file: *mut libc::c_char = dc_get_location_kml( @@ -876,7 +914,13 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc: mailmime_set_body_text(kml_mime_part, kml_file, strlen(kml_file)); mailmime_smart_add_part(message, kml_mime_part); parts += 1; - (*factory).out_last_added_location_id = last_added_location_id + if 0 == dc_param_exists( + (*msg).param, + DC_PARAM_SET_LATITUDE as libc::c_int, + ) { + // otherwise, the independent location is already filed + (*factory).out_last_added_location_id = last_added_location_id; + } } } current_block = 9952640327414195044; diff --git a/src/dc_mimeparser.rs b/src/dc_mimeparser.rs index c1a81455b..68b7ce3b6 100644 --- a/src/dc_mimeparser.rs +++ b/src/dc_mimeparser.rs @@ -53,7 +53,8 @@ pub struct dc_mimeparser_t { pub context: *mut dc_context_t, pub reports: *mut carray, pub is_system_message: libc::c_int, - pub kml: *mut dc_kml_t, + pub location_kml: *mut dc_kml_t, + pub message_kml: *mut dc_kml_t, } // deprecated @@ -99,6 +100,7 @@ pub unsafe fn dc_mimeparser_unref(mut mimeparser: *mut dc_mimeparser_t) { free((*mimeparser).e2ee_helper as *mut libc::c_void); free(mimeparser as *mut libc::c_void); } + pub unsafe fn dc_mimeparser_empty(mut mimeparser: *mut dc_mimeparser_t) { if mimeparser.is_null() { return; @@ -137,9 +139,14 @@ pub unsafe fn dc_mimeparser_empty(mut mimeparser: *mut dc_mimeparser_t) { } (*mimeparser).decrypting_failed = 0i32; dc_e2ee_thanks((*mimeparser).e2ee_helper); - dc_kml_unref((*mimeparser).kml); - (*mimeparser).kml = 0 as *mut dc_kml_t; + + dc_kml_unref((*mimeparser).location_kml); + (*mimeparser).location_kml = 0 as *mut dc_kml_t; + + dc_kml_unref((*mimeparser).message_kml); + (*mimeparser).message_kml = 0 as *mut dc_kml_t; } + unsafe fn dc_mimepart_unref(mut mimepart: *mut dc_mimepart_t) { if mimepart.is_null() { return; @@ -1415,7 +1422,26 @@ unsafe fn dc_mimeparser_add_single_part_if_known( 4i32 as libc::c_ulong, ) == 0i32 { - (*mimeparser).kml = dc_kml_parse( + (*mimeparser).location_kml = dc_kml_parse( + (*mimeparser).context, + decoded_data, + decoded_data_bytes, + ); + current_block = 8795901732489102124; + } else if strncmp( + desired_filename, + b"message\x00" as *const u8 as *const libc::c_char, + 7i32 as libc::c_ulong, + ) == 0i32 + && strncmp( + desired_filename + .offset(strlen(desired_filename) as isize) + .offset(-4isize), + b".kml\x00" as *const u8 as *const libc::c_char, + 4i32 as libc::c_ulong, + ) == 0i32 + { + (*mimeparser).message_kml = dc_kml_parse( (*mimeparser).context, decoded_data, decoded_data_bytes, diff --git a/src/dc_msg.rs b/src/dc_msg.rs index ddc33badb..fa06338c0 100644 --- a/src/dc_msg.rs +++ b/src/dc_msg.rs @@ -442,12 +442,60 @@ pub unsafe fn dc_msg_get_file(mut msg: *const dc_msg_t) -> *mut libc::c_char { dc_strdup(0 as *const libc::c_char) }; } + +/** + * Check if a message has a location bound to it. + * These messages are also returned by dc_get_locations() + * and the UI may decide to display a special icon beside such messages, + * + * @memberof dc_msg_t + * @param msg The message object. + * @return 1=Message has location bound to it, 0=No location bound to message. + */ pub unsafe fn dc_msg_has_location(mut msg: *const dc_msg_t) -> libc::c_int { if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint { return 0i32; } return ((*msg).location_id != 0i32 as libc::c_uint) as libc::c_int; } + +/** + * Set any location that should be bound to the message object. + * The function is useful to add a marker to the map + * at a position different from the self-location. + * You should not call this function + * if you want to bind the current self-location to a message; + * this is done by dc_set_location() and dc_send_locations_to_chat(). + * + * Typically results in the event #DC_EVENT_LOCATION_CHANGED with + * contact_id set to DC_CONTACT_ID_SELF. + * + * @memberof dc_msg_t + * @param msg The message object. + * @param latitude North-south position of the location. + * @param longitude East-west position of the location. + * @return None. + */ +pub unsafe fn dc_msg_set_location( + mut msg: *const dc_msg_t, + latitude: libc::c_double, + longitude: libc::c_double, +) { + if msg.is_null() + || (*msg).magic != 0x11561156i32 as libc::c_uint + || (latitude == 0.0 && longitude == 0.0) + { + return; + } + + dc_param_set_float((*msg).param, DC_PARAM_SET_LATITUDE as libc::c_int, latitude); + dc_param_set_float( + (*msg).param, + DC_PARAM_SET_LONGITUDE as libc::c_int, + longitude, + ); +} + pub unsafe fn dc_msg_get_timestamp(mut msg: *const dc_msg_t) -> time_t { if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint { return 0i32 as time_t; diff --git a/src/dc_param.rs b/src/dc_param.rs index 0cd05b55b..e74b51d4d 100644 --- a/src/dc_param.rs +++ b/src/dc_param.rs @@ -4,17 +4,71 @@ use crate::dc_tools::*; use crate::types::*; use crate::x::*; -/* * - * @class dc_param_t - * - * An object for handling key=value parameter lists; for the key, curently only - * a single character is allowed. - * - * The object is used eg. by dc_chat_t or dc_msg_t, for readable paramter names, - * these classes define some DC_PARAM_* constantats. - * - * Only for library-internal use. - */ +/// for msgs and jobs +pub const DC_PARAM_FILE: char = 'f'; +/// for msgs +pub const DC_PARAM_WIDTH: char = 'w'; +/// for msgs +pub const DC_PARAM_HEIGHT: char = 'h'; +/// for msgs +pub const DC_PARAM_DURATION: char = 'd'; +/// for msgs +pub const DC_PARAM_MIMETYPE: char = 'm'; +/// for msgs: incoming: message is encryoted, outgoing: guarantee E2EE or the message is not send +pub const DC_PARAM_GUARANTEE_E2EE: char = 'c'; +/// for msgs: decrypted with validation errors or without mutual set, if neither 'c' nor 'e' are preset, the messages is only transport encrypted +pub const DC_PARAM_ERRONEOUS_E2EE: char = 'e'; +/// for msgs: force unencrypted message, either DC_FP_ADD_AUTOCRYPT_HEADER (1), DC_FP_NO_AUTOCRYPT_HEADER (2) or 0 +pub const DC_PARAM_FORCE_PLAINTEXT: char = 'u'; +/// for msgs: an incoming message which requestes a MDN (aka read receipt) +pub const DC_PARAM_WANTS_MDN: char = 'r'; +/// for msgs +pub const DC_PARAM_FORWARDED: char = 'a'; +/// for msgs +pub const DC_PARAM_CMD: char = 'S'; +/// for msgs +pub const DC_PARAM_CMD_ARG: char = 'E'; +/// for msgs +pub const DC_PARAM_CMD_ARG2: char = 'F'; +/// for msgs +pub const DC_PARAM_CMD_ARG3: char = 'G'; +/// for msgs +pub const DC_PARAM_CMD_ARG4: char = 'H'; +/// for msgs +pub const DC_PARAM_ERROR: char = 'L'; +/// for msgs in PREPARING: space-separated list of message IDs of forwarded copies +pub const DC_PARAM_PREP_FORWARDS: char = 'P'; +/// for msgs +pub const DC_PARAM_SET_LATITUDE: char = 'l'; +/// for msgs +pub const DC_PARAM_SET_LONGITUDE: char = 'n'; + +/// for jobs +pub const DC_PARAM_SERVER_FOLDER: char = 'Z'; +/// for jobs +pub const DC_PARAM_SERVER_UID: char = 'z'; +/// for jobs +pub const DC_PARAM_ALSO_MOVE: char = 'M'; +/// for jobs: space-separated list of message recipients +pub const DC_PARAM_RECIPIENTS: char = 'R'; +/// for groups +pub const DC_PARAM_UNPROMOTED: char = 'U'; +/// for groups and contacts +pub const DC_PARAM_PROFILE_IMAGE: char = 'i'; +/// for chats +pub const DC_PARAM_SELFTALK: char = 'K'; + +// values for DC_PARAM_FORCE_PLAINTEXT +pub const DC_FP_ADD_AUTOCRYPT_HEADER: u8 = 1; +pub const DC_FP_NO_AUTOCRYPT_HEADER: u8 = 2; + +/// An object for handling key=value parameter lists; for the key, curently only +/// a single character is allowed. +/// +/// The object is used eg. by dc_chat_t or dc_msg_t, for readable paramter names, +/// these classes define some DC_PARAM_* constantats. +/// +/// Only for library-internal use. #[derive(Copy, Clone)] #[repr(C)] pub struct dc_param_t { @@ -34,6 +88,7 @@ pub unsafe fn dc_param_exists(mut param: *mut dc_param_t, mut key: libc::c_int) 0i32 }; } + unsafe extern "C" fn find_param( mut haystack: *mut libc::c_char, mut key: libc::c_int, @@ -111,6 +166,36 @@ pub unsafe fn dc_param_get_int( free(str as *mut libc::c_void); return ret; } + +/** + * Get value of a parameter. + * + * @memberof dc_param_t + * @param param Parameter object to query. + * @param key Key of the parameter to get, one of the DC_PARAM_* constants. + * @param def Value to return if the parameter is not set. + * @return The stored value or the default value. + */ +pub unsafe fn dc_param_get_float( + param: *const dc_param_t, + key: libc::c_int, + def: libc::c_double, +) -> libc::c_double { + if param.is_null() || key == 0 { + return def; + } + + let mut str = dc_param_get(param, key, std::ptr::null()); + if str.is_null() { + return def; + } + + let ret = dc_atof(str) as libc::c_double; + free(str as *mut libc::c_void); + + ret +} + pub unsafe fn dc_param_set( mut param: *mut dc_param_t, mut key: libc::c_int, @@ -265,3 +350,25 @@ pub unsafe fn dc_param_set_urlencoded( ); }; } + +/** + * Set parameter to a float. + * + * @memberof dc_param_t + * @param param Parameter object to modify. + * @param key Key of the parameter to modify, one of the DC_PARAM_* constants. + * @param value Value to store for key. + * @return None. + */ +pub unsafe fn dc_param_set_float(param: *mut dc_param_t, key: libc::c_int, value: libc::c_double) { + if param.is_null() || key == 0 { + return; + } + + let value_str = dc_ftoa(value); + if value_str.is_null() { + return; + } + dc_param_set(param, key, value_str); + free(value_str as *mut libc::c_void); +} diff --git a/src/dc_receive_imf.rs b/src/dc_receive_imf.rs index d0d4eae4b..4a66075e4 100644 --- a/src/dc_receive_imf.rs +++ b/src/dc_receive_imf.rs @@ -1,7 +1,7 @@ use c2rust_bitfields::BitfieldStruct; use libc; -use crate::constants::Event; +use crate::constants::*; use crate::dc_apeerstate::*; use crate::dc_array::*; use crate::dc_chat::*; @@ -552,7 +552,7 @@ pub unsafe fn dc_receive_imf( carray_get((*mime_parser).parts, i as libc::c_uint) as *mut dc_mimepart_t; if !(0 != (*part).is_meta) { - if !(*mime_parser).kml.is_null() + if !(*mime_parser).location_kml.is_null() && icnt == 1i32 as libc::c_ulong && !(*part).msg.is_null() && (strcmp( @@ -922,22 +922,56 @@ pub unsafe fn dc_receive_imf( i = i.wrapping_add(1) } } - if !(*mime_parser).kml.is_null() && chat_id > 9i32 as libc::c_uint { - let mut contact: *mut dc_contact_t = dc_get_contact(context, from_id); - if !(*(*mime_parser).kml).addr.is_null() - && !contact.is_null() - && !(*contact).addr.is_null() - && strcasecmp((*contact).addr, (*(*mime_parser).kml).addr) == 0i32 + if !(*mime_parser).message_kml.is_null() && chat_id > 9i32 as libc::c_uint { + let mut location_id_written = false; + let mut send_event = false; + + if !(*mime_parser).message_kml.is_null() + && chat_id > DC_CHAT_ID_LAST_SPECIAL as libc::c_uint { let mut newest_location_id: uint32_t = dc_save_locations( context, chat_id, from_id, - (*(*mime_parser).kml).locations, + (*(*mime_parser).message_kml).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_null() + && chat_id > DC_CHAT_ID_LAST_SPECIAL as libc::c_uint + { + let contact = dc_get_contact(context, from_id); + if !(*(*mime_parser).location_kml).addr.is_null() + && !contact.is_null() + && !(*contact).addr.is_null() + && strcasecmp((*contact).addr, (*(*mime_parser).location_kml).addr) + == 0i32 + { + let newest_location_id = dc_save_locations( + context, + chat_id, + from_id, + (*(*mime_parser).location_kml).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; + } + dc_contact_unref(contact); + } + if send_event { (*context).cb.expect("non-null function pointer")( context, Event::LOCATION_CHANGED, @@ -945,8 +979,8 @@ pub unsafe fn dc_receive_imf( 0i32 as uintptr_t, ); } - dc_contact_unref(contact); } + if 0 != add_delete_job && carray_count(created_db_entries) >= 2i32 as libc::c_uint { diff --git a/src/dc_sqlite3.rs b/src/dc_sqlite3.rs index 4dd683118..49f6fd384 100644 --- a/src/dc_sqlite3.rs +++ b/src/dc_sqlite3.rs @@ -740,6 +740,20 @@ pub unsafe fn dc_sqlite3_open( 54i32, ); } + if dbversion < 55 { + dc_sqlite3_execute( + sql, + b"ALTER TABLE locations ADD COLUMN independent INTEGER DEFAULT 0;\x00" as *const u8 as *const libc::c_char + ); + + dbversion = 55; + dc_sqlite3_set_config_int( + sql, + b"dbversion\x00" as *const u8 as *const libc::c_char, + 55, + ); + } + if 0 != recalc_fingerprints { let mut stmt: *mut sqlite3_stmt = dc_sqlite3_prepare( sql,