gnunet_chat_util.c (7470B)
1 /* 2 This file is part of GNUnet. 3 Copyright (C) 2021--2024, 2026 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 gnunet_chat_util.c 23 */ 24 25 #include "gnunet_chat_util.h" 26 27 #include <gnunet/gnunet_common.h> 28 #include <gnunet/gnunet_messenger_service.h> 29 #include <gnunet/gnunet_util_lib.h> 30 31 static const char label_prefix_of_contact [] = "contact"; 32 static const char label_prefix_of_group [] = "group"; 33 34 static const char identity_prefix_of_lobby [] = "_gnunet_chat_lobby"; 35 36 void 37 util_shorthash_from_member (const struct GNUNET_MESSENGER_Contact *member, 38 struct GNUNET_ShortHashCode *shorthash) 39 { 40 GNUNET_assert(shorthash); 41 42 const size_t id = GNUNET_MESSENGER_contact_get_id(member); 43 44 memset(shorthash, 0, sizeof(*shorthash)); 45 GNUNET_memcpy( 46 shorthash, 47 &id, 48 sizeof(id) < sizeof(*shorthash) ? sizeof(id) : sizeof(*shorthash) 49 ); 50 } 51 52 void 53 util_shorthash_from_discourse_id (const struct GNUNET_CHAT_DiscourseId *id, 54 struct GNUNET_ShortHashCode *shorthash) 55 { 56 GNUNET_assert(shorthash); 57 58 memset(shorthash, 0, sizeof(*shorthash)); 59 GNUNET_memcpy( 60 shorthash, 61 id, 62 sizeof(*id) < sizeof(*shorthash) ? sizeof(*id) : sizeof(*shorthash) 63 ); 64 } 65 66 void 67 util_discourse_id_from_shorthash (const struct GNUNET_ShortHashCode *shorthash, 68 struct GNUNET_CHAT_DiscourseId *id) 69 { 70 GNUNET_assert(id); 71 72 memset(id, 0, sizeof(*id)); 73 GNUNET_memcpy( 74 id, 75 shorthash, 76 sizeof(*id) < sizeof(*shorthash) ? sizeof(*id) : sizeof(*shorthash) 77 ); 78 } 79 80 void 81 util_set_name_field (const char *name, 82 char **field) 83 { 84 GNUNET_assert(field); 85 86 if (*field) 87 GNUNET_free(*field); 88 89 if (name) 90 *field = GNUNET_strdup(name); 91 else 92 *field = NULL; 93 } 94 95 enum GNUNET_GenericReturnValue 96 util_hash_file (const char *filename, 97 struct GNUNET_HashCode *hash) 98 { 99 GNUNET_assert((filename) && (hash)); 100 101 uint64_t size; 102 103 if (GNUNET_OK != GNUNET_DISK_file_size(filename, &size, GNUNET_NO, GNUNET_YES)) 104 return GNUNET_SYSERR; 105 106 struct GNUNET_DISK_FileHandle *file = GNUNET_DISK_file_open( 107 filename, GNUNET_DISK_OPEN_READ, GNUNET_DISK_PERM_USER_READ 108 ); 109 110 if (!file) 111 return GNUNET_SYSERR; 112 113 struct GNUNET_DISK_MapHandle *mapping; 114 const void* data; 115 116 if (size > 0) 117 { 118 data = GNUNET_DISK_file_map( 119 file, &mapping, GNUNET_DISK_MAP_TYPE_READ, size 120 ); 121 122 if ((!data) || (!mapping)) 123 { 124 GNUNET_DISK_file_close(file); 125 return GNUNET_SYSERR; 126 } 127 } 128 else 129 { 130 mapping = NULL; 131 data = NULL; 132 } 133 134 GNUNET_CRYPTO_hash(data, size, hash); 135 136 if (mapping) 137 GNUNET_DISK_file_unmap(mapping); 138 139 GNUNET_DISK_file_close(file); 140 return GNUNET_OK; 141 } 142 143 int 144 util_get_dirname (const char *directory, 145 const char *subdir, 146 char **filename) 147 { 148 GNUNET_assert( 149 (filename) && 150 (directory) && 151 (subdir) 152 ); 153 154 return GNUNET_asprintf ( 155 filename, 156 "%s/%s", 157 directory, 158 subdir 159 ); 160 } 161 162 int 163 util_get_filename (const char *directory, 164 const char *subdir, 165 const struct GNUNET_HashCode *hash, 166 char **filename) 167 { 168 GNUNET_assert( 169 (filename) && 170 (directory) && 171 (subdir) && 172 (hash) 173 ); 174 175 char* dirname; 176 util_get_dirname(directory, subdir, &dirname); 177 178 int result = GNUNET_asprintf ( 179 filename, 180 "%s/%s", 181 dirname, 182 GNUNET_h2s_full(hash) 183 ); 184 185 GNUNET_free(dirname); 186 return result; 187 } 188 189 char* 190 util_get_lower(const char *name) 191 { 192 GNUNET_assert(name); 193 194 char *lower = GNUNET_STRINGS_utf8_tolower(name); 195 if (lower == NULL) 196 return GNUNET_strdup(name); 197 198 return lower; 199 } 200 201 int 202 util_get_context_label (enum GNUNET_CHAT_ContextType type, 203 const struct GNUNET_HashCode *hash, 204 char **label) 205 { 206 GNUNET_assert((hash) && (label)); 207 208 const char *type_string = "chat"; 209 210 switch (type) 211 { 212 case GNUNET_CHAT_CONTEXT_TYPE_CONTACT: 213 type_string = "contact"; 214 break; 215 case GNUNET_CHAT_CONTEXT_TYPE_GROUP: 216 type_string = "group"; 217 break; 218 default: 219 break; 220 } 221 222 char *low = util_get_lower(GNUNET_h2s(hash)); 223 224 int result = GNUNET_asprintf ( 225 label, 226 "%s_%s", 227 type_string, 228 low 229 ); 230 231 GNUNET_free(low); 232 return result; 233 } 234 235 enum GNUNET_CHAT_ContextType 236 util_get_context_label_type (const char *label, 237 const struct GNUNET_HashCode *hash) 238 { 239 GNUNET_assert((hash) && (label)); 240 241 enum GNUNET_CHAT_ContextType type = GNUNET_CHAT_CONTEXT_TYPE_UNKNOWN; 242 243 char *low = util_get_lower(GNUNET_h2s(hash)); 244 245 const char *sub = strstr(label, low); 246 if ((!sub) || (sub == label) || (sub[-1] != '_')) 247 goto cleanup; 248 249 const size_t len = (size_t) (sub - label - 1); 250 251 if (0 == strncmp(label, label_prefix_of_group, len)) 252 type = GNUNET_CHAT_CONTEXT_TYPE_GROUP; 253 else if (0 == strncmp(label, label_prefix_of_contact, len)) 254 type = GNUNET_CHAT_CONTEXT_TYPE_CONTACT; 255 256 cleanup: 257 GNUNET_free(low); 258 return type; 259 } 260 261 int 262 util_lobby_name (const struct GNUNET_HashCode *hash, 263 char **name) 264 { 265 GNUNET_assert((hash) && (name)); 266 267 char *low = util_get_lower(GNUNET_h2s(hash)); 268 269 int result = GNUNET_asprintf ( 270 name, 271 "%s_%s", 272 identity_prefix_of_lobby, 273 low 274 ); 275 276 GNUNET_free(low); 277 return result; 278 } 279 280 enum GNUNET_GenericReturnValue 281 util_is_lobby_name(const char *name) 282 { 283 GNUNET_assert(name); 284 285 const char *sub = strstr(name, identity_prefix_of_lobby); 286 if ((!sub) || (sub != name)) 287 return GNUNET_NO; 288 289 const size_t len = strlen(identity_prefix_of_lobby); 290 291 if (name[len] != '_') 292 return GNUNET_NO; 293 else 294 return GNUNET_YES; 295 } 296 297 enum GNUNET_CHAT_MessageKind 298 util_message_kind_from_kind (enum GNUNET_MESSENGER_MessageKind kind) 299 { 300 switch (kind) 301 { 302 case GNUNET_MESSENGER_KIND_JOIN: 303 return GNUNET_CHAT_KIND_JOIN; 304 case GNUNET_MESSENGER_KIND_LEAVE: 305 return GNUNET_CHAT_KIND_LEAVE; 306 case GNUNET_MESSENGER_KIND_NAME: 307 case GNUNET_MESSENGER_KIND_KEY: 308 case GNUNET_MESSENGER_KIND_ID: 309 return GNUNET_CHAT_KIND_CONTACT; 310 case GNUNET_MESSENGER_KIND_INVITE: 311 return GNUNET_CHAT_KIND_INVITATION; 312 case GNUNET_MESSENGER_KIND_TEXT: 313 return GNUNET_CHAT_KIND_TEXT; 314 case GNUNET_MESSENGER_KIND_FILE: 315 return GNUNET_CHAT_KIND_FILE; 316 case GNUNET_MESSENGER_KIND_DELETION: 317 return GNUNET_CHAT_KIND_DELETION; 318 case GNUNET_MESSENGER_KIND_TICKET: 319 return GNUNET_CHAT_KIND_SHARED_ATTRIBUTES; 320 case GNUNET_MESSENGER_KIND_TAG: 321 return GNUNET_CHAT_KIND_TAG; 322 case GNUNET_MESSENGER_KIND_SUBSCRIBTION: 323 return GNUNET_CHAT_KIND_DISCOURSE; 324 case GNUNET_MESSENGER_KIND_TALK: 325 return GNUNET_CHAT_KIND_DATA; 326 default: 327 return GNUNET_CHAT_KIND_UNKNOWN; 328 } 329 }