LCOV - code coverage report
Current view: top level - src/domain/read - contacts.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 67.2 % 67 45
Test Date: 2026-05-06 13:17:06 Functions: 100.0 % 1 1

            Line data    Source code
       1              : /* SPDX-License-Identifier: GPL-3.0-or-later */
       2              : /* Copyright 2026 Peter Csaszar */
       3              : 
       4              : /**
       5              :  * @file domain/read/contacts.c
       6              :  */
       7              : 
       8              : #include "domain/read/contacts.h"
       9              : 
      10              : #include "tl_serial.h"
      11              : #include "tl_registry.h"
      12              : #include "tl_skip.h"
      13              : #include "mtproto_rpc.h"
      14              : #include "logger.h"
      15              : #include "raii.h"
      16              : 
      17              : #include <stdlib.h>
      18              : #include <string.h>
      19              : 
      20              : #define CRC_contacts_getContacts 0x5dd69e12u
      21              : #define CRC_contact              0x145ade0bu
      22              : 
      23            8 : int domain_get_contacts(const ApiConfig *cfg,
      24              :                          MtProtoSession *s, Transport *t,
      25              :                          ContactEntry *out, int max_entries, int *out_count) {
      26            8 :     if (!cfg || !s || !t || !out || !out_count || max_entries <= 0) return -1;
      27            6 :     *out_count = 0;
      28            6 :     if (max_entries > CONTACTS_MAX) max_entries = CONTACTS_MAX;
      29              : 
      30            6 :     TlWriter w; tl_writer_init(&w);
      31            6 :     tl_write_uint32(&w, CRC_contacts_getContacts);
      32            6 :     tl_write_int64 (&w, 0);  /* hash = 0 → server always returns full list */
      33              :     uint8_t query[32];
      34            6 :     if (w.len > sizeof(query)) { tl_writer_free(&w); return -1; }
      35            6 :     memcpy(query, w.data, w.len);
      36            6 :     size_t qlen = w.len;
      37            6 :     tl_writer_free(&w);
      38              : 
      39            6 :     RAII_STRING uint8_t *resp = (uint8_t *)malloc(65536);
      40            6 :     if (!resp) return -1;
      41            6 :     size_t resp_len = 0;
      42            6 :     if (api_call(cfg, s, t, query, qlen, resp, 65536, &resp_len) != 0) return -1;
      43            6 :     if (resp_len < 4) return -1;
      44              : 
      45              :     uint32_t top;
      46            6 :     memcpy(&top, resp, 4);
      47            6 :     if (top == TL_rpc_error) {
      48            1 :         RpcError err; rpc_parse_error(resp, resp_len, &err);
      49            1 :         logger_log(LOG_ERROR, "contacts: RPC error %d: %s",
      50              :                    err.error_code, err.error_msg);
      51            1 :         return -1;
      52              :     }
      53            5 :     if (top == TL_contacts_contactsNotModified) {
      54            0 :         return 0;
      55              :     }
      56            5 :     if (top != TL_contacts_contacts) {
      57            0 :         logger_log(LOG_ERROR, "contacts: unexpected top 0x%08x", top);
      58            0 :         return -1;
      59              :     }
      60              : 
      61            5 :     TlReader r = tl_reader_init(resp, resp_len);
      62            5 :     tl_read_uint32(&r); /* top constructor */
      63              : 
      64              :     /* contacts:Vector<Contact> */
      65            5 :     uint32_t vec = tl_read_uint32(&r);
      66            5 :     if (vec != TL_vector) return -1;
      67            5 :     uint32_t count = tl_read_uint32(&r);
      68            5 :     int written = 0;
      69           12 :     for (uint32_t i = 0; i < count && written < max_entries; i++) {
      70            7 :         if (!tl_reader_ok(&r)) break;
      71            7 :         uint32_t ccrc = tl_read_uint32(&r);
      72            7 :         if (ccrc != CRC_contact) {
      73            0 :             logger_log(LOG_WARN,
      74              :                        "contacts: unknown Contact 0x%08x — stopping", ccrc);
      75            0 :             break;
      76              :         }
      77              :         ContactEntry e;
      78            7 :         memset(&e, 0, sizeof(e));
      79            7 :         e.user_id = tl_read_int64(&r);
      80            7 :         int b = tl_read_bool(&r);
      81            7 :         e.mutual = (b == 1) ? 1 : 0;
      82            7 :         out[written++] = e;
      83              :     }
      84            5 :     *out_count = written;
      85              : 
      86              :     /* saved_count:int */
      87            5 :     tl_read_int32(&r);
      88              : 
      89              :     /* users:Vector<User> — tl_extract_user advances past the FULL object
      90              :      * so the cursor is correctly positioned for the next user each iteration. */
      91            5 :     uint32_t uvec = tl_read_uint32(&r);
      92            5 :     if (uvec == TL_vector) {
      93            5 :         uint32_t ucount = tl_read_uint32(&r);
      94            5 :         for (uint32_t i = 0; i < ucount; i++) {
      95            0 :             if (!tl_reader_ok(&r)) break;
      96            0 :             UserSummary us = {0};
      97            0 :             if (tl_extract_user(&r, &us) != 0) {
      98            0 :                 logger_log(LOG_WARN, "contacts: user parse failed at index %u", i);
      99            0 :                 break;
     100              :             }
     101            0 :             for (int j = 0; j < written; j++) {
     102            0 :                 if (out[j].user_id == us.id) {
     103            0 :                     out[j].access_hash = us.access_hash;
     104            0 :                     size_t n = strlen(us.name);
     105            0 :                     if (n >= sizeof(out[j].name)) n = sizeof(out[j].name) - 1;
     106            0 :                     memcpy(out[j].name, us.name, n);
     107            0 :                     out[j].name[n] = '\0';
     108            0 :                     n = strlen(us.username);
     109            0 :                     if (n >= sizeof(out[j].username)) n = sizeof(out[j].username) - 1;
     110            0 :                     memcpy(out[j].username, us.username, n);
     111            0 :                     out[j].username[n] = '\0';
     112            0 :                     break;
     113              :                 }
     114              :             }
     115              :         }
     116              :     }
     117              : 
     118            5 :     return 0;
     119              : }
        

Generated by: LCOV version 2.0-1