#include "lib.h"
#include "str.h"
#include "rfc2822.h"
#include "message-header-encode.h"
#include <stdio.h>
#include <ctype.h>
bool rfc2822_header_field_name_verify
(const char *field_name, unsigned int len)
{
const char *p = field_name;
const char *pend = p + len;
while ( p < pend ) {
if ( *p < 33 || *p == ':' )
return FALSE;
p++;
}
return TRUE;
}
bool rfc2822_header_field_body_verify
(const char *field_body, unsigned int len)
{
const char *p = field_body;
const char *pend = p + len;
while ( p < pend ) {
if ( *p == '\0' || *p == '\r' || *p == '\n' || ((unsigned char)*p) > 127 )
return FALSE;
p++;
}
return TRUE;
}
const char *rfc2822_header_field_name_sanitize(const char *name)
{
char *result = t_strdup_noconst(name);
char *p;
result = str_lcase(result);
p = result;
*p = i_toupper(*p);
while ( *p != '\0' ) {
if ( *p == '-' ) {
p++;
if ( *p != '\0' )
*p = i_toupper(*p);
continue;
}
p++;
}
return result;
}
static inline bool rfc2822_write(FILE *f, const char *data, size_t len)
{
return ( fwrite(data, len, 1, f) == 1 );
}
int rfc2822_header_field_write
(FILE *f, const char *name, const char *body)
{
static const unsigned int max_line = 80;
const char *bp = body;
const char *sp = body;
const char *wp = NULL;
const char *nlp = NULL;
unsigned int line_len = strlen(name);
int len = 0;
if ( !rfc2822_write(f, name, line_len) || !rfc2822_write(f, ": ", 2) )
return -1;
line_len += 2;
len += line_len;
while ( *bp != '\0' ) {
while ( *bp != '\0' && nlp == NULL && (wp == NULL || line_len < max_line) ) {
if ( *bp == ' ' || *bp == '\t' ) {
wp = bp;
} else if ( *bp == '\r' || *bp == '\n' ) {
nlp = bp;
break;
}
bp++; line_len++;
}
if ( *bp == '\0' ) break;
if ( nlp != NULL ) {
while ( *bp == '\r' || *bp == '\n' )
bp++;
if ( !rfc2822_write(f, sp, nlp-sp) )
return -1;
len += nlp-sp;
if ( *bp != '\0' && *bp != ' ' && *bp != '\t' ) {
if ( !rfc2822_write(f, "\r\n\t", 3) )
return -1;
len += 3;
} else {
if ( !rfc2822_write(f, "\r\n", 2) )
return -1;
len += 2;
}
sp = bp;
} else {
if ( !rfc2822_write(f, sp, wp-sp) || !rfc2822_write(f, "\r\n", 2) )
return -1;
len += (wp-sp) + 2;
sp = wp;
}
line_len = bp - sp;
wp = NULL;
nlp = NULL;
}
if ( bp != sp ) {
if ( !rfc2822_write(f, sp, bp-sp) || !rfc2822_write(f, "\r\n", 2) )
return -1;
len += (bp-sp) + 2;
}
return len;
}
int rfc2822_header_field_printf
(FILE *f, const char *name, const char *body_fmt, ...)
{
string_t *body = t_str_new(256);
va_list args;
va_start(args, body_fmt);
str_vprintfa(body, body_fmt, args);
va_end(args);
return rfc2822_header_field_write(f, name, str_c(body));
}
int rfc2822_header_field_utf8_printf
(FILE *f, const char *name, const char *body_fmt, ...)
{
string_t *body = t_str_new(256);
va_list args;
va_start(args, body_fmt);
message_header_encode(t_strdup_vprintf(body_fmt, args), body);
va_end(args);
return rfc2822_header_field_write(f, name, str_c(body));
}