messenger-gtk

Gtk+3 graphical user interfaces for GNUnet Messenger
Log | Files | Refs | Submodules | README | LICENSE

contact.c (9874B)


      1 /*
      2    This file is part of GNUnet.
      3    Copyright (C) 2021--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 contact.c
     23  */
     24 
     25 #include "contact.h"
     26 
     27 #include "ui.h"
     28 
     29 #include <gnunet/gnunet_chat_lib.h>
     30 #include <gnunet/gnunet_common.h>
     31 #include <string.h>
     32 
     33 enum GNUNET_GenericReturnValue
     34 contact_create_info(struct GNUNET_CHAT_Contact *contact)
     35 {
     36   if ((!contact) || (GNUNET_CHAT_contact_get_user_pointer(contact)))
     37     return GNUNET_NO;
     38 
     39   MESSENGER_ContactInfo* info = g_malloc(sizeof(MESSENGER_ContactInfo));
     40 
     41   info->last_message = NULL;
     42   info->icon_file = NULL;
     43   info->icon = NULL;
     44   info->task = 0;
     45 
     46   info->name_labels = NULL;
     47   info->name_avatars = NULL;
     48   info->visible_widgets = NULL;
     49 
     50   GNUNET_CHAT_contact_set_user_pointer(contact, info);
     51   return GNUNET_YES;
     52 }
     53 
     54 void
     55 contact_destroy_info(struct GNUNET_CHAT_Contact *contact)
     56 {
     57   g_assert(contact);
     58 
     59   MESSENGER_ContactInfo* info = GNUNET_CHAT_contact_get_user_pointer(contact);
     60 
     61   if (!info)
     62     return;
     63 
     64   if (info->name_labels)
     65     g_list_free(info->name_labels);
     66 
     67   if (info->name_avatars)
     68     g_list_free(info->name_avatars);
     69 
     70   if (info->visible_widgets)
     71     g_list_free(info->visible_widgets);
     72 
     73   if (info->task)
     74     util_source_remove(info->task);
     75 
     76   if (info->icon)
     77     g_object_unref(info->icon);
     78 
     79   if (info->icon_file)
     80     g_object_unref(info->icon_file);
     81 
     82   g_free(info);
     83 
     84   GNUNET_CHAT_contact_set_user_pointer(contact, NULL);
     85 }
     86 
     87 void
     88 contact_set_last_message_to_info(const struct GNUNET_CHAT_Contact *contact,
     89 				                         void *message)
     90 {
     91   MESSENGER_ContactInfo* info = GNUNET_CHAT_contact_get_user_pointer(contact);
     92 
     93   if (!info)
     94     return;
     95 
     96   info->last_message = message;
     97 }
     98 
     99 void*
    100 contact_get_last_message_from_info(const struct GNUNET_CHAT_Contact *contact)
    101 {
    102   MESSENGER_ContactInfo* info = GNUNET_CHAT_contact_get_user_pointer(contact);
    103 
    104   if (!info)
    105     return NULL;
    106 
    107   return info->last_message;
    108 }
    109 
    110 void
    111 contact_add_name_label_to_info(const struct GNUNET_CHAT_Contact *contact,
    112 			                         GtkLabel *label)
    113 {
    114   g_assert(label);
    115 
    116   MESSENGER_ContactInfo* info = GNUNET_CHAT_contact_get_user_pointer(contact);
    117 
    118   if (!info)
    119     return;
    120 
    121   const char *name = GNUNET_CHAT_contact_get_name(contact);
    122 
    123   ui_label_set_text(label, name);
    124 
    125   info->name_labels = g_list_append(info->name_labels, label);
    126 }
    127 
    128 void
    129 contact_remove_name_label_from_info(const struct GNUNET_CHAT_Contact *contact,
    130 			                              GtkLabel *label)
    131 {
    132   g_assert(label);
    133 
    134   MESSENGER_ContactInfo* info = GNUNET_CHAT_contact_get_user_pointer(contact);
    135 
    136   if (!info)
    137     return;
    138 
    139   if (info->name_labels)
    140     info->name_labels = g_list_remove(info->name_labels, label);
    141 }
    142 
    143 void
    144 contact_add_name_avatar_to_info(const struct GNUNET_CHAT_Contact *contact,
    145 			                          HdyAvatar *avatar)
    146 {
    147   g_assert(avatar);
    148 
    149   MESSENGER_ContactInfo* info = GNUNET_CHAT_contact_get_user_pointer(contact);
    150 
    151   if (!info)
    152     return;
    153 
    154   const char *name = GNUNET_CHAT_contact_get_name(contact);
    155 
    156   ui_avatar_set_text(avatar, name);
    157   ui_avatar_set_icon(avatar, info->icon);
    158 
    159   info->name_avatars = g_list_append(info->name_avatars, avatar);
    160 }
    161 
    162 void
    163 contact_remove_name_avatar_from_info(const struct GNUNET_CHAT_Contact *contact,
    164 			                               HdyAvatar *avatar)
    165 {
    166   g_assert(avatar);
    167 
    168   MESSENGER_ContactInfo* info = GNUNET_CHAT_contact_get_user_pointer(contact);
    169 
    170   if (!info)
    171     return;
    172 
    173   if (info->name_avatars)
    174     info->name_avatars = g_list_remove(info->name_avatars, avatar);
    175 }
    176 
    177 void
    178 contact_add_visible_widget_to_info(const struct GNUNET_CHAT_Contact *contact,
    179                                    GtkWidget *widget)
    180 {
    181   g_assert(widget);
    182 
    183   MESSENGER_ContactInfo* info = GNUNET_CHAT_contact_get_user_pointer(contact);
    184 
    185   if (!info)
    186     return;
    187 
    188   gboolean visible = (GNUNET_YES != GNUNET_CHAT_contact_is_blocked(contact));
    189 
    190   gtk_widget_set_visible(widget, visible);
    191 
    192   info->visible_widgets = g_list_append(info->visible_widgets, widget);
    193 }
    194 
    195 void
    196 contact_remove_visible_widget_to_info(const struct GNUNET_CHAT_Contact *contact,
    197                                       GtkWidget *widget)
    198 {
    199   g_assert(widget);
    200 
    201   MESSENGER_ContactInfo* info = GNUNET_CHAT_contact_get_user_pointer(contact);
    202 
    203   if (!info)
    204     return;
    205   
    206   if (info->visible_widgets)
    207     info->visible_widgets = g_list_remove(info->visible_widgets, widget);
    208 }
    209 
    210 void
    211 contact_update_info(const struct GNUNET_CHAT_Contact *contact)
    212 {
    213   MESSENGER_ContactInfo* info = GNUNET_CHAT_contact_get_user_pointer(contact);
    214 
    215   if (!info)
    216     return;
    217 
    218   GList* list;
    219   const char *name = GNUNET_CHAT_contact_get_name(contact);
    220 
    221   gboolean visible = (GNUNET_YES != GNUNET_CHAT_contact_is_blocked(contact));
    222 
    223   for (list = info->name_labels; list; list = list->next)
    224     ui_label_set_text(GTK_LABEL(list->data), name);
    225 
    226   for (list = info->name_avatars; list; list = list->next)
    227     ui_avatar_set_text(HDY_AVATAR(list->data), name);
    228 
    229   for (list = info->name_avatars; list; list = list->next)
    230     ui_avatar_set_icon(HDY_AVATAR(list->data), info->icon);
    231 
    232   for (list = info->visible_widgets; list; list = list->next)
    233     gtk_widget_set_visible(GTK_WIDGET(list->data), visible);
    234 }
    235 
    236 static gboolean
    237 _task_update_avatars(gpointer data)
    238 {
    239   g_assert(data);
    240 
    241   MESSENGER_ContactInfo *info = (MESSENGER_ContactInfo*) data;
    242 
    243   info->task = 0;
    244 
    245   GList* list;
    246   for (list = info->name_avatars; list; list = list->next)
    247     ui_avatar_set_icon(HDY_AVATAR(list->data), info->icon);
    248 
    249   return FALSE;
    250 }
    251 
    252 static void
    253 _info_profile_downloaded(void *cls,
    254                          struct GNUNET_CHAT_File *file,
    255                          uint64_t completed,
    256                          uint64_t size)
    257 {
    258   g_assert((cls) && (file));
    259 
    260   MESSENGER_ContactInfo* info = (MESSENGER_ContactInfo*) cls;
    261 
    262   if (completed < size)
    263     return;
    264 
    265   const char *preview = GNUNET_CHAT_file_open_preview(file);
    266 
    267   if (!preview)
    268     return;
    269 
    270   GFile *file_object = g_file_new_for_path(preview);
    271 
    272   if (!file_object)
    273     return;
    274 
    275   if (!(info->icon_file))
    276     goto skip_comparison;
    277 
    278   if (g_file_equal(info->icon_file, file_object))
    279   {
    280     g_object_unref(file_object);
    281     return;
    282   }
    283 
    284   g_object_unref(info->icon_file);
    285 
    286 skip_comparison:
    287   info->icon_file = file_object;
    288 
    289   if (info->icon)
    290     g_object_unref(info->icon);
    291 
    292   info->icon = g_file_icon_new(file_object);
    293 
    294   if (!(info->task))
    295     info->task = util_idle_add(G_SOURCE_FUNC(_task_update_avatars), info);
    296 }
    297 
    298 static enum GNUNET_GenericReturnValue
    299 _info_iterate_attribute(MESSENGER_ContactInfo* info,
    300                         struct GNUNET_CHAT_Handle *handle,
    301                         struct GNUNET_CHAT_Contact *contact,
    302                         const char *name,
    303                         const char *value)
    304 {
    305   g_assert((info) && (handle) && (contact) && (name));
    306 
    307   if ((0 != strcmp(name, GNUNET_CHAT_ATTRIBUTE_AVATAR)) || (!value))
    308     return GNUNET_YES;
    309 
    310   struct GNUNET_CHAT_Uri *uri = GNUNET_CHAT_uri_parse(value, NULL);
    311 
    312   if (!uri)
    313     return GNUNET_YES;
    314 
    315   struct GNUNET_CHAT_File *file = GNUNET_CHAT_request_file(handle, uri);
    316 
    317   if (!file)
    318     goto skip_file;
    319 
    320   if (GNUNET_YES == GNUNET_CHAT_file_is_ready(file))
    321     _info_profile_downloaded(
    322       info,
    323       file,
    324       GNUNET_CHAT_file_get_local_size(file),
    325       GNUNET_CHAT_file_get_size(file)
    326     );
    327   else if (GNUNET_YES != GNUNET_CHAT_file_is_downloading(file))
    328     GNUNET_CHAT_file_start_download(
    329       file,
    330       _info_profile_downloaded,
    331       info
    332     );
    333 
    334 skip_file:
    335   GNUNET_CHAT_uri_destroy(uri);
    336   return GNUNET_YES;
    337 }
    338 
    339 static enum GNUNET_GenericReturnValue
    340 _handle_iterate_attribute(void *cls,
    341                           struct GNUNET_CHAT_Handle *handle,
    342                           const char *name,
    343                           const char *value)
    344 {
    345   g_assert((cls) && (handle) && (name));
    346 
    347   struct GNUNET_CHAT_Contact *contact = (struct GNUNET_CHAT_Contact*) cls;
    348 
    349   MESSENGER_ContactInfo* info = GNUNET_CHAT_contact_get_user_pointer(contact);
    350 
    351   if (!info)
    352     return GNUNET_NO;
    353 
    354   return _info_iterate_attribute(
    355     info,
    356     handle,
    357     contact,
    358     name,
    359     value
    360   );
    361 }
    362 
    363 static enum GNUNET_GenericReturnValue
    364 _contact_iterate_attribute(void *cls,
    365                            struct GNUNET_CHAT_Contact *contact,
    366                            const char *name,
    367                            const char *value)
    368 {
    369   g_assert((cls) && (contact) && (name));
    370 
    371   struct GNUNET_CHAT_Handle *handle = (struct GNUNET_CHAT_Handle*) cls;
    372 
    373   MESSENGER_ContactInfo* info = GNUNET_CHAT_contact_get_user_pointer(contact);
    374 
    375   if (!info)
    376     return GNUNET_NO;
    377 
    378   return _info_iterate_attribute(
    379     info,
    380     handle,
    381     contact,
    382     name,
    383     value
    384   );
    385 }
    386 
    387 void
    388 contact_update_attributes(struct GNUNET_CHAT_Contact *contact,
    389                           MESSENGER_Application *app)
    390 {
    391   g_assert(app);
    392 
    393   MESSENGER_ContactInfo* info = GNUNET_CHAT_contact_get_user_pointer(contact);
    394 
    395   if (!info)
    396     return;
    397 
    398   if (GNUNET_YES == GNUNET_CHAT_contact_is_owned(contact))
    399     GNUNET_CHAT_get_attributes(
    400       app->chat.messenger.handle,
    401       _handle_iterate_attribute,
    402       contact
    403     );
    404   else
    405     GNUNET_CHAT_contact_get_attributes(
    406       contact,
    407       _contact_iterate_attribute,
    408       app->chat.messenger.handle
    409     );
    410 }