1 /*	$NetBSD: is_header.c,v 1.1.1.1 2009/06/23 10:08:46 tron 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