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 }