LCOV - code coverage report
Current view: top level - src/infrastructure - config_store.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 86.4 % 59 51
Test Date: 2026-04-20 19:54:22 Functions: 100.0 % 4 4

            Line data    Source code
       1              : /* SPDX-License-Identifier: GPL-3.0-or-later */
       2              : /* Copyright 2026 Peter Csaszar */
       3              : 
       4              : #include "config_store.h"
       5              : #include "config.h"
       6              : #include "fs_util.h"
       7              : #include "platform/path.h"
       8              : #include "raii.h"
       9              : #include "logger.h"
      10              : #include <stdio.h>
      11              : #include <stdlib.h>
      12              : #include <string.h>
      13              : #include <ctype.h>
      14              : 
      15              : #define CONFIG_APP_DIR "tg-cli"
      16              : #define CONFIG_FILE   "config.ini"
      17              : 
      18              : /** @brief Trims leading and trailing whitespace from a string in-place. */
      19           12 : static char* trim(char *str) {
      20              :     char *end;
      21           12 :     while (isspace((unsigned char)*str)) str++;
      22           12 :     if (*str == 0) return str;
      23           12 :     end = str + strlen(str) - 1;
      24           12 :     while (end > str && isspace((unsigned char)*end)) end--;
      25           12 :     end[1] = '\0';
      26           12 :     return str;
      27              : }
      28              : 
      29              : /** @brief Returns a heap-allocated path to the config file. Caller must free. */
      30            6 : static char* get_config_path(void) {
      31            6 :     const char *config_base = platform_config_dir();
      32            6 :     if (!config_base) return NULL;
      33            6 :     char *path = NULL;
      34            6 :     if (asprintf(&path, "%s/%s/%s", config_base, CONFIG_APP_DIR, CONFIG_FILE) == -1) {
      35            0 :         return NULL;
      36              :     }
      37            6 :     return path;
      38              : }
      39              : 
      40            4 : Config* config_load_from_store(void) {
      41            8 :     RAII_STRING char *path = get_config_path();
      42            4 :     if (!path) return NULL;
      43              : 
      44            8 :     RAII_FILE FILE *fp = fopen(path, "r");
      45            4 :     if (!fp) return NULL;
      46              : 
      47            3 :     Config *cfg = calloc(1, sizeof(Config));
      48            3 :     if (!cfg) return NULL;
      49              : 
      50              :     char line[512];
      51            9 :     while (fgets(line, sizeof(line), fp)) {
      52            6 :         char *key = strtok(line, "=");
      53            6 :         char *val = strtok(NULL, "\n");
      54            6 :         if (key && val) {
      55            6 :             key = trim(key);
      56            6 :             val = trim(val);
      57            6 :             if (strcmp(key, "API_BASE") == 0) cfg->api_base = strdup(val);
      58            3 :             else if (strcmp(key, "TOKEN") == 0) cfg->token = strdup(val);
      59            1 :             else if (strcmp(key, "SSL_NO_VERIFY") == 0) cfg->ssl_no_verify = atoi(val);
      60              :         }
      61              :     }
      62              : 
      63              :     /* Set default API base if missing */
      64            3 :     if (!cfg->api_base) cfg->api_base = strdup("https://api.telegram.org");
      65              : 
      66            3 :     if (!cfg->token) {
      67            1 :         logger_log(LOG_WARN, "Config found but incomplete (missing TOKEN).");
      68            1 :         config_free(cfg);
      69            1 :         return NULL;
      70              :     }
      71              : 
      72            2 :     return cfg;
      73              : }
      74              : 
      75            2 : int config_save_to_store(const Config *cfg) {
      76            2 :     const char *config_base = platform_config_dir();
      77            2 :     if (!config_base) return -1;
      78              : 
      79              :     char dir_path[1024];
      80            2 :     snprintf(dir_path, sizeof(dir_path), "%s/%s", config_base, CONFIG_APP_DIR);
      81              : 
      82              :     /* Create directory with 0700 */
      83            2 :     if (fs_mkdir_p(dir_path, 0700) != 0) {
      84            0 :         logger_log(LOG_ERROR, "Failed to create config directory %s", dir_path);
      85            0 :         return -1;
      86              :     }
      87              : 
      88            4 :     RAII_STRING char *path = get_config_path();
      89            2 :     if (!path) {
      90            0 :         logger_log(LOG_ERROR, "Failed to determine config directory");
      91            0 :         return -1;
      92              :     }
      93            4 :     RAII_FILE FILE *fp = fopen(path, "w");
      94            2 :     if (!fp) {
      95            0 :         logger_log(LOG_ERROR, "Failed to open config file for writing: %s", path);
      96            0 :         return -1;
      97              :     }
      98              : 
      99              :     /* Set 0600 immediately */
     100            2 :     if (fs_ensure_permissions(path, 0600) != 0) {
     101            0 :         logger_log(LOG_WARN, "Failed to set strict permissions on %s", path);
     102              :     }
     103              : 
     104            2 :     fprintf(fp, "API_BASE=%s\n", cfg->api_base ? cfg->api_base : "https://api.telegram.org");
     105            2 :     fprintf(fp, "TOKEN=%s\n", cfg->token ? cfg->token : "");
     106            2 :     if (cfg->ssl_no_verify)
     107            1 :         fprintf(fp, "SSL_NO_VERIFY=1\n");
     108              : 
     109            2 :     logger_log(LOG_INFO, "Config saved to %s", path);
     110            2 :     return 0;
     111              : }
        

Generated by: LCOV version 2.0-1