libgnunetchat

library for GNUnet Messenger
Log | Files | Refs | README | LICENSE

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 }