Home | History | Annotate | Line # | Download | only in global
      1 /*	$NetBSD: is_header.c,v 1.2 2025/02/25 19:15:45 christos Exp $	*/
      2 
      3 /*++
      4 /* NAME
      5 /*	is_header 3
      6 /* SUMMARY
      7 /*	message header classification
      8 /* SYNOPSIS
      9 /*	#include <is_header.h>
     10 /*
     11 /*	ssize_t	is_header(string)
     12 /*	const char *string;
     13 /*
     14 /*	ssize_t	is_header_buf(string, len)
     15 /*	const char *string;
     16 /*	ssize_t	len;
     17 /* DESCRIPTION
     18 /*	is_header() examines the given string and returns non-zero (true)
     19 /*	when it begins with a mail header name + optional space + colon.
     20 /*	The result is the length of the mail header name.
     21 /*
     22 /*	is_header_buf() is a more elaborate interface for use with strings
     23 /*	that may not be null terminated.
     24 /* STANDARDS
     25 /*	RFC 822 (ARPA Internet Text Messages)
     26 /* LICENSE
     27 /* .ad
     28 /* .fi
     29 /*	The Secure Mailer license must be distributed with this software.
     30 /* AUTHOR(S)
     31 /*	Wietse Venema
     32 /*	IBM T.J. Watson Research
     33 /*	P.O. Box 704
     34 /*	Yorktown Heights, NY 10598, USA
     35 /*--*/
     36 
     37 /* System library. */
     38 
     39 #include "sys_defs.h"
     40 #include <ctype.h>
     41 
     42 /* Global library. */
     43 
     44 #include "is_header.h"
     45 
     46 /* is_header_buf - determine if this can be a header line */
     47 
     48 ssize_t is_header_buf(const char *str, ssize_t str_len)
     49 {
     50     const unsigned char *cp;
     51     int     state;
     52     int     c;
     53     ssize_t len;
     54 
     55 #define INIT		0
     56 #define IN_CHAR		1
     57 #define IN_CHAR_SPACE	2
     58 #define CU_CHAR_PTR(x)	((const unsigned char *) (x))
     59 
     60     /*
     61      * XXX RFC 2822 Section 4.5, Obsolete header fields: whitespace may
     62      * appear between header label and ":" (see: RFC 822, Section 3.4.2.).
     63      *
     64      * XXX Don't run off the end in case some non-standard iscntrl()
     65      * implementation considers null a non-control character...
     66      */
     67     for (len = 0, state = INIT, cp = CU_CHAR_PTR(str); /* see below */ ; cp++) {
     68 	if (str_len != IS_HEADER_NULL_TERMINATED && str_len-- <= 0)
     69 	    return (0);
     70 	switch (c = *cp) {
     71 	default:
     72 	    if (c == 0 || !ISASCII(c) || ISCNTRL(c))
     73 		return (0);
     74 	    if (state == INIT)
     75 		state = IN_CHAR;
     76 	    if (state == IN_CHAR) {
     77 		len++;
     78 		continue;
     79 	    }
     80 	    return (0);
     81 	case ' ':
     82 	case '\t':
     83 	    if (state == IN_CHAR)
     84 		state = IN_CHAR_SPACE;
     85 	    if (state == IN_CHAR_SPACE)
     86 		continue;
     87 	    return (0);
     88 	case ':':
     89 	    return ((state == IN_CHAR || state == IN_CHAR_SPACE) ? len : 0);
     90 	}
     91     }
     92     /* Redundant return for future proofing. */
     93     return (0);
     94 }
     95