@@ -28,16 +28,24 @@ void UserProfile::set_name(std::string_view new_name) {
2828 if (new_name.size () > contact_info::MAX_NAME_LENGTH)
2929 throw std::invalid_argument{" Invalid profile name: exceeds maximum length" };
3030 set_nonempty_str (data[" n" ], new_name);
31+
32+ const auto target_timestamp = (data[" t" ].integer_or (0 ) >= data[" T" ].integer_or (0 ) ? " t" : " T" );
33+ data[target_timestamp] = ts_now ();
3134}
3235void UserProfile::set_name_truncated (std::string new_name) {
3336 set_name (utf8_truncate (std::move (new_name), contact_info::MAX_NAME_LENGTH));
3437}
3538
3639profile_pic UserProfile::get_profile_pic () const {
3740 profile_pic pic{};
38- if (auto * url = data[" p" ].string (); url && !url->empty ())
41+
42+ const bool use_primary_keys = (data[" t" ].integer_or (0 ) >= data[" T" ].integer_or (0 ));
43+ const auto url_key = (use_primary_keys ? " p" : " P" );
44+ const auto key_key = (use_primary_keys ? " q" : " Q" );
45+
46+ if (auto * url = data[url_key].string (); url && !url->empty ())
3947 pic.url = *url;
40- if (auto * key = data[" q " ].string (); key && key->size () == 32 )
48+ if (auto * key = data[key_key ].string (); key && key->size () == 32 )
4149 pic.key .assign (
4250 reinterpret_cast <const unsigned char *>(key->data ()),
4351 reinterpret_cast <const unsigned char *>(key->data ()) + 32 );
@@ -46,12 +54,28 @@ profile_pic UserProfile::get_profile_pic() const {
4654
4755void UserProfile::set_profile_pic (std::string_view url, std::span<const unsigned char > key) {
4856 set_pair_if (!url.empty () && key.size () == 32 , data[" p" ], url, data[" q" ], key);
57+
58+ // If the profile was removed then we should remove the "reupload" version as well
59+ if (url.empty () || key.size () != 32 )
60+ set_reupload_profile_pic ({});
61+
62+ data[" t" ] = ts_now ();
4963}
5064
5165void UserProfile::set_profile_pic (profile_pic pic) {
5266 set_profile_pic (pic.url , pic.key );
5367}
5468
69+ void UserProfile::set_reupload_profile_pic (
70+ std::string_view url, std::span<const unsigned char > key) {
71+ set_pair_if (!url.empty () && key.size () == 32 , data[" P" ], url, data[" Q" ], key);
72+ data[" T" ] = ts_now ();
73+ }
74+
75+ void UserProfile::set_reupload_profile_pic (profile_pic pic) {
76+ set_reupload_profile_pic (pic.url , pic.key );
77+ }
78+
5579void UserProfile::set_nts_priority (int priority) {
5680 set_nonzero_int (data[" +" ], priority);
5781}
@@ -75,6 +99,9 @@ void UserProfile::set_blinded_msgreqs(std::optional<bool> value) {
7599 data[" M" ].erase ();
76100 else
77101 data[" M" ] = static_cast <int >(*value);
102+
103+ const auto target_timestamp = (data[" t" ].integer_or (0 ) >= data[" T" ].integer_or (0 ) ? " t" : " T" );
104+ data[target_timestamp] = ts_now ();
78105}
79106
80107std::optional<bool > UserProfile::get_blinded_msgreqs () const {
@@ -83,6 +110,15 @@ std::optional<bool> UserProfile::get_blinded_msgreqs() const {
83110 return std::nullopt ;
84111}
85112
113+ std::chrono::sys_seconds UserProfile::get_profile_updated () const {
114+ if (auto t = data[" t" ].sys_seconds ()) {
115+ if (auto T = data[" T" ].sys_seconds (); T && *T > *t)
116+ return *T;
117+ return *t;
118+ }
119+ return std::chrono::sys_seconds{};
120+ }
121+
86122extern " C" {
87123
88124using namespace session ;
@@ -141,6 +177,21 @@ LIBSESSION_C_API int user_profile_set_pic(config_object* conf, user_profile_pic
141177 static_cast <int >(SESSION_ERR_BAD_VALUE));
142178}
143179
180+ LIBSESSION_C_API int user_profile_set_reupload_pic (config_object* conf, user_profile_pic pic) {
181+ std::string_view url{pic.url };
182+ std::span<const unsigned char > key;
183+ if (!url.empty ())
184+ key = {pic.key , 32 };
185+
186+ return wrap_exceptions (
187+ conf,
188+ [&] {
189+ unbox<UserProfile>(conf)->set_reupload_profile_pic (url, key);
190+ return 0 ;
191+ },
192+ static_cast <int >(SESSION_ERR_BAD_VALUE));
193+ }
194+
144195LIBSESSION_C_API int user_profile_get_nts_priority (const config_object* conf) {
145196 return unbox<UserProfile>(conf)->get_nts_priority ();
146197}
@@ -170,4 +221,8 @@ LIBSESSION_C_API void user_profile_set_blinded_msgreqs(config_object* conf, int
170221 unbox<UserProfile>(conf)->set_blinded_msgreqs (std::move (val));
171222}
172223
173- } // extern "C"
224+ LIBSESSION_C_API int64_t user_profile_get_profile_updated (config_object* conf) {
225+ return unbox<UserProfile>(conf)->get_profile_updated ().time_since_epoch ().count ();
226+ }
227+
228+ } // extern "C"
0 commit comments