ascii-chat 0.8.38
Real-time terminal-based video chat with ASCII art conversion
Loading...
Searching...
No Matches
validation.c File Reference

Go to the source code of this file.

Functions

int validate_opt_port (const char *value_str, char *error_msg, size_t error_msg_size)
 
bool validate_port_callback (const void *options_struct, char **error_msg)
 
int validate_opt_positive_int (const char *value_str, char *error_msg, size_t error_msg_size)
 
int validate_opt_non_negative_int (const char *value_str, char *error_msg, size_t error_msg_size)
 
int validate_opt_color_mode (const char *value_str, char *error_msg, size_t error_msg_size)
 
int validate_opt_render_mode (const char *value_str, char *error_msg, size_t error_msg_size)
 
int validate_opt_palette (const char *value_str, char *error_msg, size_t error_msg_size)
 
int validate_opt_log_level (const char *value_str, char *error_msg, size_t error_msg_size)
 
int validate_opt_ip_address (const char *value_str, char *parsed_address, size_t address_size, bool is_client, char *error_msg, size_t error_msg_size)
 
float validate_opt_float_non_negative (const char *value_str, char *error_msg, size_t error_msg_size)
 
float validate_opt_volume (const char *value_str, char *error_msg, size_t error_msg_size)
 
int validate_opt_max_clients (const char *value_str, char *error_msg, size_t error_msg_size)
 
int validate_opt_compression_level (const char *value_str, char *error_msg, size_t error_msg_size)
 
int validate_opt_fps (const char *value_str, char *error_msg, size_t error_msg_size)
 
int validate_opt_reconnect (const char *value_str, char *error_msg, size_t error_msg_size)
 
int validate_opt_device_index (const char *value_str, char *error_msg, size_t error_msg_size)
 
int validate_opt_password (const char *value_str, char *error_msg, size_t error_msg_size)
 
int options_collect_identity_keys (options_t *opts, int argc, char *argv[])
 
bool is_remote_key_path (const char *key_path)
 

Function Documentation

◆ is_remote_key_path()

bool is_remote_key_path ( const char *  key_path)

Definition at line 596 of file validation.c.

596 {
597 if (!key_path || key_path[0] == '\0') {
598 return false;
599 }
600 return (strncmp(key_path, "github:", 7) == 0 ||
601 strncmp(key_path, "gitlab:", 7) == 0 ||
602 strncmp(key_path, "gpg:", 4) == 0 ||
603 strncmp(key_path, "http://", 7) == 0 ||
604 strncmp(key_path, "https://", 8) == 0);
605}

Referenced by options_collect_identity_keys(), and options_init().

◆ options_collect_identity_keys()

int options_collect_identity_keys ( options_t *  opts,
int  argc,
char *  argv[] 
)

Collect multiple –key flags into identity_keys array

Scans argv for all –key or -K flags and populates:

  • opts->encrypt_key with the first key (backward compatibility)
  • opts->identity_keys[] with all keys
  • opts->num_identity_keys with count

This enables multi-key support for servers/ACDS that need to present different identity keys (SSH, GPG) based on client expectations.

Definition at line 528 of file validation.c.

528 {
529 if (!opts || !argv) {
530 log_error("options_collect_identity_keys: Invalid arguments");
531 return -1;
532 }
533
534 size_t key_count = 0;
535
536 // Scan argv for all --key or -K flags
537 for (int i = 1; i < argc && key_count < MAX_IDENTITY_KEYS; i++) {
538 const char *arg = argv[i];
539
540 // Check if this is a --key or -K flag
541 bool is_key_flag = false;
542 const char *key_value = NULL;
543
544 if (strcmp(arg, "--key") == 0 || strcmp(arg, "-K") == 0) {
545 // Next argument is the key path
546 if (i + 1 < argc) {
547 key_value = argv[i + 1];
548 is_key_flag = true;
549 i++; // Skip the value argument
550 }
551 } else if (strncmp(arg, "--key=", 6) == 0) {
552 // --key=value format
553 key_value = arg + 6;
554 is_key_flag = true;
555 }
556
557 if (is_key_flag && key_value && strlen(key_value) > 0) {
558 // Validate that local key files exist (skip for remote/virtual keys)
559 if (!is_remote_key_path(key_value)) {
560 struct stat st;
561 if (stat(key_value, &st) != 0) {
562 log_error("Key file not found: %s", key_value);
563 SET_ERRNO(ERROR_CRYPTO_KEY, "Key file not found: %s", key_value);
564 return -1;
565 }
566 // Check if it's a regular file (S_IFREG) - works on both Windows and Unix
567 if ((st.st_mode & S_IFMT) != S_IFREG) {
568 log_error("Key path is not a regular file: %s", key_value);
569 SET_ERRNO(ERROR_CRYPTO_KEY, "Key path is not a regular file: %s", key_value);
570 return -1;
571 }
572 }
573
574 // Store in identity_keys array
575 SAFE_STRNCPY(opts->identity_keys[key_count], key_value, OPTIONS_BUFF_SIZE);
576
577 // First key also goes into encrypt_key for backward compatibility
578 if (key_count == 0) {
579 SAFE_STRNCPY(opts->encrypt_key, key_value, OPTIONS_BUFF_SIZE);
580 }
581
582 key_count++;
583 log_debug("Collected identity key #%zu: %s", key_count, key_value);
584 }
585 }
586
587 opts->num_identity_keys = key_count;
588
589 if (key_count > 0) {
590 log_info("Collected %zu identity key(s) for multi-key support", key_count);
591 }
592
593 return (int)key_count;
594}
bool is_remote_key_path(const char *key_path)
Definition validation.c:596

References is_remote_key_path().

Referenced by options_init().

◆ validate_opt_color_mode()

int validate_opt_color_mode ( const char *  value_str,
char *  error_msg,
size_t  error_msg_size 
)

Validate color mode string Returns parsed color mode on success, -1 on error

Definition at line 139 of file validation.c.

139 {
140 if (!value_str) {
141 if (error_msg) {
142 SAFE_SNPRINTF(error_msg, error_msg_size, "Color mode value is required");
143 }
144 return -1;
145 }
146
147 if (strcmp(value_str, "auto") == 0) {
148 return COLOR_MODE_AUTO;
149 }
150 if (strcmp(value_str, "none") == 0 || strcmp(value_str, "mono") == 0) {
151 return COLOR_MODE_NONE;
152 }
153 if (strcmp(value_str, "16") == 0 || strcmp(value_str, "16color") == 0) {
154 return COLOR_MODE_16_COLOR;
155 }
156 if (strcmp(value_str, "256") == 0 || strcmp(value_str, "256color") == 0) {
157 return COLOR_MODE_256_COLOR;
158 }
159 if (strcmp(value_str, "truecolor") == 0 || strcmp(value_str, "24bit") == 0) {
160 return COLOR_MODE_TRUECOLOR;
161 }
162 if (error_msg) {
163 SAFE_SNPRINTF(error_msg, error_msg_size,
164 "Invalid color mode '%s'. Valid modes: auto, none, mono, 16, 256, truecolor", value_str);
165 }
166 return -1;
167}

◆ validate_opt_compression_level()

int validate_opt_compression_level ( const char *  value_str,
char *  error_msg,
size_t  error_msg_size 
)

Validate compression level (1-9) Returns parsed value on success, -1 on error

Definition at line 388 of file validation.c.

388 {
389 int result = validate_int_range(value_str, 1, 9, "Compression level", error_msg, error_msg_size);
390 return (result == INT_MIN) ? -1 : result;
391}

◆ validate_opt_device_index()

int validate_opt_device_index ( const char *  value_str,
char *  error_msg,
size_t  error_msg_size 
)

Validate device index (-1 for default, or 0+ for specific device) Returns parsed value on success, INT_MIN on error

Definition at line 457 of file validation.c.

457 {
458 if (!value_str || strlen(value_str) == 0) {
459 if (error_msg) {
460 SAFE_SNPRINTF(error_msg, error_msg_size, "Device index value is required");
461 }
462 return INT_MIN;
463 }
464
465 int index = strtoint_safe(value_str);
466 if (index == INT_MIN) {
467 if (error_msg) {
468 SAFE_SNPRINTF(error_msg, error_msg_size,
469 "Invalid device index '%s'. Must be -1 (default) or a non-negative integer.", value_str);
470 }
471 return INT_MIN;
472 }
473
474 // -1 is valid (system default), otherwise must be >= 0
475 if (index < -1) {
476 if (error_msg) {
477 SAFE_SNPRINTF(error_msg, error_msg_size,
478 "Invalid device index '%d'. Must be -1 (default) or a non-negative integer.", index);
479 }
480 return INT_MIN;
481 }
482 return index;
483}
int strtoint_safe(const char *str)

References strtoint_safe().

Referenced by validate_webcam_index().

◆ validate_opt_float_non_negative()

float validate_opt_float_non_negative ( const char *  value_str,
char *  error_msg,
size_t  error_msg_size 
)

Validate float value (non-negative) Returns parsed value on success, returns -1.0f on error (caller must check)

Definition at line 321 of file validation.c.

321 {
322 if (!value_str || strlen(value_str) == 0) {
323 if (error_msg) {
324 SAFE_SNPRINTF(error_msg, error_msg_size, "Value is required");
325 }
326 return -1.0f;
327 }
328
329 char *endptr;
330 float val = strtof(value_str, &endptr);
331 if (*endptr != '\0' || value_str == endptr) {
332 if (error_msg) {
333 SAFE_SNPRINTF(error_msg, error_msg_size, "Invalid float value '%s'. Must be a number.", value_str);
334 }
335 return -1.0f;
336 }
337 if (val < 0.0f) {
338 if (error_msg) {
339 SAFE_SNPRINTF(error_msg, error_msg_size, "Value must be non-negative (got %.2f)", val);
340 }
341 return -1.0f;
342 }
343 return val;
344}

◆ validate_opt_fps()

int validate_opt_fps ( const char *  value_str,
char *  error_msg,
size_t  error_msg_size 
)

Validate FPS value (1-144) Returns parsed value on success, -1 on error

Definition at line 397 of file validation.c.

397 {
398 int result = validate_int_range(value_str, 1, 144, "FPS", error_msg, error_msg_size);
399 return (result == INT_MIN) ? -1 : result;
400}

◆ validate_opt_ip_address()

int validate_opt_ip_address ( const char *  value_str,
char *  parsed_address,
size_t  address_size,
bool  is_client,
char *  error_msg,
size_t  error_msg_size 
)

Validate IP address or hostname Returns 0 on success, -1 on error Sets parsed_address on success (resolved if hostname)

Definition at line 269 of file validation.c.

270 {
271 (void)is_client; // Parameter not used but kept for API consistency
272 if (!value_str || strlen(value_str) == 0) {
273 if (error_msg) {
274 SAFE_SNPRINTF(error_msg, error_msg_size, "Address value is required");
275 }
276 return -1;
277 }
278
279 // Parse IPv6 address (remove brackets if present)
280 char parsed_addr[OPTIONS_BUFF_SIZE];
281 if (parse_ipv6_address(value_str, parsed_addr, sizeof(parsed_addr)) == 0) {
282 value_str = parsed_addr;
283 }
284
285 // Check if it's a valid IPv4 address
286 if (is_valid_ipv4(value_str)) {
287 SAFE_SNPRINTF(parsed_address, address_size, "%s", value_str);
288 return 0;
289 }
290 // Check if it's a valid IPv6 address
291 if (is_valid_ipv6(value_str)) {
292 SAFE_SNPRINTF(parsed_address, address_size, "%s", value_str);
293 return 0;
294 }
295 // Check if it looks like an invalid IP (has dots but not valid IPv4 format)
296 if (strchr(value_str, '.') != NULL) {
297 if (error_msg) {
298 SAFE_SNPRINTF(error_msg, error_msg_size,
299 "Invalid IP address format '%s'. IPv4 addresses must have exactly 4 octets.", value_str);
300 }
301 return -1;
302 }
303
304 // Otherwise, try to resolve as hostname
305 char resolved_ip[OPTIONS_BUFF_SIZE];
306 if (platform_resolve_hostname_to_ipv4(value_str, resolved_ip, sizeof(resolved_ip)) == 0) {
307 SAFE_SNPRINTF(parsed_address, address_size, "%s", resolved_ip);
308 return 0;
309 } else {
310 if (error_msg) {
311 SAFE_SNPRINTF(error_msg, error_msg_size, "Failed to resolve hostname '%s' to IP address.", value_str);
312 }
313 return -1;
314 }
315}
int is_valid_ipv4(const char *ip)
Definition ip.c:58
int is_valid_ipv6(const char *ip)
Definition ip.c:105
int parse_ipv6_address(const char *input, char *output, size_t output_size)
Definition ip.c:158

References is_valid_ipv4(), is_valid_ipv6(), and parse_ipv6_address().

◆ validate_opt_log_level()

int validate_opt_log_level ( const char *  value_str,
char *  error_msg,
size_t  error_msg_size 
)

Validate log level string Returns parsed log level on success, -1 on error

Definition at line 235 of file validation.c.

235 {
236 if (!value_str) {
237 if (error_msg) {
238 SAFE_SNPRINTF(error_msg, error_msg_size, "Log level value is required");
239 }
240 return -1;
241 }
242
243 if (platform_strcasecmp(value_str, "dev") == 0) {
244 return LOG_DEV;
245 } else if (platform_strcasecmp(value_str, "debug") == 0) {
246 return LOG_DEBUG;
247 } else if (platform_strcasecmp(value_str, "info") == 0) {
248 return LOG_INFO;
249 } else if (platform_strcasecmp(value_str, "warn") == 0) {
250 return LOG_WARN;
251 } else if (platform_strcasecmp(value_str, "error") == 0) {
252 return LOG_ERROR;
253 } else if (platform_strcasecmp(value_str, "fatal") == 0) {
254 return LOG_FATAL;
255 } else {
256 if (error_msg) {
257 SAFE_SNPRINTF(error_msg, error_msg_size,
258 "Invalid log level '%s'. Valid levels: dev, debug, info, warn, error, fatal", value_str);
259 }
260 return -1;
261 }
262}
int platform_strcasecmp(const char *s1, const char *s2)

References platform_strcasecmp().

Referenced by parse_log_level_option().

◆ validate_opt_max_clients()

int validate_opt_max_clients ( const char *  value_str,
char *  error_msg,
size_t  error_msg_size 
)

Validate max clients (1-32) Returns parsed value on success, -1 on error

Definition at line 379 of file validation.c.

379 {
380 int result = validate_int_range(value_str, 1, 32, "Max clients", error_msg, error_msg_size);
381 return (result == INT_MIN) ? -1 : result;
382}

◆ validate_opt_non_negative_int()

int validate_opt_non_negative_int ( const char *  value_str,
char *  error_msg,
size_t  error_msg_size 
)

Validate non-negative integer Returns parsed value on success, -1 on error

Definition at line 130 of file validation.c.

130 {
131 int result = validate_int_range(value_str, 0, INT_MAX, "Value", error_msg, error_msg_size);
132 return (result == INT_MIN) ? -1 : result;
133}

◆ validate_opt_palette()

int validate_opt_palette ( const char *  value_str,
char *  error_msg,
size_t  error_msg_size 
)

Validate palette type string Returns parsed palette type on success, -1 on error

Definition at line 201 of file validation.c.

201 {
202 if (!value_str) {
203 if (error_msg) {
204 SAFE_SNPRINTF(error_msg, error_msg_size, "Palette value is required");
205 }
206 return -1;
207 }
208
209 if (strcmp(value_str, "standard") == 0) {
210 return PALETTE_STANDARD;
211 } else if (strcmp(value_str, "blocks") == 0) {
212 return PALETTE_BLOCKS;
213 } else if (strcmp(value_str, "digital") == 0) {
214 return PALETTE_DIGITAL;
215 } else if (strcmp(value_str, "minimal") == 0) {
216 return PALETTE_MINIMAL;
217 } else if (strcmp(value_str, "cool") == 0) {
218 return PALETTE_COOL;
219 } else if (strcmp(value_str, "custom") == 0) {
220 return PALETTE_CUSTOM;
221 } else {
222 if (error_msg) {
223 SAFE_SNPRINTF(error_msg, error_msg_size,
224 "Invalid palette '%s'. Valid palettes: standard, blocks, digital, minimal, cool, custom",
225 value_str);
226 }
227 return -1;
228 }
229}

◆ validate_opt_password()

int validate_opt_password ( const char *  value_str,
char *  error_msg,
size_t  error_msg_size 
)

Validate password (8-256 characters, no null bytes) Returns 0 on success, -1 on error

Definition at line 489 of file validation.c.

489 {
490 if (!value_str) {
491 if (error_msg) {
492 SAFE_SNPRINTF(error_msg, error_msg_size, "Password value is required");
493 }
494 return -1;
495 }
496
497 size_t len = strlen(value_str);
498 if (len < 8) {
499 if (error_msg) {
500 SAFE_SNPRINTF(error_msg, error_msg_size, "Password too short (%zu chars). Must be at least 8 characters.", len);
501 }
502 return -1;
503 }
504 if (len > 256) {
505 if (error_msg) {
506 SAFE_SNPRINTF(error_msg, error_msg_size, "Password too long (%zu chars). Must be at most 256 characters.", len);
507 }
508 return -1;
509 }
510
511 // Note: No need to check for embedded null bytes - strlen() already stopped at the first null,
512 // so by definition there are no null bytes within [0, len).
513
514 return 0;
515}

◆ validate_opt_port()

int validate_opt_port ( const char *  value_str,
char *  error_msg,
size_t  error_msg_size 
)

Validate port number (1-65535) Returns 0 on success, non-zero on error

Definition at line 74 of file validation.c.

74 {
75 if (!value_str || strlen(value_str) == 0) {
76 if (error_msg) {
77 SAFE_SNPRINTF(error_msg, error_msg_size, "Port value is required");
78 }
79 return -1;
80 }
81
82 // Use safe integer parsing with range validation
83 uint16_t port_num;
84 if (parse_port(value_str, &port_num) != ASCIICHAT_OK) {
85 if (error_msg) {
86 SAFE_SNPRINTF(error_msg, error_msg_size, "Invalid port value '%s'. Port must be a number between 1 and 65535.",
87 value_str);
88 }
89 return -1;
90 }
91 return 0;
92}
asciichat_error_t parse_port(const char *str, uint16_t *out_port)
Definition parsing.c:251

References parse_port().

◆ validate_opt_positive_int()

int validate_opt_positive_int ( const char *  value_str,
char *  error_msg,
size_t  error_msg_size 
)

Validate positive integer Returns parsed value on success, -1 on error

Definition at line 121 of file validation.c.

121 {
122 int result = validate_int_range(value_str, 1, INT_MAX, "Value", error_msg, error_msg_size);
123 return (result == INT_MIN) ? -1 : result;
124}

◆ validate_opt_reconnect()

int validate_opt_reconnect ( const char *  value_str,
char *  error_msg,
size_t  error_msg_size 
)

Validate reconnect value (off, auto, 0, -1, or 1-999) Returns: 0 for "off" (no retries) -1 for "auto" (unlimited retries) 1-999 for specific retry count INT_MIN on parse error

Definition at line 410 of file validation.c.

410 {
411 if (!value_str || strlen(value_str) == 0) {
412 if (error_msg) {
413 SAFE_SNPRINTF(error_msg, error_msg_size, "Reconnect value is required");
414 }
415 return INT_MIN;
416 }
417
418 // Check for string values first
419 if (platform_strcasecmp(value_str, "off") == 0) {
420 return 0; // No retries
421 }
422 if (platform_strcasecmp(value_str, "auto") == 0) {
423 return -1; // Unlimited retries
424 }
425
426 // Parse as integer
427 int val = strtoint_safe(value_str);
428 if (val == INT_MIN) {
429 if (error_msg) {
430 SAFE_SNPRINTF(error_msg, error_msg_size, "Invalid reconnect value '%s'. Use 'off', 'auto', or a number 0-999.",
431 value_str);
432 }
433 return INT_MIN;
434 }
435
436 // 0 means off, -1 means auto, 1-999 is valid range
437 if (val == 0) {
438 return 0; // No retries
439 }
440 if (val == -1) {
441 return -1; // Unlimited retries
442 }
443 if (val < 1 || val > 999) {
444 if (error_msg) {
445 SAFE_SNPRINTF(error_msg, error_msg_size, "Invalid reconnect count '%s'. Must be 'off', 'auto', or 1-999.",
446 value_str);
447 }
448 return INT_MIN;
449 }
450 return val;
451}

References platform_strcasecmp(), and strtoint_safe().

◆ validate_opt_render_mode()

int validate_opt_render_mode ( const char *  value_str,
char *  error_msg,
size_t  error_msg_size 
)

Validate render mode string Returns parsed render mode on success, -1 on error

Definition at line 173 of file validation.c.

173 {
174 if (!value_str) {
175 if (error_msg) {
176 SAFE_SNPRINTF(error_msg, error_msg_size, "Render mode value is required");
177 }
178 return -1;
179 }
180
181 if (strcmp(value_str, "foreground") == 0 || strcmp(value_str, "fg") == 0) {
182 return RENDER_MODE_FOREGROUND;
183 }
184 if (strcmp(value_str, "background") == 0 || strcmp(value_str, "bg") == 0) {
185 return RENDER_MODE_BACKGROUND;
186 }
187 if (strcmp(value_str, "half-block") == 0 || strcmp(value_str, "halfblock") == 0) {
188 return RENDER_MODE_HALF_BLOCK;
189 }
190 if (error_msg) {
191 SAFE_SNPRINTF(error_msg, error_msg_size,
192 "Invalid render mode '%s'. Valid modes: foreground, background, half-block", value_str);
193 }
194 return -1;
195}

◆ validate_opt_volume()

float validate_opt_volume ( const char *  value_str,
char *  error_msg,
size_t  error_msg_size 
)

Validate volume value (0.0-1.0) Returns parsed value on success, -1.0f on error

Definition at line 350 of file validation.c.

350 {
351 if (!value_str || strlen(value_str) == 0) {
352 if (error_msg) {
353 SAFE_SNPRINTF(error_msg, error_msg_size, "Volume value is required");
354 }
355 return -1.0f;
356 }
357
358 char *endptr;
359 float val = strtof(value_str, &endptr);
360 if (*endptr != '\0' || value_str == endptr) {
361 if (error_msg) {
362 SAFE_SNPRINTF(error_msg, error_msg_size, "Invalid volume value '%s'. Must be a number.", value_str);
363 }
364 return -1.0f;
365 }
366 if (val < 0.0f || val > 1.0f) {
367 if (error_msg) {
368 SAFE_SNPRINTF(error_msg, error_msg_size, "Volume must be between 0.0 and 1.0 (got %.2f)", val);
369 }
370 return -1.0f;
371 }
372 return val;
373}

◆ validate_port_callback()

bool validate_port_callback ( const void *  options_struct,
char **  error_msg 
)

Validate port option callback (matches option_descriptor validate signature) Used during options parsing to validate port values with PCRE2

Definition at line 98 of file validation.c.

98 {
99 const options_t *opts = (const options_t *)options_struct;
100
101 // Port is stored as an int, but we need to validate it as a string
102 // The issue is that strtol() already accepted invalid formats like " 80", "+80", "0123"
103 // So we can't validate after parsing - we need to prevent the parse in the first place
104 // This callback runs AFTER parsing, so it's too late
105
106 // Instead, check if the port value is in range (this will catch the range but not format issues)
107 if (opts->port < 1 || opts->port > 65535) {
108 if (error_msg) {
109 *error_msg = platform_strdup("Port must be between 1 and 65535");
110 }
111 return false;
112 }
113
114 return true;
115}
char * platform_strdup(const char *s)

References platform_strdup().