account.c (6895B)
1 /* 2 This file is part of GNUnet. 3 Copyright (C) 2024 GNUnet e.V. 4 5 GNUnet is free software: you can redistribute it and/or modify it 6 under the terms of the GNU Affero General Public License as published 7 by the Free Software Foundation, either version 3 of the License, 8 or (at your option) any later version. 9 10 GNUnet is distributed in the hope that it will be useful, but 11 WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 Affero General Public License for more details. 14 15 You should have received a copy of the GNU Affero General Public License 16 along with this program. If not, see <http://www.gnu.org/licenses/>. 17 18 SPDX-License-Identifier: AGPL3.0-or-later 19 */ 20 /* 21 * @author Tobias Frisch 22 * @file account.c 23 */ 24 25 #include "account.h" 26 27 #include "contact.h" 28 #include "ui.h" 29 30 #include <gnunet/gnunet_chat_lib.h> 31 #include <gnunet/gnunet_common.h> 32 #include <string.h> 33 34 static GList *infos = NULL; 35 36 enum GNUNET_GenericReturnValue 37 account_create_info(struct GNUNET_CHAT_Account *account) 38 { 39 if ((!account) || (GNUNET_CHAT_account_get_user_pointer(account))) 40 return GNUNET_NO; 41 42 MESSENGER_AccountInfo *info = g_malloc(sizeof(MESSENGER_AccountInfo)); 43 44 info->account = account; 45 46 info->icon_file = NULL; 47 info->icon = NULL; 48 info->task = 0; 49 50 info->name_avatars = NULL; 51 52 infos = g_list_append(infos, info); 53 54 GNUNET_CHAT_account_set_user_pointer(account, info); 55 return GNUNET_YES; 56 } 57 58 static void 59 _destroy_account_info(gpointer data) 60 { 61 g_assert(data); 62 63 MESSENGER_AccountInfo *info = (MESSENGER_AccountInfo*) data; 64 65 if (info->name_avatars) 66 g_list_free(info->name_avatars); 67 68 if (info->task) 69 util_source_remove(info->task); 70 71 if (info->icon) 72 g_object_unref(info->icon); 73 74 if (info->icon_file) 75 g_object_unref(info->icon_file); 76 77 GNUNET_CHAT_account_set_user_pointer(info->account, NULL); 78 79 g_free(info); 80 } 81 82 void 83 account_destroy_info(struct GNUNET_CHAT_Account *account) 84 { 85 g_assert(account); 86 87 MESSENGER_AccountInfo* info = GNUNET_CHAT_account_get_user_pointer(account); 88 89 if (!info) 90 return; 91 92 if (infos) 93 infos = g_list_remove(infos, info); 94 95 _destroy_account_info(info); 96 } 97 98 void 99 account_cleanup_infos() 100 { 101 if (!infos) 102 return; 103 104 g_list_free_full(infos, (GDestroyNotify) _destroy_account_info); 105 106 infos = NULL; 107 } 108 109 void 110 account_add_name_avatar_to_info(const struct GNUNET_CHAT_Account *account, 111 HdyAvatar *avatar) 112 { 113 g_assert(avatar); 114 115 MESSENGER_AccountInfo *info = GNUNET_CHAT_account_get_user_pointer(account); 116 117 if (!info) 118 return; 119 120 const char *name = GNUNET_CHAT_account_get_name(account); 121 122 ui_avatar_set_text(avatar, name); 123 ui_avatar_set_icon(avatar, info->icon); 124 125 info->name_avatars = g_list_append(info->name_avatars, avatar); 126 } 127 128 void 129 account_switch_name_avatar_to_info(const struct GNUNET_CHAT_Account *account, 130 HdyAvatar *avatar) 131 { 132 g_assert(avatar); 133 134 MESSENGER_AccountInfo *info = GNUNET_CHAT_account_get_user_pointer(account); 135 136 if (!info) 137 return; 138 139 if (g_list_find(info->name_avatars, avatar)) 140 return; 141 142 GList *list = infos; 143 while (list) 144 { 145 MESSENGER_AccountInfo *other = (MESSENGER_AccountInfo*) list->data; 146 147 if (g_list_find(other->name_avatars, avatar)) 148 { 149 account_remove_name_avatar_from_info(other->account, avatar); 150 break; 151 } 152 153 list = g_list_next(list); 154 } 155 156 account_add_name_avatar_to_info(account, avatar); 157 } 158 159 void 160 account_remove_name_avatar_from_info(const struct GNUNET_CHAT_Account *account, 161 HdyAvatar *avatar) 162 { 163 g_assert(avatar); 164 165 MESSENGER_AccountInfo *info = GNUNET_CHAT_account_get_user_pointer(account); 166 167 if (!info) 168 return; 169 170 if (info->name_avatars) 171 info->name_avatars = g_list_remove(info->name_avatars, avatar); 172 } 173 174 static gboolean 175 _task_update_avatars(gpointer data) 176 { 177 g_assert(data); 178 179 MESSENGER_AccountInfo *info = (MESSENGER_AccountInfo*) data; 180 181 info->task = 0; 182 183 GList* list; 184 for (list = info->name_avatars; list; list = list->next) 185 ui_avatar_set_icon(HDY_AVATAR(list->data), info->icon); 186 187 return FALSE; 188 } 189 190 static void 191 _info_profile_downloaded(void *cls, 192 struct GNUNET_CHAT_File *file, 193 uint64_t completed, 194 uint64_t size) 195 { 196 g_assert((cls) && (file)); 197 198 struct GNUNET_CHAT_Account *account = (struct GNUNET_CHAT_Account*) cls; 199 200 MESSENGER_AccountInfo *info = GNUNET_CHAT_account_get_user_pointer(account); 201 202 if ((!info) || (completed < size)) 203 return; 204 205 const char *preview = GNUNET_CHAT_file_open_preview(file); 206 207 if (!preview) 208 return; 209 210 GFile *file_object = g_file_new_for_path(preview); 211 212 if (!file_object) 213 return; 214 215 if (!(info->icon_file)) 216 goto skip_comparison; 217 218 if (g_file_equal(info->icon_file, file_object)) 219 { 220 g_object_unref(file_object); 221 return; 222 } 223 224 g_object_unref(info->icon_file); 225 226 skip_comparison: 227 info->icon_file = file_object; 228 229 if (info->icon) 230 g_object_unref(info->icon); 231 232 info->icon = g_file_icon_new(file_object); 233 234 if (!(info->task)) 235 info->task = util_idle_add(G_SOURCE_FUNC(_task_update_avatars), info); 236 } 237 238 static enum GNUNET_GenericReturnValue 239 _account_iterate_attribute(void *cls, 240 struct GNUNET_CHAT_Account *account, 241 const char *name, 242 const char *value) 243 { 244 g_assert((cls) && (account) && (name)); 245 246 struct GNUNET_CHAT_Handle *handle = (struct GNUNET_CHAT_Handle*) cls; 247 248 MESSENGER_AccountInfo *info = GNUNET_CHAT_account_get_user_pointer(account); 249 250 if (!info) 251 return GNUNET_NO; 252 253 if ((0 != strcmp(name, GNUNET_CHAT_ATTRIBUTE_AVATAR)) || (!value)) 254 return GNUNET_YES; 255 256 struct GNUNET_CHAT_Uri *uri = GNUNET_CHAT_uri_parse(value, NULL); 257 258 if (!uri) 259 return GNUNET_YES; 260 261 struct GNUNET_CHAT_File *file = GNUNET_CHAT_request_file(handle, uri); 262 263 if (!file) 264 goto skip_file; 265 266 if (GNUNET_YES == GNUNET_CHAT_file_is_ready(file)) 267 _info_profile_downloaded( 268 info->account, 269 file, 270 GNUNET_CHAT_file_get_local_size(file), 271 GNUNET_CHAT_file_get_size(file) 272 ); 273 else if (GNUNET_YES != GNUNET_CHAT_file_is_downloading(file)) 274 GNUNET_CHAT_file_start_download( 275 file, 276 _info_profile_downloaded, 277 info->account 278 ); 279 280 skip_file: 281 GNUNET_CHAT_uri_destroy(uri); 282 return GNUNET_YES; 283 } 284 285 void 286 account_update_attributes(const struct GNUNET_CHAT_Account *account, 287 MESSENGER_Application *app) 288 { 289 g_assert(app); 290 291 MESSENGER_AccountInfo *info = GNUNET_CHAT_account_get_user_pointer(account); 292 293 if ((!info) || (!(info->account))) 294 return; 295 296 GNUNET_CHAT_account_get_attributes( 297 app->chat.messenger.handle, 298 info->account, 299 _account_iterate_attribute, 300 app->chat.messenger.handle 301 ); 302 }