stamail

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

headers.c (5537B)


      1 /*
      2  * ============================================================================
      3  * ███████╗████████╗ █████╗ ███╗   ███╗ █████╗ ██╗██╗     
      4  * ██╔════╝╚══██╔══╝██╔══██╗████╗ ████║██╔══██╗██║██║     
      5  * ███████╗   ██║   ███████║██╔████╔██║███████║██║██║     
      6  * ╚════██║   ██║   ██╔══██║██║╚██╔╝██║██╔══██║██║██║     
      7  * ███████║   ██║   ██║  ██║██║ ╚═╝ ██║██║  ██║██║███████╗
      8  * ╚══════╝   ╚═╝   ╚═╝  ╚═╝╚═╝     ╚═╝╚═╝  ╚═╝╚═╝╚══════╝
      9  * ============================================================================
     10  *
     11  * Copyright (C) 2026 Binkd.
     12  *
     13  * This file is part of stamail.
     14  *
     15  * stamail is free software: you can redistribute it and/or modify it under the
     16  * terms of the GNU General Public License as published by the Free Software
     17  * Foundation, either version 3 of the License, or (at your option) any later
     18  * version.
     19  *
     20  * stamail is distributed in the hope that it will be useful, but WITHOUT ANY
     21  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
     22  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
     23  * details.
     24  * 
     25  * You should have received a copy of the GNU General Public License
     26  * along with stamail. If not, see <https://www.gnu.org/licenses/>.
     27  *
     28  * =============================================================================
     29 */
     30 
     31 #include <stdio.h>
     32 #include <stdlib.h>
     33 #include <string.h>
     34 #include <strings.h>
     35 #include <ctype.h>
     36 #include "stamail.h"
     37 
     38 /* Read a header value from file */
     39 static char *read_header(FILE *fp, const char *header_name, int *len) {
     40     static char line[4096];
     41     static char value[4096];
     42     int value_len = 0;
     43     size_t header_len = strlen(header_name);
     44     int found = 0;
     45     
     46     rewind(fp);
     47     
     48     while (fgets(line, sizeof(line), fp)) {
     49         /* End of headers (blank line) */
     50         if (line[0] == '\n' || line[0] == '\r')
     51             break;
     52         
     53         /* Check if this line starts with our header */
     54         if (!found && strncasecmp(line, header_name, header_len) == 0 &&
     55             line[header_len] == ':') {
     56             found = 1;
     57             /* Skip header name and colon, skip whitespace */
     58             char *p = line + header_len + 1;
     59             while (*p && isspace(*p)) p++;
     60             
     61             /* Copy value, removing newline */
     62             while (*p && *p != '\n' && *p != '\r' && 
     63                    value_len < (int)sizeof(value) - 1) {
     64                 value[value_len++] = *p++;
     65             }
     66             continue;
     67         }
     68         
     69         /* Handle continuation lines (start with whitespace) */
     70         if (found && (line[0] == ' ' || line[0] == '\t')) {
     71             char *p = line;
     72             while (*p && isspace(*p)) p++;
     73             
     74             /* Add space before continuation */
     75             if (value_len > 0 && value_len < (int)sizeof(value) - 1)
     76                 value[value_len++] = ' ';
     77             
     78             while (*p && *p != '\n' && *p != '\r' && 
     79                    value_len < (int)sizeof(value) - 1) {
     80                 value[value_len++] = *p++;
     81             }
     82             continue;
     83         }
     84         
     85         /* If we found our header and this isn't a continuation, we're done */
     86         if (found)
     87             break;
     88     }
     89     
     90     if (!found || value_len == 0)
     91         return NULL;
     92     
     93     value[value_len] = '\0';
     94     *len = value_len;
     95     
     96     /* Allocate and return a copy */
     97     char *result = malloc(value_len + 1);
     98     if (result) {
     99         memcpy(result, value, value_len + 1);
    100     }
    101     return result;
    102 }
    103 
    104 /* Extract In-Reply-To from maildir file */
    105 int extract_threading_headers(struct message_node *node) {
    106     if (!node->m.filename || node->m.filename_len == 0)
    107         return -1;
    108     
    109     /* Build null-terminated filename */
    110     char path[2048];
    111     if (node->m.filename_len >= (int)sizeof(path))
    112         return -1;
    113     
    114     memcpy(path, node->m.filename, node->m.filename_len);
    115     path[node->m.filename_len] = '\0';
    116     
    117     FILE *fp = fopen(path, "r");
    118     if (!fp) {
    119         perror(path);
    120         return -1;
    121     }
    122     
    123     /* Read In-Reply-To header */
    124     int len;
    125     char *in_reply_to = read_header(fp, "In-Reply-To", &len);
    126     if (in_reply_to) {
    127         /* Strip < > brackets */
    128         char *start = in_reply_to;
    129         int new_len = len;
    130         
    131         if (len > 2 && start[0] == '<' && start[len-1] == '>') {
    132             start++;
    133             new_len -= 2;
    134         }
    135         
    136         /* Store in message node (allocate permanent copy) */
    137         node->m.in_reply_to = malloc(new_len + 1);
    138         if (node->m.in_reply_to) {
    139             memcpy((char *)node->m.in_reply_to, start, new_len);
    140             ((char *)node->m.in_reply_to)[new_len] = '\0';
    141             node->m.in_reply_to_len = new_len;
    142         }
    143         
    144         free(in_reply_to);
    145     }
    146     
    147     /* Read References header */
    148     char *references = read_header(fp, "References", &len);
    149     if (references) {
    150         node->m.references = references;  /* Keep the allocation */
    151         node->m.references_len = len;
    152     }
    153     
    154     fclose(fp);
    155     return 0;
    156 }