use libc; use crate::constants::Event; use crate::dc_array::*; use crate::dc_chat::*; use crate::dc_context::*; use crate::dc_job::*; use crate::dc_log::*; use crate::dc_msg::*; use crate::dc_param::*; use crate::dc_saxparser::*; use crate::dc_sqlite3::*; use crate::dc_stock::*; use crate::dc_strbuilder::*; use crate::dc_tools::*; use crate::types::*; use crate::x::*; // location handling #[derive(Copy, Clone)] #[repr(C)] pub struct dc_location_t { 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, } #[derive(Copy, Clone)] #[repr(C)] pub struct dc_kml_t { pub addr: *mut libc::c_char, pub locations: *mut dc_array_t, pub tag: libc::c_int, pub curr: dc_location_t, } // location streaming pub unsafe fn dc_send_locations_to_chat( mut context: &dc_context_t, mut chat_id: uint32_t, mut seconds: libc::c_int, ) { let mut stmt: *mut sqlite3_stmt = 0 as *mut sqlite3_stmt; let mut now: time_t = time(0 as *mut time_t); let mut msg: *mut dc_msg_t = 0 as *mut dc_msg_t; let mut stock_str: *mut libc::c_char = 0 as *mut libc::c_char; let mut is_sending_locations_before: libc::c_int = 0i32; if !(seconds < 0i32 || chat_id <= 9i32 as libc::c_uint) { is_sending_locations_before = dc_is_sending_locations_to_chat(context, chat_id); stmt = dc_sqlite3_prepare( context, &mut context.sql.clone().lock().unwrap(), b"UPDATE chats SET locations_send_begin=?, locations_send_until=? WHERE id=?\x00" as *const u8 as *const libc::c_char); sqlite3_bind_int64( stmt, 1i32, (if 0 != seconds { now } else { 0i32 as libc::c_long }) as sqlite3_int64, ); sqlite3_bind_int64( stmt, 2i32, (if 0 != seconds { now + seconds as libc::c_long } else { 0i32 as libc::c_long }) as sqlite3_int64, ); sqlite3_bind_int(stmt, 3i32, chat_id as libc::c_int); sqlite3_step(stmt); if 0 != seconds && 0 == is_sending_locations_before { msg = dc_msg_new(context, 10i32); (*msg).text = dc_stock_system_msg( context, 64i32, 0 as *const libc::c_char, 0 as *const libc::c_char, 0i32 as uint32_t, ); dc_param_set_int((*msg).param, 'S' as i32, 8i32); dc_send_msg(context, chat_id, msg); } else if 0 == seconds && 0 != is_sending_locations_before { stock_str = dc_stock_system_msg( context, 65i32, 0 as *const libc::c_char, 0 as *const libc::c_char, 0i32 as uint32_t, ); dc_add_device_msg(context, chat_id, stock_str); } (context.cb)( context, Event::CHAT_MODIFIED, chat_id as uintptr_t, 0i32 as uintptr_t, ); if 0 != seconds { schedule_MAYBE_SEND_LOCATIONS(context, 0i32); dc_job_add( context, 5007i32, chat_id as libc::c_int, 0 as *const libc::c_char, seconds + 1i32, ); } } free(stock_str as *mut libc::c_void); dc_msg_unref(msg); sqlite3_finalize(stmt); } /* ****************************************************************************** * job to send locations out to all chats that want them ******************************************************************************/ unsafe fn schedule_MAYBE_SEND_LOCATIONS(mut context: &dc_context_t, mut flags: libc::c_int) { if 0 != flags & 0x1i32 || 0 == dc_job_action_exists(context, 5005i32) { dc_job_add(context, 5005i32, 0i32, 0 as *const libc::c_char, 60i32); }; } pub unsafe extern "C" fn dc_is_sending_locations_to_chat( mut context: &dc_context_t, mut chat_id: uint32_t, ) -> libc::c_int { let mut is_sending_locations: libc::c_int = 0i32; let mut stmt: *mut sqlite3_stmt = 0 as *mut sqlite3_stmt; stmt = dc_sqlite3_prepare( context, &mut context.sql.clone().lock().unwrap(), b"SELECT id FROM chats WHERE (? OR id=?) AND locations_send_until>?;\x00" as *const u8 as *const libc::c_char, ); sqlite3_bind_int( stmt, 1i32, if chat_id == 0i32 as libc::c_uint { 1i32 } else { 0i32 }, ); sqlite3_bind_int(stmt, 2i32, chat_id as libc::c_int); sqlite3_bind_int64(stmt, 3i32, time(0 as *mut time_t) as sqlite3_int64); if !(sqlite3_step(stmt) != 100i32) { is_sending_locations = 1i32 } sqlite3_finalize(stmt); return is_sending_locations; } pub unsafe fn dc_set_location( mut context: &dc_context_t, mut latitude: libc::c_double, mut longitude: libc::c_double, mut accuracy: libc::c_double, ) -> libc::c_int { let mut stmt_chats: *mut sqlite3_stmt = 0 as *mut sqlite3_stmt; let mut stmt_insert: *mut sqlite3_stmt = 0 as *mut sqlite3_stmt; let mut continue_streaming: libc::c_int = 0i32; if latitude == 0.0f64 && longitude == 0.0f64 { continue_streaming = 1i32 } else { stmt_chats = dc_sqlite3_prepare( context, &mut context.sql.clone().lock().unwrap(), b"SELECT id FROM chats WHERE locations_send_until>?;\x00" as *const u8 as *const libc::c_char, ); sqlite3_bind_int64(stmt_chats, 1i32, time(0 as *mut time_t) as sqlite3_int64); while sqlite3_step(stmt_chats) == 100i32 { let mut chat_id: uint32_t = sqlite3_column_int(stmt_chats, 0i32) as uint32_t; stmt_insert = dc_sqlite3_prepare( context, &mut context.sql.clone().lock().unwrap(), b"INSERT INTO locations (latitude, longitude, accuracy, timestamp, chat_id, from_id) VALUES (?,?,?,?,?,?);\x00" as *const u8 as *const libc::c_char); sqlite3_bind_double(stmt_insert, 1i32, latitude); sqlite3_bind_double(stmt_insert, 2i32, longitude); sqlite3_bind_double(stmt_insert, 3i32, accuracy); sqlite3_bind_int64(stmt_insert, 4i32, time(0 as *mut time_t) as sqlite3_int64); sqlite3_bind_int(stmt_insert, 5i32, chat_id as libc::c_int); sqlite3_bind_int(stmt_insert, 6i32, 1i32); sqlite3_step(stmt_insert); continue_streaming = 1i32 } if 0 != continue_streaming { (context.cb)( context, Event::LOCATION_CHANGED, 1i32 as uintptr_t, 0i32 as uintptr_t, ); schedule_MAYBE_SEND_LOCATIONS(context, 0i32); } } sqlite3_finalize(stmt_chats); sqlite3_finalize(stmt_insert); return continue_streaming; } pub unsafe fn dc_get_locations( mut context: &dc_context_t, mut chat_id: uint32_t, mut contact_id: uint32_t, mut timestamp_from: time_t, mut timestamp_to: time_t, ) -> *mut dc_array_t { let mut ret: *mut dc_array_t = dc_array_new_typed(1i32, 500i32 as size_t); let mut stmt: *mut sqlite3_stmt = 0 as *mut sqlite3_stmt; 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, &mut context.sql.clone().lock().unwrap(), 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, if chat_id == 0i32 as libc::c_uint { 1i32 } else { 0i32 }, ); sqlite3_bind_int(stmt, 2i32, chat_id as libc::c_int); sqlite3_bind_int( stmt, 3i32, if contact_id == 0i32 as libc::c_uint { 1i32 } else { 0i32 }, ); sqlite3_bind_int(stmt, 4i32, contact_id as libc::c_int); sqlite3_bind_int(stmt, 5i32, timestamp_from as libc::c_int); sqlite3_bind_int(stmt, 6i32, timestamp_to as libc::c_int); while sqlite3_step(stmt) == 100i32 { let mut loc: *mut _dc_location = calloc(1, ::std::mem::size_of::<_dc_location>()) as *mut _dc_location; if loc.is_null() { break; } (*loc).location_id = sqlite3_column_double(stmt, 0i32) as uint32_t; (*loc).latitude = sqlite3_column_double(stmt, 1i32); (*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).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, 9i32) as *const libc::c_char; if 0 != is_marker(txt) { (*loc).marker = strdup(txt) } } dc_array_add_ptr(ret, loc as *mut libc::c_void); } sqlite3_finalize(stmt); return ret; } unsafe fn is_marker(mut txt: *const libc::c_char) -> libc::c_int { if !txt.is_null() { let mut len: libc::c_int = dc_utf8_strlen(txt) as libc::c_int; if len == 1i32 && *txt.offset(0isize) as libc::c_int != ' ' as i32 { return 1i32; } } return 0i32; } pub unsafe fn dc_delete_all_locations(mut context: &dc_context_t) { let mut stmt: *mut sqlite3_stmt = 0 as *mut sqlite3_stmt; stmt = dc_sqlite3_prepare( context, &mut context.sql.clone().lock().unwrap(), b"DELETE FROM locations;\x00" as *const u8 as *const libc::c_char, ); sqlite3_step(stmt); (context.cb)( context, Event::LOCATION_CHANGED, 0i32 as uintptr_t, 0i32 as uintptr_t, ); sqlite3_finalize(stmt); } pub unsafe fn dc_get_location_kml( mut context: &dc_context_t, mut chat_id: uint32_t, mut last_added_location_id: *mut uint32_t, ) -> *mut libc::c_char { let mut success: libc::c_int = 0i32; let mut stmt: *mut sqlite3_stmt = 0 as *mut sqlite3_stmt; let mut self_addr: *mut libc::c_char = 0 as *mut libc::c_char; let mut now: time_t = time(0 as *mut time_t); let mut locations_send_begin: time_t = 0i32 as time_t; let mut locations_send_until: time_t = 0i32 as time_t; let mut locations_last_sent: time_t = 0i32 as time_t; let mut location_count: libc::c_int = 0i32; let mut ret: dc_strbuilder_t = dc_strbuilder_t { buf: 0 as *mut libc::c_char, allocated: 0, free: 0, eos: 0 as *mut libc::c_char, }; dc_strbuilder_init(&mut ret, 1000i32); self_addr = dc_sqlite3_get_config( context, &mut context.sql.clone().lock().unwrap(), b"configured_addr\x00" as *const u8 as *const libc::c_char, b"\x00" as *const u8 as *const libc::c_char, ); stmt = dc_sqlite3_prepare( context, &mut context.sql.clone().lock().unwrap(), b"SELECT locations_send_begin, locations_send_until, locations_last_sent FROM chats WHERE id=?;\x00" as *const u8 as *const libc::c_char); sqlite3_bind_int(stmt, 1i32, chat_id as libc::c_int); if !(sqlite3_step(stmt) != 100i32) { locations_send_begin = sqlite3_column_int64(stmt, 0i32) as time_t; locations_send_until = sqlite3_column_int64(stmt, 1i32) as time_t; locations_last_sent = sqlite3_column_int64(stmt, 2i32) as time_t; sqlite3_finalize(stmt); stmt = 0 as *mut sqlite3_stmt; if !(locations_send_begin == 0i32 as libc::c_long || now > locations_send_until) { dc_strbuilder_catf(&mut ret as *mut dc_strbuilder_t, b"\n\n\n\x00" as *const u8 as *const libc::c_char, self_addr); stmt = dc_sqlite3_prepare( context, &mut context.sql.clone().lock().unwrap(), 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); sqlite3_bind_int(stmt, 4i32, 1i32); while sqlite3_step(stmt) == 100i32 { let mut location_id: uint32_t = sqlite3_column_int(stmt, 0i32) as uint32_t; let mut latitude: *mut libc::c_char = dc_ftoa(sqlite3_column_double(stmt, 1i32)); let mut longitude: *mut libc::c_char = dc_ftoa(sqlite3_column_double(stmt, 2i32)); let mut accuracy: *mut libc::c_char = dc_ftoa(sqlite3_column_double(stmt, 3i32)); let mut timestamp: *mut libc::c_char = get_kml_timestamp(sqlite3_column_int64(stmt, 4i32) as time_t); dc_strbuilder_catf(&mut ret as *mut dc_strbuilder_t, b"%s%s,%s\n\x00" as *const u8 as *const libc::c_char, timestamp, accuracy, longitude, latitude); location_count += 1; if !last_added_location_id.is_null() { *last_added_location_id = location_id } free(latitude as *mut libc::c_void); free(longitude as *mut libc::c_void); free(accuracy as *mut libc::c_void); free(timestamp as *mut libc::c_void); } if !(location_count == 0i32) { dc_strbuilder_cat( &mut ret, b"\n\x00" as *const u8 as *const libc::c_char, ); success = 1i32 } } } sqlite3_finalize(stmt); free(self_addr as *mut libc::c_void); if 0 == success { free(ret.buf as *mut libc::c_void); } return if 0 != success { ret.buf } else { 0 as *mut libc::c_char }; } /* ****************************************************************************** * create kml-files ******************************************************************************/ unsafe fn get_kml_timestamp(mut utc: time_t) -> *mut libc::c_char { // Returns a string formatted as YYYY-MM-DDTHH:MM:SSZ. The trailing `Z` indicates UTC. let mut wanted_struct: tm = tm { tm_sec: 0, tm_min: 0, tm_hour: 0, tm_mday: 0, tm_mon: 0, tm_year: 0, tm_wday: 0, tm_yday: 0, tm_isdst: 0, tm_gmtoff: 0, tm_zone: 0 as *mut libc::c_char, }; memcpy( &mut wanted_struct as *mut tm as *mut libc::c_void, gmtime(&mut utc) as *const libc::c_void, ::std::mem::size_of::(), ); return dc_mprintf( b"%04i-%02i-%02iT%02i:%02i:%02iZ\x00" as *const u8 as *const libc::c_char, wanted_struct.tm_year as libc::c_int + 1900i32, wanted_struct.tm_mon as libc::c_int + 1i32, wanted_struct.tm_mday as libc::c_int, wanted_struct.tm_hour as libc::c_int, wanted_struct.tm_min as libc::c_int, wanted_struct.tm_sec as libc::c_int, ); } pub unsafe fn dc_get_message_kml( timestamp: time_t, latitude: libc::c_double, longitude: libc::c_double, ) -> *mut libc::c_char { 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( context: &dc_context_t, chat_id: uint32_t, timestamp: time_t, ) { let mut stmt: *mut sqlite3_stmt = 0 as *mut sqlite3_stmt; stmt = dc_sqlite3_prepare( context, &mut context.sql.clone().lock().unwrap(), b"UPDATE chats SET locations_last_sent=? WHERE id=?;\x00" as *const u8 as *const libc::c_char, ); sqlite3_bind_int64(stmt, 1i32, timestamp as sqlite3_int64); sqlite3_bind_int(stmt, 2i32, chat_id as libc::c_int); sqlite3_step(stmt); sqlite3_finalize(stmt); } pub unsafe fn dc_set_msg_location_id( mut context: &dc_context_t, mut msg_id: uint32_t, mut location_id: uint32_t, ) { let mut stmt: *mut sqlite3_stmt = 0 as *mut sqlite3_stmt; stmt = dc_sqlite3_prepare( context, &mut context.sql.clone().lock().unwrap(), b"UPDATE msgs SET location_id=? WHERE id=?;\x00" as *const u8 as *const libc::c_char, ); sqlite3_bind_int64(stmt, 1i32, location_id as sqlite3_int64); sqlite3_bind_int(stmt, 2i32, msg_id as libc::c_int); sqlite3_step(stmt); sqlite3_finalize(stmt); } pub unsafe fn dc_save_locations( mut context: &dc_context_t, 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; let mut newest_timestamp: time_t = 0i32 as time_t; let mut newest_location_id: uint32_t = 0i32 as uint32_t; if !(chat_id <= 9i32 as libc::c_uint || locations.is_null()) { stmt_test = dc_sqlite3_prepare( context, &mut context.sql.clone().lock().unwrap(), 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, &mut context.sql.clone().lock().unwrap(), 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 = 0; while i < dc_array_get_cnt(locations) { let mut location: *mut dc_location_t = dc_array_get_ptr(locations, i as size_t) as *mut dc_location_t; 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 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); sqlite3_bind_int(stmt_insert, 3i32, chat_id as libc::c_int); 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 { newest_timestamp = (*location).timestamp; newest_location_id = dc_sqlite3_get_rowid2( context, &mut context.sql.clone().lock().unwrap(), b"locations\x00" as *const u8 as *const libc::c_char, b"timestamp\x00" as *const u8 as *const libc::c_char, (*location).timestamp as uint64_t, b"from_id\x00" as *const u8 as *const libc::c_char, contact_id, ) } i += 1 } } sqlite3_finalize(stmt_test); sqlite3_finalize(stmt_insert); return newest_location_id; } pub unsafe fn dc_kml_parse( mut context: &dc_context_t, mut content: *const libc::c_char, mut content_bytes: size_t, ) -> *mut dc_kml_t { let mut kml: *mut dc_kml_t = calloc(1, ::std::mem::size_of::()) as *mut dc_kml_t; let mut content_nullterminated: *mut libc::c_char = 0 as *mut libc::c_char; let mut saxparser: dc_saxparser_t = dc_saxparser_t { starttag_cb: None, endtag_cb: None, text_cb: None, userdata: 0 as *mut libc::c_void, }; if content_bytes > (1 * 1024 * 1024) { dc_log_warning( context, 0, b"A kml-files with %i bytes is larger than reasonably expected.\x00" as *const u8 as *const libc::c_char, content_bytes, ); } else { content_nullterminated = dc_null_terminate(content, content_bytes as libc::c_int); if !content_nullterminated.is_null() { (*kml).locations = dc_array_new_typed(1, 100 as size_t); dc_saxparser_init(&mut saxparser, kml as *mut libc::c_void); dc_saxparser_set_tag_handler( &mut saxparser, Some(kml_starttag_cb), Some(kml_endtag_cb), ); dc_saxparser_set_text_handler(&mut saxparser, Some(kml_text_cb)); dc_saxparser_parse(&mut saxparser, content_nullterminated); } } free(content_nullterminated as *mut libc::c_void); return kml; } unsafe fn kml_text_cb(userdata: *mut libc::c_void, text: *const libc::c_char, _len: libc::c_int) { let mut kml: *mut dc_kml_t = userdata as *mut dc_kml_t; if 0 != (*kml).tag & (0x4 | 0x10) { let mut val: *mut libc::c_char = dc_strdup(text); dc_str_replace( &mut val, b"\n\x00" as *const u8 as *const libc::c_char, b"\x00" as *const u8 as *const libc::c_char, ); dc_str_replace( &mut val, b"\r\x00" as *const u8 as *const libc::c_char, b"\x00" as *const u8 as *const libc::c_char, ); dc_str_replace( &mut val, b"\t\x00" as *const u8 as *const libc::c_char, b"\x00" as *const u8 as *const libc::c_char, ); dc_str_replace( &mut val, b" \x00" as *const u8 as *const libc::c_char, b"\x00" as *const u8 as *const libc::c_char, ); if 0 != (*kml).tag & 0x4 && strlen(val) >= 19 { let mut tmval: tm = tm { tm_sec: 0, tm_min: 0, tm_hour: 0, tm_mday: 0, tm_mon: 0, tm_year: 0, tm_wday: 0, tm_yday: 0, tm_isdst: 0, tm_gmtoff: 0, tm_zone: 0 as *mut libc::c_char, }; memset( &mut tmval as *mut tm as *mut libc::c_void, 0, ::std::mem::size_of::(), ); *val.offset(4isize) = 0i32 as libc::c_char; tmval.tm_year = atoi(val) - 1900i32; *val.offset(7isize) = 0i32 as libc::c_char; tmval.tm_mon = atoi(val.offset(5isize)) - 1i32; *val.offset(10isize) = 0i32 as libc::c_char; tmval.tm_mday = atoi(val.offset(8isize)); *val.offset(13isize) = 0i32 as libc::c_char; tmval.tm_hour = atoi(val.offset(11isize)); *val.offset(16isize) = 0i32 as libc::c_char; tmval.tm_min = atoi(val.offset(14isize)); *val.offset(19isize) = 0i32 as libc::c_char; tmval.tm_sec = atoi(val.offset(17isize)); (*kml).curr.timestamp = mkgmtime(&mut tmval); if (*kml).curr.timestamp > time(0 as *mut time_t) { (*kml).curr.timestamp = time(0 as *mut time_t) } } else if 0 != (*kml).tag & 0x10i32 { let mut comma: *mut libc::c_char = strchr(val, ',' as i32); if !comma.is_null() { let mut longitude: *mut libc::c_char = val; let mut latitude: *mut libc::c_char = comma.offset(1isize); *comma = 0i32 as libc::c_char; comma = strchr(latitude, ',' as i32); if !comma.is_null() { *comma = 0i32 as libc::c_char } (*kml).curr.latitude = dc_atof(latitude); (*kml).curr.longitude = dc_atof(longitude) } } free(val as *mut libc::c_void); }; } unsafe fn kml_endtag_cb(mut userdata: *mut libc::c_void, mut tag: *const libc::c_char) { let mut kml: *mut dc_kml_t = userdata as *mut dc_kml_t; if strcmp(tag, b"placemark\x00" as *const u8 as *const libc::c_char) == 0i32 { if 0 != (*kml).tag & 0x1i32 && 0 != (*kml).curr.timestamp && 0. != (*kml).curr.latitude && 0. != (*kml).curr.longitude { let mut location: *mut dc_location_t = calloc(1, ::std::mem::size_of::()) as *mut dc_location_t; *location = (*kml).curr; dc_array_add_ptr((*kml).locations, location as *mut libc::c_void); } (*kml).tag = 0i32 }; } /* ****************************************************************************** * parse kml-files ******************************************************************************/ unsafe fn kml_starttag_cb( mut userdata: *mut libc::c_void, mut tag: *const libc::c_char, mut attr: *mut *mut libc::c_char, ) { let mut kml: *mut dc_kml_t = userdata as *mut dc_kml_t; if strcmp(tag, b"document\x00" as *const u8 as *const libc::c_char) == 0i32 { let mut addr: *const libc::c_char = dc_attr_find(attr, b"addr\x00" as *const u8 as *const libc::c_char); if !addr.is_null() { (*kml).addr = dc_strdup(addr) } } else if strcmp(tag, b"placemark\x00" as *const u8 as *const libc::c_char) == 0i32 { (*kml).tag = 0x1i32; (*kml).curr.timestamp = 0i32 as time_t; (*kml).curr.latitude = 0i32 as libc::c_double; (*kml).curr.longitude = 0.0f64; (*kml).curr.accuracy = 0.0f64 } else if strcmp(tag, b"timestamp\x00" as *const u8 as *const libc::c_char) == 0i32 && 0 != (*kml).tag & 0x1i32 { (*kml).tag = 0x1i32 | 0x2i32 } else if strcmp(tag, b"when\x00" as *const u8 as *const libc::c_char) == 0i32 && 0 != (*kml).tag & 0x2i32 { (*kml).tag = 0x1i32 | 0x2i32 | 0x4i32 } else if strcmp(tag, b"point\x00" as *const u8 as *const libc::c_char) == 0i32 && 0 != (*kml).tag & 0x1i32 { (*kml).tag = 0x1i32 | 0x8i32 } else if strcmp(tag, b"coordinates\x00" as *const u8 as *const libc::c_char) == 0i32 && 0 != (*kml).tag & 0x8i32 { (*kml).tag = 0x1i32 | 0x8i32 | 0x10i32; let mut accuracy: *const libc::c_char = dc_attr_find(attr, b"accuracy\x00" as *const u8 as *const libc::c_char); if !accuracy.is_null() { (*kml).curr.accuracy = dc_atof(accuracy) } }; } pub unsafe fn dc_kml_unref(mut kml: *mut dc_kml_t) { if kml.is_null() { return; } dc_array_unref((*kml).locations); free((*kml).addr as *mut libc::c_void); free(kml as *mut libc::c_void); } pub unsafe fn dc_job_do_DC_JOB_MAYBE_SEND_LOCATIONS(context: &dc_context_t, _job: *mut dc_job_t) { let mut stmt_chats: *mut sqlite3_stmt = 0 as *mut sqlite3_stmt; let mut stmt_locations: *mut sqlite3_stmt = 0 as *mut sqlite3_stmt; let mut now: time_t = time(0 as *mut time_t); let mut continue_streaming: libc::c_int = 1i32; dc_log_info( context, 0i32, b" ----------------- MAYBE_SEND_LOCATIONS -------------- \x00" as *const u8 as *const libc::c_char, ); stmt_chats = dc_sqlite3_prepare( context, &mut context.sql.clone().lock().unwrap(), 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; let mut locations_send_begin: time_t = sqlite3_column_int64(stmt_chats, 1i32) as time_t; let mut locations_last_sent: time_t = sqlite3_column_int64(stmt_chats, 2i32) as time_t; continue_streaming = 1i32; // be a bit tolerant as the timer may not align exactly with time(NULL) if now - locations_last_sent < (60i32 - 3i32) as libc::c_long { continue; } if stmt_locations.is_null() { stmt_locations = dc_sqlite3_prepare( context, &mut context.sql.clone().lock().unwrap(), 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); } sqlite3_bind_int(stmt_locations, 1i32, 1i32); sqlite3_bind_int64(stmt_locations, 2i32, locations_send_begin as sqlite3_int64); sqlite3_bind_int64(stmt_locations, 3i32, locations_last_sent as sqlite3_int64); // if there is no new location, there's nothing to send. // however, maybe we want to bypass this test eg. 15 minutes if sqlite3_step(stmt_locations) != 100i32 { continue; } // pending locations are attached automatically to every message, // so also to this empty text message. // DC_CMD_LOCATION is only needed to create a nicer subject. // // for optimisation and to avoid flooding the sending queue, // we could sending these messages only if we're really online. // the easiest way to determine this, is to check for an empty message queue. // (might not be 100%, however, as positions are sent combined later // and dc_set_location() is typically called periodically, this is ok) let mut msg: *mut dc_msg_t = dc_msg_new(context, 10i32); (*msg).hidden = 1i32; dc_param_set_int((*msg).param, 'S' as i32, 9i32); dc_send_msg(context, chat_id, msg); dc_msg_unref(msg); } if 0 != continue_streaming { schedule_MAYBE_SEND_LOCATIONS(context, 0x1i32); } sqlite3_finalize(stmt_chats); sqlite3_finalize(stmt_locations); } pub unsafe fn dc_job_do_DC_JOB_MAYBE_SEND_LOC_ENDED( mut context: &dc_context_t, mut job: &mut dc_job_t, ) { // this function is called when location-streaming _might_ have ended for a chat. // the function checks, if location-streaming is really ended; // if so, a device-message is added if not yet done. let mut chat_id: uint32_t = (*job).foreign_id; let mut locations_send_begin: time_t = 0i32 as time_t; let mut locations_send_until: time_t = 0i32 as time_t; let mut stmt = 0 as *mut sqlite3_stmt; let mut stock_str: *mut libc::c_char = 0 as *mut libc::c_char; stmt = dc_sqlite3_prepare( context, &mut context.sql.clone().lock().unwrap(), b"SELECT locations_send_begin, locations_send_until FROM chats WHERE id=?\x00" as *const u8 as *const libc::c_char, ); sqlite3_bind_int(stmt, 1i32, chat_id as libc::c_int); if !(sqlite3_step(stmt) != 100i32) { locations_send_begin = sqlite3_column_int64(stmt, 0i32) as time_t; locations_send_until = sqlite3_column_int64(stmt, 1i32) as time_t; sqlite3_finalize(stmt); stmt = 0 as *mut sqlite3_stmt; if !(locations_send_begin != 0i32 as libc::c_long && time(0 as *mut time_t) <= locations_send_until) { // still streaming - // may happen as several calls to dc_send_locations_to_chat() // do not un-schedule pending DC_MAYBE_SEND_LOC_ENDED jobs if !(locations_send_begin == 0i32 as libc::c_long && locations_send_until == 0i32 as libc::c_long) { // not streaming, device-message already sent stmt = dc_sqlite3_prepare( context, &mut context.sql.clone().lock().unwrap(), b"UPDATE chats SET locations_send_begin=0, locations_send_until=0 WHERE id=?\x00" as *const u8 as *const libc::c_char); sqlite3_bind_int(stmt, 1i32, chat_id as libc::c_int); sqlite3_step(stmt); stock_str = dc_stock_system_msg( context, 65i32, 0 as *const libc::c_char, 0 as *const libc::c_char, 0i32 as uint32_t, ); dc_add_device_msg(context, chat_id, stock_str); (context.cb)( context, Event::CHAT_MODIFIED, chat_id as uintptr_t, 0i32 as uintptr_t, ); } } } sqlite3_finalize(stmt); free(stock_str as *mut libc::c_void); }