diff --git a/src/dc_chat.rs b/src/dc_chat.rs index 18d0d6922..4166d7db6 100644 --- a/src/dc_chat.rs +++ b/src/dc_chat.rs @@ -1494,7 +1494,7 @@ pub unsafe fn dc_create_group_chat( let draft_txt = CString::new(context.stock_string_repl_str(StockMessage::NewGroupDraft, as_str(chat_name))) .unwrap(); - let grpid = as_str(dc_create_id()); + let grpid = dc_create_id(); if sql::execute( context, &context.sql, diff --git a/src/dc_securejoin.rs b/src/dc_securejoin.rs index 22ed7bcb5..3bf1f305b 100644 --- a/src/dc_securejoin.rs +++ b/src/dc_securejoin.rs @@ -45,12 +45,12 @@ pub unsafe fn dc_get_securejoin_qr( dc_ensure_secret_key_exists(context); invitenumber = dc_token_lookup(context, DC_TOKEN_INVITENUMBER, group_chat_id); if invitenumber.is_null() { - invitenumber = dc_create_id(); + invitenumber = to_cstring(dc_create_id()); dc_token_save(context, DC_TOKEN_INVITENUMBER, group_chat_id, invitenumber); } auth = dc_token_lookup(context, DC_TOKEN_AUTH, group_chat_id); if auth.is_null() { - auth = dc_create_id(); + auth = to_cstring(dc_create_id()); dc_token_save(context, DC_TOKEN_AUTH, group_chat_id, auth); } let self_addr = context.sql.get_config(context, "configured_addr"); diff --git a/src/dc_tools.rs b/src/dc_tools.rs index d2db0afa2..f34cdad26 100644 --- a/src/dc_tools.rs +++ b/src/dc_tools.rs @@ -720,7 +720,7 @@ pub unsafe fn dc_create_smeared_timestamps(context: &Context, count: libc::c_int } /* Message-ID tools */ -pub unsafe fn dc_create_id() -> *mut libc::c_char { +pub fn dc_create_id() -> String { /* generate an id. the generated ID should be as short and as unique as possible: - short, because it may also used as part of Message-ID headers or in QR codes - unique as two IDs generated on two devices should not be the same. However, collisions are not world-wide but only by the few contacts. @@ -738,39 +738,34 @@ pub unsafe fn dc_create_id() -> *mut libc::c_char { encode_66bits_as_base64(buf[0usize], buf[1usize], buf[2usize]) } -/* ****************************************************************************** - * generate Message-IDs - ******************************************************************************/ -unsafe fn encode_66bits_as_base64(v1: uint32_t, v2: uint32_t, fill: uint32_t) -> *mut libc::c_char { - /* encode 66 bits as a base64 string. This is useful for ID generating with short strings as - we save 5 character in each id compared to 64 bit hex encoding, for a typical group ID, these are 10 characters (grpid+msgid): - hex: 64 bit, 4 bits/character, length = 64/4 = 16 characters - base64: 64 bit, 6 bits/character, length = 64/6 = 11 characters (plus 2 additional bits) */ - let ret: *mut libc::c_char = malloc(12) as *mut libc::c_char; - assert!(!ret.is_null()); - - static mut CHARS: [libc::c_char; 65] = [ +/// Encode 66 bits as a base64 string. +/// This is useful for ID generating with short strings as we save 5 character +/// in each id compared to 64 bit hex encoding. For a typical group ID, these +/// are 10 characters (grpid+msgid): +/// hex: 64 bit, 4 bits/character, length = 64/4 = 16 characters +/// base64: 64 bit, 6 bits/character, length = 64/6 = 11 characters (plus 2 additional bits) +/// Only the lower 2 bits of `fill` are used. +fn encode_66bits_as_base64(v1: u32, v2: u32, fill: u32) -> String { + static CHARS: [u8; 65] = [ 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 45, 95, 0, ]; - *ret.offset(0isize) = CHARS[(v1 >> 26i32 & 0x3fi32 as libc::c_uint) as usize]; - *ret.offset(1isize) = CHARS[(v1 >> 20i32 & 0x3fi32 as libc::c_uint) as usize]; - *ret.offset(2isize) = CHARS[(v1 >> 14i32 & 0x3fi32 as libc::c_uint) as usize]; - *ret.offset(3isize) = CHARS[(v1 >> 8i32 & 0x3fi32 as libc::c_uint) as usize]; - *ret.offset(4isize) = CHARS[(v1 >> 2i32 & 0x3fi32 as libc::c_uint) as usize]; - *ret.offset(5isize) = CHARS - [(v1 << 4i32 & 0x30i32 as libc::c_uint | v2 >> 28i32 & 0xfi32 as libc::c_uint) as usize]; - *ret.offset(6isize) = CHARS[(v2 >> 22i32 & 0x3fi32 as libc::c_uint) as usize]; - *ret.offset(7isize) = CHARS[(v2 >> 16i32 & 0x3fi32 as libc::c_uint) as usize]; - *ret.offset(8isize) = CHARS[(v2 >> 10i32 & 0x3fi32 as libc::c_uint) as usize]; - *ret.offset(9isize) = CHARS[(v2 >> 4i32 & 0x3fi32 as libc::c_uint) as usize]; - *ret.offset(10isize) = - CHARS[(v2 << 2i32 & 0x3ci32 as libc::c_uint | fill & 0x3i32 as libc::c_uint) as usize]; - *ret.offset(11isize) = 0i32 as libc::c_char; - - ret + let ret = vec![ + CHARS[((v1 >> 26) & 0x3f) as usize], + CHARS[((v1 >> 20) & 0x3f) as usize], + CHARS[((v1 >> 14) & 0x3f) as usize], + CHARS[((v1 >> 8) & 0x3f) as usize], + CHARS[((v1 >> 2) & 0x3f) as usize], + CHARS[(((v1 << 4) & 0x30) | ((v2 >> 28) & 0x0f)) as usize], + CHARS[((v2 >> 22) & 0x3f) as usize], + CHARS[((v2 >> 16) & 0x3f) as usize], + CHARS[((v2 >> 10) & 0x3f) as usize], + CHARS[((v2 >> 4) & 0x3f) as usize], + CHARS[(((v2 << 2) & 0x3c) | (fill & 0x03)) as usize], + ]; + String::from_utf8(ret).unwrap() } pub unsafe fn dc_create_incoming_rfc724_mid( @@ -810,7 +805,7 @@ pub unsafe fn dc_create_outgoing_rfc724_mid( - the message ID should be globally unique - do not add a counter or any private data as as this may give unneeded information to the receiver */ let mut rand1: *mut libc::c_char = 0 as *mut libc::c_char; - let rand2: *mut libc::c_char = dc_create_id(); + let rand2: *mut libc::c_char = to_cstring(dc_create_id()); let ret: *mut libc::c_char; let mut at_hostname: *const libc::c_char = strchr(from_addr, '@' as i32); if at_hostname.is_null() { @@ -824,7 +819,7 @@ pub unsafe fn dc_create_outgoing_rfc724_mid( at_hostname, ) } else { - rand1 = dc_create_id(); + rand1 = to_cstring(dc_create_id()); ret = dc_mprintf( b"Mr.%s.%s%s\x00" as *const u8 as *const libc::c_char, rand1, @@ -1981,11 +1976,28 @@ mod tests { #[test] fn test_dc_create_id() { - unsafe { - let buf = dc_create_id(); - assert_eq!(strlen(buf), 11); - free(buf as *mut libc::c_void); - } + let buf = dc_create_id(); + assert_eq!(buf.len(), 11); + } + + #[test] + fn test_encode_66bits_as_base64() { + assert_eq!( + encode_66bits_as_base64(0x01234567, 0x89abcdef, 0), + "ASNFZ4mrze8" + ); + assert_eq!( + encode_66bits_as_base64(0x01234567, 0x89abcdef, 1), + "ASNFZ4mrze9" + ); + assert_eq!( + encode_66bits_as_base64(0x01234567, 0x89abcdef, 2), + "ASNFZ4mrze-" + ); + assert_eq!( + encode_66bits_as_base64(0x01234567, 0x89abcdef, 3), + "ASNFZ4mrze_" + ); } #[test]