LCOV - code coverage report
Current view: top level - src/plugins/connectivity_report - valent-telephony.c (source / functions) Coverage Total Hit
Test: Code Coverage Lines: 87.6 % 161 141
Test Date: 2025-06-08 16:39:35 Functions: 100.0 % 17 17
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 51.2 % 123 63

             Branch data     Line data    Source code
       1                 :             : // SPDX-License-Identifier: GPL-3.0-or-later
       2                 :             : // SPDX-FileCopyrightText: Andy Holmes <andrew.g.r.holmes@gmail.com>
       3                 :             : 
       4                 :             : #define G_LOG_DOMAIN "valent-telephony"
       5                 :             : 
       6                 :             : #include "config.h"
       7                 :             : 
       8                 :             : #include <math.h>
       9                 :             : 
      10                 :             : #include <gio/gio.h>
      11                 :             : #include <json-glib/json-glib.h>
      12                 :             : #include <valent.h>
      13                 :             : 
      14                 :             : #include "valent-telephony.h"
      15                 :             : 
      16                 :             : 
      17                 :             : /**
      18                 :             :  * ValentTelephony:
      19                 :             :  *
      20                 :             :  * A class for controlling pointer and keyboard devices.
      21                 :             :  *
      22                 :             :  * `ValentTelephony` is an abstraction of telephony support, intended for use by
      23                 :             :  * [class@Valent.DevicePlugin] implementations.
      24                 :             :  */
      25                 :             : 
      26                 :             : struct _ValentTelephony
      27                 :             : {
      28                 :             :   ValentObject        parent_instance;
      29                 :             : 
      30                 :             :   GDBusObjectManager *manager;
      31                 :             :   GDBusProxy         *modem;
      32                 :             :   GHashTable         *modems;
      33                 :             : };
      34                 :             : 
      35   [ +  +  +  - ]:          22 : G_DEFINE_FINAL_TYPE (ValentTelephony, valent_telephony, VALENT_TYPE_OBJECT)
      36                 :             : 
      37                 :             : enum {
      38                 :             :   CHANGED,
      39                 :             :   N_SIGNALS
      40                 :             : };
      41                 :             : 
      42                 :             : static guint signals[N_SIGNALS] = { 0, };
      43                 :             : 
      44                 :             : 
      45                 :             : static ValentTelephony *default_telephony = NULL;
      46                 :             : 
      47                 :             : /*
      48                 :             :  * ModemManager-enums.h
      49                 :             :  */
      50                 :             : typedef enum { /*< underscore_name=mm_modem_access_technology >*/
      51                 :             :   MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN     = 0,
      52                 :             :   MM_MODEM_ACCESS_TECHNOLOGY_POTS        = 1 << 0,
      53                 :             :   MM_MODEM_ACCESS_TECHNOLOGY_GSM         = 1 << 1,
      54                 :             :   MM_MODEM_ACCESS_TECHNOLOGY_GSM_COMPACT = 1 << 2,
      55                 :             :   MM_MODEM_ACCESS_TECHNOLOGY_GPRS        = 1 << 3,
      56                 :             :   MM_MODEM_ACCESS_TECHNOLOGY_EDGE        = 1 << 4,
      57                 :             :   MM_MODEM_ACCESS_TECHNOLOGY_UMTS        = 1 << 5,
      58                 :             :   MM_MODEM_ACCESS_TECHNOLOGY_HSDPA       = 1 << 6,
      59                 :             :   MM_MODEM_ACCESS_TECHNOLOGY_HSUPA       = 1 << 7,
      60                 :             :   MM_MODEM_ACCESS_TECHNOLOGY_HSPA        = 1 << 8,
      61                 :             :   MM_MODEM_ACCESS_TECHNOLOGY_HSPA_PLUS   = 1 << 9,
      62                 :             :   MM_MODEM_ACCESS_TECHNOLOGY_1XRTT       = 1 << 10,
      63                 :             :   MM_MODEM_ACCESS_TECHNOLOGY_EVDO0       = 1 << 11,
      64                 :             :   MM_MODEM_ACCESS_TECHNOLOGY_EVDOA       = 1 << 12,
      65                 :             :   MM_MODEM_ACCESS_TECHNOLOGY_EVDOB       = 1 << 13,
      66                 :             :   MM_MODEM_ACCESS_TECHNOLOGY_LTE         = 1 << 14,
      67                 :             :   MM_MODEM_ACCESS_TECHNOLOGY_5GNR        = 1 << 15,
      68                 :             :   MM_MODEM_ACCESS_TECHNOLOGY_ANY         = 0xFFFFFFFF,
      69                 :             : } ValentModemAccessTechnology;
      70                 :             : 
      71                 :             : typedef enum { /*< underscore_name=mm_modem_state >*/
      72                 :             :   MM_MODEM_STATE_FAILED        = -1,
      73                 :             :   MM_MODEM_STATE_UNKNOWN       = 0,
      74                 :             :   MM_MODEM_STATE_INITIALIZING  = 1,
      75                 :             :   MM_MODEM_STATE_LOCKED        = 2,
      76                 :             :   MM_MODEM_STATE_DISABLED      = 3,
      77                 :             :   MM_MODEM_STATE_DISABLING     = 4,
      78                 :             :   MM_MODEM_STATE_ENABLING      = 5,
      79                 :             :   MM_MODEM_STATE_ENABLED       = 6,
      80                 :             :   MM_MODEM_STATE_SEARCHING     = 7,
      81                 :             :   MM_MODEM_STATE_REGISTERED    = 8,
      82                 :             :   MM_MODEM_STATE_DISCONNECTING = 9,
      83                 :             :   MM_MODEM_STATE_CONNECTING    = 10,
      84                 :             :   MM_MODEM_STATE_CONNECTED     = 11,
      85                 :             : } ValentModemState;
      86                 :             : 
      87                 :             : 
      88                 :             : static inline const char *
      89                 :           6 : get_telephony_type_string (unsigned int flags)
      90                 :             : {
      91   [ -  -  -  -  :           6 :   switch (flags)
             -  -  +  -  
                      + ]
      92                 :             :     {
      93                 :             :     case MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN:
      94                 :             :     case MM_MODEM_ACCESS_TECHNOLOGY_POTS:
      95                 :             :       return "Unknown";
      96                 :             : 
      97                 :           0 :     case MM_MODEM_ACCESS_TECHNOLOGY_GSM:
      98                 :             :     case MM_MODEM_ACCESS_TECHNOLOGY_GSM_COMPACT:
      99                 :           0 :       return "GSM";
     100                 :             : 
     101                 :           0 :     case MM_MODEM_ACCESS_TECHNOLOGY_GPRS:
     102                 :           0 :       return "GPRS";
     103                 :             : 
     104                 :           0 :     case MM_MODEM_ACCESS_TECHNOLOGY_EDGE:
     105                 :           0 :       return "EDGE";
     106                 :             : 
     107                 :           0 :     case MM_MODEM_ACCESS_TECHNOLOGY_UMTS:
     108                 :           0 :       return "UMTS";
     109                 :             : 
     110                 :           0 :     case MM_MODEM_ACCESS_TECHNOLOGY_HSDPA:
     111                 :             :     case MM_MODEM_ACCESS_TECHNOLOGY_HSUPA:
     112                 :             :     case MM_MODEM_ACCESS_TECHNOLOGY_HSUPA | MM_MODEM_ACCESS_TECHNOLOGY_HSDPA:
     113                 :             :     case MM_MODEM_ACCESS_TECHNOLOGY_HSPA:
     114                 :             :     case MM_MODEM_ACCESS_TECHNOLOGY_HSPA_PLUS:
     115                 :           0 :       return "HSPA";
     116                 :             : 
     117                 :           0 :     case MM_MODEM_ACCESS_TECHNOLOGY_1XRTT:
     118                 :             :     case MM_MODEM_ACCESS_TECHNOLOGY_EVDO0:
     119                 :             :     case MM_MODEM_ACCESS_TECHNOLOGY_EVDOA:
     120                 :             :     case MM_MODEM_ACCESS_TECHNOLOGY_EVDOB:
     121                 :           0 :       return "CDMA2000";
     122                 :             : 
     123                 :           2 :     case MM_MODEM_ACCESS_TECHNOLOGY_LTE:
     124                 :           2 :       return "LTE";
     125                 :             : 
     126                 :           0 :     case MM_MODEM_ACCESS_TECHNOLOGY_5GNR:
     127                 :           0 :       return "5G";
     128                 :             : 
     129                 :             :     case MM_MODEM_ACCESS_TECHNOLOGY_ANY:
     130                 :             :       return "Unknown";
     131                 :             : 
     132                 :             :     default:
     133                 :             :       return "Unknown";
     134                 :             :     }
     135                 :             : }
     136                 :             : 
     137                 :             : static void
     138                 :           4 : on_properties_changed (GDBusProxy      *proxy,
     139                 :             :                        GVariant        *changed_properties,
     140                 :             :                        GStrv            invalidated,
     141                 :             :                        ValentTelephony *self)
     142                 :             : {
     143                 :           4 :   GVariantIter iter;
     144                 :           4 :   const char *property;
     145                 :           4 :   GVariant *value;
     146                 :           4 :   gboolean changed = FALSE;
     147                 :             : 
     148                 :           4 :   g_variant_iter_init (&iter, changed_properties);
     149                 :             : 
     150         [ +  + ]:          44 :   while (g_variant_iter_loop (&iter, "{sv}", &property, &value))
     151                 :             :     {
     152         [ +  + ]:          40 :       if (g_str_equal (property, "AccessTechnologies"))
     153                 :             :         changed = TRUE;
     154         [ +  + ]:          36 :       else if (g_str_equal (property, "SignalQuality"))
     155                 :             :         changed = TRUE;
     156         [ +  + ]:          32 :       else if (g_str_equal (property, "State"))
     157                 :          12 :         changed = TRUE;
     158                 :             :     }
     159                 :             : 
     160         [ +  - ]:           4 :   if (changed)
     161                 :           4 :     g_signal_emit (G_OBJECT (self), signals [CHANGED], 0);
     162                 :           4 : }
     163                 :             : 
     164                 :             : static void
     165                 :           2 : g_dbus_proxy_new_for_bus_cb (GObject      *object,
     166                 :             :                              GAsyncResult *result,
     167                 :             :                              gpointer      user_data)
     168                 :             : {
     169                 :           2 :   g_autoptr (ValentTelephony) self = VALENT_TELEPHONY (user_data);
     170         [ -  - ]:           2 :   g_autoptr (GDBusProxy) proxy = NULL;
     171         [ -  - ]:           2 :   g_autoptr (GError) error = NULL;
     172                 :           2 :   const char *object_path;
     173                 :             : 
     174                 :           2 :   proxy = g_dbus_proxy_new_for_bus_finish (result, &error);
     175                 :             : 
     176         [ -  + ]:           2 :   if (proxy == NULL)
     177                 :             :     {
     178                 :           0 :       g_warning ("%s(): %s", G_STRFUNC, error->message);
     179         [ #  # ]:           0 :       return;
     180                 :             :     }
     181                 :             : 
     182                 :           2 :   g_signal_connect_object (proxy,
     183                 :             :                            "g-properties-changed",
     184                 :             :                            G_CALLBACK (on_properties_changed),
     185                 :             :                            self, 0);
     186                 :             : 
     187                 :           2 :   object_path = g_dbus_proxy_get_object_path (proxy);
     188         [ -  + ]:           2 :   g_hash_table_replace (self->modems,
     189                 :           2 :                         g_strdup (object_path),
     190                 :             :                         g_steal_pointer (&proxy));
     191                 :             : 
     192         [ -  + ]:           2 :   g_signal_emit (G_OBJECT (self), signals [CHANGED], 0);
     193                 :             : }
     194                 :             : 
     195                 :             : static void
     196                 :           2 : on_modem_added (GDBusObjectManager *manager,
     197                 :             :                 GDBusObject        *object,
     198                 :             :                 ValentTelephony    *self)
     199                 :             : {
     200                 :           2 :   const char *object_path;
     201                 :             : 
     202   [ +  -  +  -  :           2 :   g_assert (G_IS_DBUS_OBJECT_MANAGER (manager));
             +  -  -  + ]
     203   [ +  -  +  -  :           2 :   g_assert (G_IS_DBUS_OBJECT (object));
             +  -  +  - ]
     204         [ +  - ]:           2 :   g_assert (VALENT_IS_TELEPHONY (self));
     205                 :             : 
     206                 :           2 :   object_path = g_dbus_object_get_object_path (object);
     207                 :             : 
     208   [ -  +  +  -  :           2 :   if (!g_str_has_prefix (object_path, "/org/freedesktop/ModemManager1/Modem"))
                   -  + ]
     209                 :           0 :     return;
     210                 :             : 
     211                 :           2 :   g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM,
     212                 :             :                             G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
     213                 :             :                             NULL,
     214                 :             :                             "org.freedesktop.ModemManager1",
     215                 :             :                             object_path,
     216                 :             :                             "org.freedesktop.ModemManager1.Modem",
     217                 :             :                             NULL,
     218                 :             :                             (GAsyncReadyCallback)g_dbus_proxy_new_for_bus_cb,
     219                 :             :                             g_object_ref (self));
     220                 :             : }
     221                 :             : 
     222                 :             : static void
     223                 :           2 : on_modem_removed (GDBusObjectManager *manager,
     224                 :             :                   GDBusObject        *object,
     225                 :             :                   ValentTelephony    *self)
     226                 :             : {
     227                 :           2 :   const char *object_path;
     228                 :             : 
     229   [ +  -  +  -  :           2 :   g_assert (G_IS_DBUS_OBJECT_MANAGER (manager));
             +  -  -  + ]
     230   [ +  -  +  -  :           2 :   g_assert (G_IS_DBUS_OBJECT (object));
             +  -  +  - ]
     231         [ +  - ]:           2 :   g_assert (VALENT_IS_TELEPHONY (self));
     232                 :             : 
     233                 :           2 :   object_path = g_dbus_object_get_object_path (object);
     234                 :             : 
     235   [ -  +  +  -  :           2 :   if (!g_str_has_prefix (object_path, "/org/freedesktop/ModemManager1/Modem"))
                   -  + ]
     236                 :           0 :     return;
     237                 :             : 
     238         [ +  - ]:           2 :   if (g_hash_table_remove (self->modems, object_path))
     239                 :           2 :     g_signal_emit (G_OBJECT (self), signals [CHANGED], 0);
     240                 :             : }
     241                 :             : 
     242                 :             : static void
     243                 :           2 : g_dbus_object_manager_client_new_for_bus_cb (GObject      *object,
     244                 :             :                                              GAsyncResult *result,
     245                 :             :                                              gpointer      user_data)
     246                 :             : {
     247                 :           2 :   g_autoptr (ValentTelephony) self = VALENT_TELEPHONY (user_data);
     248                 :           2 :   g_autolist (GDBusObject) modems = NULL;
     249                 :           2 :   g_autoptr (GError) error = NULL;
     250                 :             : 
     251                 :           2 :   self->manager = g_dbus_object_manager_client_new_for_bus_finish (result,
     252                 :             :                                                                    &error);
     253                 :             : 
     254         [ -  + ]:           2 :   if (self->manager == NULL)
     255                 :             :     {
     256                 :           0 :       g_warning ("%s(): %s", G_STRFUNC, error->message);
     257         [ #  # ]:           0 :       return;
     258                 :             :     }
     259                 :             : 
     260                 :           2 :   modems = g_dbus_object_manager_get_objects (self->manager);
     261                 :             : 
     262         [ +  + ]:           3 :   for (const GList *iter = modems; iter; iter = iter->next)
     263                 :           1 :     on_modem_added (self->manager, iter->data, self);
     264                 :             : 
     265                 :           2 :   g_signal_connect_object (self->manager,
     266                 :             :                            "object-added",
     267                 :             :                            G_CALLBACK (on_modem_added),
     268                 :             :                            self, 0);
     269         [ -  + ]:           2 :   g_signal_connect_object (self->manager,
     270                 :             :                            "object-removed",
     271                 :             :                            G_CALLBACK (on_modem_removed),
     272                 :             :                            self, 0);
     273                 :             : }
     274                 :             : 
     275                 :             : /*
     276                 :             :  * ValentObject
     277                 :             :  */
     278                 :             : static void
     279                 :           1 : valent_telephony_destroy (ValentObject *object)
     280                 :             : {
     281                 :           1 :   ValentTelephony *self = VALENT_TELEPHONY (object);
     282                 :             : 
     283                 :           1 :   g_signal_handlers_disconnect_by_data (self->manager, self);
     284         [ +  - ]:           1 :   g_clear_object (&self->manager);
     285                 :             : 
     286                 :           1 :   VALENT_OBJECT_CLASS (valent_telephony_parent_class)->destroy (object);
     287                 :           1 : }
     288                 :             : 
     289                 :             : /*
     290                 :             :  * GObject
     291                 :             :  */
     292                 :             : static void
     293                 :           2 : valent_telephony_constructed (GObject *object)
     294                 :             : {
     295                 :           2 :   ValentTelephony *self = VALENT_TELEPHONY (object);
     296                 :             : 
     297                 :           2 :   G_OBJECT_CLASS (valent_telephony_parent_class)->constructed (object);
     298                 :             : 
     299                 :           2 :   g_dbus_object_manager_client_new_for_bus (G_BUS_TYPE_SYSTEM,
     300                 :             :                                             G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_DO_NOT_AUTO_START,
     301                 :             :                                             "org.freedesktop.ModemManager1",
     302                 :             :                                             "/org/freedesktop/ModemManager1",
     303                 :             :                                             NULL, NULL, NULL,
     304                 :             :                                             NULL,
     305                 :             :                                             (GAsyncReadyCallback)g_dbus_object_manager_client_new_for_bus_cb,
     306                 :             :                                             g_object_ref (self));
     307                 :           2 : }
     308                 :             : 
     309                 :             : static void
     310                 :           1 : valent_telephony_finalize (GObject *object)
     311                 :             : {
     312                 :           1 :   ValentTelephony *self = VALENT_TELEPHONY (object);
     313                 :             : 
     314         [ +  - ]:           1 :   g_clear_pointer (&self->modems, g_hash_table_unref);
     315                 :             : 
     316                 :           1 :   G_OBJECT_CLASS (valent_telephony_parent_class)->finalize (object);
     317                 :           1 : }
     318                 :             : 
     319                 :             : static void
     320                 :           2 : valent_telephony_class_init (ValentTelephonyClass *klass)
     321                 :             : {
     322                 :           2 :   GObjectClass *object_class = G_OBJECT_CLASS (klass);
     323                 :           2 :   ValentObjectClass *vobject_class = VALENT_OBJECT_CLASS (klass);
     324                 :             : 
     325                 :           2 :   object_class->constructed = valent_telephony_constructed;
     326                 :           2 :   object_class->finalize = valent_telephony_finalize;
     327                 :             : 
     328                 :           2 :   vobject_class->destroy = valent_telephony_destroy;
     329                 :             : 
     330                 :             :   /**
     331                 :             :    * ValentTelephony::changed:
     332                 :             :    * @self: a `ValentTelephony`
     333                 :             :    *
     334                 :             :    * `ValentTelephony`::changed is emitted whenever a relevant property changes.
     335                 :             :    */
     336                 :           4 :   signals [CHANGED] =
     337                 :           2 :     g_signal_new ("changed",
     338                 :             :                   G_TYPE_FROM_CLASS (klass),
     339                 :             :                   G_SIGNAL_RUN_LAST,
     340                 :             :                   0,
     341                 :             :                   NULL, NULL, NULL,
     342                 :             :                   G_TYPE_NONE, 0);
     343                 :           2 : }
     344                 :             : 
     345                 :             : static void
     346                 :           2 : valent_telephony_init (ValentTelephony *self)
     347                 :             : {
     348                 :           2 :   self->modems = g_hash_table_new_full (g_str_hash,
     349                 :             :                                         g_str_equal,
     350                 :             :                                         g_free,
     351                 :             :                                         g_object_unref);
     352                 :           2 : }
     353                 :             : 
     354                 :             : /**
     355                 :             :  * valent_telephony_get_default:
     356                 :             :  *
     357                 :             :  * Get the default [class@Valent.Network].
     358                 :             :  *
     359                 :             :  * Returns: (transfer none) (not nullable): a `ValentTelephony`
     360                 :             :  *
     361                 :             :  * Since: 1.0
     362                 :             :  */
     363                 :             : ValentTelephony *
     364                 :           3 : valent_telephony_get_default (void)
     365                 :             : {
     366         [ +  + ]:           3 :   if (default_telephony == NULL)
     367                 :             :     {
     368                 :           2 :       default_telephony = g_object_new (VALENT_TYPE_TELEPHONY, NULL);
     369                 :             : 
     370                 :           2 :       g_object_add_weak_pointer (G_OBJECT (default_telephony),
     371                 :             :                                  (gpointer)&default_telephony);
     372                 :             :     }
     373                 :             : 
     374                 :           3 :   return default_telephony;
     375                 :             : }
     376                 :             : 
     377                 :             : static JsonNode *
     378                 :           6 : valent_telephony_serialize_modem (GDBusProxy *proxy)
     379                 :             : {
     380                 :          12 :   g_autoptr (JsonBuilder) builder = NULL;
     381                 :           6 :   GVariant *value;
     382                 :           6 :   unsigned int access_technologies;
     383                 :           6 :   uint32_t signal_quality;
     384                 :           6 :   gboolean signal_recent;
     385                 :           6 :   int32_t state;
     386                 :           6 :   const char *telephony_type;
     387                 :           6 :   int64_t signal_strength = 0;
     388                 :             : 
     389   [ +  -  +  -  :           6 :   g_assert (G_IS_DBUS_PROXY (proxy));
             -  +  -  - ]
     390                 :             : 
     391                 :             :   /* Extract the relevant properties */
     392                 :           6 :   value = g_dbus_proxy_get_cached_property (proxy, "AccessTechnologies");
     393                 :           6 :   g_variant_get (value, "u", &access_technologies);
     394         [ +  - ]:           6 :   g_clear_pointer (&value, g_variant_unref);
     395                 :             : 
     396                 :           6 :   value = g_dbus_proxy_get_cached_property (proxy, "SignalQuality");
     397                 :           6 :   g_variant_get (value, "(ub)", &signal_quality, &signal_recent);
     398         [ +  - ]:           6 :   g_clear_pointer (&value, g_variant_unref);
     399                 :             : 
     400                 :           6 :   value = g_dbus_proxy_get_cached_property (proxy, "State");
     401                 :           6 :   g_variant_get (value, "i", &state);
     402         [ +  - ]:           6 :   g_clear_pointer (&value, g_variant_unref);
     403                 :             : 
     404                 :             :   /* Convert to KDE Connect values (`networkType`, `signalStrength`) */
     405                 :           6 :   telephony_type = get_telephony_type_string (access_technologies);
     406                 :             : 
     407         [ +  + ]:           6 :   if (state >= MM_MODEM_STATE_ENABLED)
     408                 :             :     {
     409         [ +  - ]:           2 :       if (signal_quality >= 100)
     410                 :             :         signal_strength = 4;
     411                 :             :       else
     412                 :           2 :         signal_strength = (int64_t)floor (signal_quality / 20);
     413                 :             :     }
     414                 :             : 
     415                 :             :   /* Serialize to a JsonNode */
     416                 :           6 :   builder = json_builder_new ();
     417                 :           6 :   json_builder_begin_object (builder);
     418                 :           6 :   json_builder_set_member_name (builder, "networkType");
     419                 :           6 :   json_builder_add_string_value (builder, telephony_type);
     420                 :           6 :   json_builder_set_member_name (builder, "signalStrength");
     421                 :           6 :   json_builder_add_int_value (builder, signal_strength);
     422                 :           6 :   json_builder_end_object (builder);
     423                 :             : 
     424         [ +  - ]:           6 :   return json_builder_get_root (builder);
     425                 :             : }
     426                 :             : 
     427                 :             : /**
     428                 :             :  * valent_telephony_get_signal_strengths:
     429                 :             :  * @telephony: a `ValentTelephony`
     430                 :             :  *
     431                 :             :  * Get a serialized dictionary of the known modems' status.
     432                 :             :  *
     433                 :             :  * Returns: (transfer full) (nullable): a `JsonNode`
     434                 :             :  *
     435                 :             :  * Since: 1.0
     436                 :             :  */
     437                 :             : JsonNode *
     438                 :           8 : valent_telephony_get_signal_strengths (ValentTelephony *telephony)
     439                 :             : {
     440                 :          16 :   g_autoptr (JsonBuilder) builder = NULL;
     441                 :           8 :   GHashTableIter iter;
     442                 :           8 :   gpointer key, value;
     443                 :           8 :   unsigned int m = 0;
     444                 :             : 
     445         [ -  + ]:           8 :   g_return_val_if_fail (VALENT_IS_TELEPHONY (telephony), NULL);
     446                 :             : 
     447                 :           8 :   builder = json_builder_new ();
     448                 :           8 :   json_builder_begin_object (builder);
     449                 :             : 
     450                 :           8 :   g_hash_table_iter_init (&iter, telephony->modems);
     451                 :             : 
     452         [ +  + ]:          14 :   while (g_hash_table_iter_next (&iter, &key, &value))
     453                 :             :     {
     454                 :           6 :       g_autoptr (JsonNode) modem = NULL;
     455                 :           6 :       g_autofree char *id = NULL;
     456                 :             : 
     457                 :           6 :       id = g_strdup_printf ("%u", m++);
     458                 :           6 :       modem = valent_telephony_serialize_modem (G_DBUS_PROXY (value));
     459                 :             : 
     460                 :           6 :       json_builder_set_member_name (builder, id);
     461                 :           6 :       json_builder_add_value (builder, g_steal_pointer (&modem));
     462                 :             :     }
     463                 :             : 
     464                 :           8 :   json_builder_end_object (builder);
     465                 :             : 
     466                 :           8 :   return json_builder_get_root (builder);
     467                 :             : }
     468                 :             : 
        

Generated by: LCOV version 2.0-1