view src/context.cpp @ 26:c6d5b1658f61

Added tag stable-1-0-9 for changeset a2d60f43590b
author Carl Byington <carl@five-ten-sg.com>
date Mon, 06 Feb 2017 12:08:35 -0800
parents 09564d4acd9e
children
line wrap: on
line source

/*

Copyright (c) 2007 Carl Byington - 510 Software Group, released under
the GPL version 3 or any later version at your choice available at
http://www.gnu.org/licenses/gpl-3.0.txt

*/

#include "includes.h"

const char *token_envfrom;
const char *token_include;
const char *token_lbrace;
const char *token_rbrace;
const char *token_rcptto;
const char *token_remove;
const char *token_semi;

string_set	all_strings;	// owns all the strings, only modified by the config loader thread
const int maxlen = 1000;	// used for snprintf buffers

CONFIG::CONFIG() {
	reference_count    = 0;
	generation		   = 0;
	load_time		   = 0;
}


CONFIG::~CONFIG() {
}


bool CONFIG::find(const char *needle, string_set &haystack) {
	string_set::iterator i = haystack.find(needle);
	if (i != haystack.end()) return true;		   // found user@domain.tld key
	const char *x = strchr(needle, '@');
	if (x) {
		x++;
		i = haystack.find(x);
		if (i != haystack.end()) return true;	   // found domain.tld key
		string userpart(needle, x-needle);
		i = haystack.find(userpart.c_str());
		if (i != haystack.end()) return true;	   // found user@ key
	}
	return false;
}


const char *CONFIG::find(const char *needle, string_map &haystack) {
	string_map::iterator i = haystack.find(needle);
	if (i != haystack.end()) return (*i).second;		// found user@domain.tld key
	const char *x = strchr(needle, '@');
	if (x) {
		x++;
		i = haystack.find(x);
		if (i != haystack.end()) return (*i).second;	// found domain.tld key
		string userpart(needle, x-needle);
		i = haystack.find(userpart.c_str());
		if (i != haystack.end()) return (*i).second;	// found user@ key
	}
	return NULL;
}


void CONFIG::dump() {
	printf("rcpt_to {\n");
	for (string_map::iterator i=rcpt_to.begin(); i!=rcpt_to.end(); i++) {
		const char	 *to = (*i).first;
		const char *target = (*i).second;
		if (!target) target = "\"\"";
		bool rem = find_remove(to);
		printf("    %s \t %s%s;\n", to, target, (rem) ? " remove" : "");
	}
	printf("};\n");
	printf("env_from {\n");
	for (string_map::iterator i=env_from.begin(); i!=env_from.end(); i++) {
		const char   *from = (*i).first;
		const char *target = (*i).second;
		if (!target) target = "\"\"";
		printf("    %s \t %s;\n", from, target);
	}
	printf("};\n");
}


////////////////////////////////////////////////
// helper to discard the strings held by a string_set
//
void discard(string_set &s) {
	for (string_set::iterator i=s.begin(); i!=s.end(); i++) {
		free((void*)*i);
	}
	s.clear();
}


////////////////////////////////////////////////
// helper to register a string in a string set
//
const char* register_string(string_set &s, const char *name) {
	string_set::iterator i = s.find(name);
	if (i != s.end()) return *i;
	char *x = strdup(name);
	s.insert(x);
	return x;
}


////////////////////////////////////////////////
// register a global string
//
const char* register_string(const char *name) {
	return register_string(all_strings, name);
}


////////////////////////////////////////////////
// clear all global strings, helper for valgrind checking
//
void clear_strings() {
	discard(all_strings);
}


////////////////////////////////////////////////
//
bool tsa(TOKEN &tok, const char *token);
bool tsa(TOKEN &tok, const char *token) {
	const char *have = tok.next();
	if (have == token) return true;
	tok.token_error(token, have);
	return false;
}


////////////////////////////////////////////////
//
bool parse_rcpt_to(TOKEN &tok, CONFIG &dc);
bool parse_rcpt_to(TOKEN &tok, CONFIG &dc) {
	if (!tsa(tok, token_lbrace)) return false;
	while (true) {
		const char *have = tok.next();
		if (!have) break;
		if (have == token_rbrace) break;
		const char *target = tok.next();
		dc.add_to(have, target);
		target = tok.next();
		if (target == token_remove) {
			dc.add_remove(have);
			target = tok.next();
		}
		if (target != token_semi) {
			tok.token_error(token_semi, target);
			break;
		}
	}
	return tsa(tok, token_semi);
}


////////////////////////////////////////////////
//
bool parse_env_from(TOKEN &tok, CONFIG &dc);
bool parse_env_from(TOKEN &tok, CONFIG &dc) {
	if (!tsa(tok, token_lbrace)) return false;
	while (true) {
		const char *have = tok.next();
		if (!have) break;
		if (have == token_rbrace) break;
		if (have == token_semi) {
			// optional separators
		}
		else {
			const char *target = tok.next();
			dc.add_from(have, target);
		}
	}
	return tsa(tok, token_semi);
}


////////////////////////////////////////////////
// parse a config file
//
bool load_conf(CONFIG &dc, const char *fn) {
	TOKEN tok(fn, &dc.config_files);
	while (true) {
		const char *have = tok.next();
		if (!have) break;
		if (have == token_envfrom) {
			if (!parse_env_from(tok, dc)) {
				tok.token_error("load_conf() failed to parse env_from");
				return false;
			}
		}
		else if (have == token_rcptto) {
			if (!parse_rcpt_to(tok, dc)) {
				tok.token_error("load_conf() failed to parse rcpt_to");
				return false;
			}
		}
		else {
			tok.token_error("env_from/rcpt_to", have);
			return false;
		}
	}
	return true;
}


////////////////////////////////////////////////
// init the tokens
//
void token_init() {
	token_envfrom	 = register_string("env_from");
	token_include	 = register_string("include");
	token_lbrace	 = register_string("{");
	token_rbrace	 = register_string("}");
	token_rcptto	 = register_string("rcpt_to");
	token_remove	 = register_string("remove");
	token_semi		 = register_string(";");
}