static void managesieve_parser_save_arg(struct managesieve_parser *parser,
				 const unsigned char *data, size_t size)
{
	struct managesieve_arg *arg;
	char *str;

	arg = managesieve_arg_create(parser);

	switch (parser->cur_type) {
	case ARG_PARSE_ATOM:
		/* simply save the string */
		arg->type = MANAGESIEVE_ARG_ATOM;
		arg->_data.str = p_strndup(parser->pool, data, size);
		arg->str_len = size;
		break;
	case ARG_PARSE_STRING:
		/* data is quoted and may contain escapes. */
		if ((parser->flags & MANAGESIEVE_PARSE_FLAG_STRING_STREAM) != 0) {
			arg->type = MANAGESIEVE_ARG_STRING_STREAM;
			arg->_data.str_stream = parser->str_stream;
		} else {
			i_assert(size > 0);

			arg->type = MANAGESIEVE_ARG_STRING;
			str = p_strndup(parser->pool, data+1, size-1);

			/* remove the escapes */
			if (parser->str_first_escape >= 0 &&
				  (parser->flags & MANAGESIEVE_PARSE_FLAG_NO_UNESCAPE) == 0) {
				/* -1 because we skipped the '"' prefix */
				str_unescape(str + parser->str_first_escape-1);
			}

			arg->_data.str = str;
			arg->str_len = strlen(str);
		}
		break;
	case ARG_PARSE_LITERAL_DATA:
		if ((parser->flags & MANAGESIEVE_PARSE_FLAG_STRING_STREAM) != 0) {
			arg->type = MANAGESIEVE_ARG_STRING_STREAM;
			arg->_data.str_stream = parser->str_stream;
		} else if ((parser->flags & MANAGESIEVE_PARSE_FLAG_LITERAL_TYPE) != 0) {
			arg->type = MANAGESIEVE_ARG_LITERAL;
			arg->_data.str = p_strndup(parser->pool, data, size);
			arg->str_len = size;
		} else {
			arg->type = MANAGESIEVE_ARG_STRING;
			arg->_data.str = p_strndup(parser->pool, data, size);
			arg->str_len = size;
		}
		break;
	default:
		i_unreached();
	}

	parser->cur_type = ARG_PARSE_NONE;
}
int rfc822_parse_content_param(struct rfc822_parser_context *ctx,
			       const char **key_r, const char **value_r)
{
	string_t *tmp;
	size_t value_pos;
	int ret;

	/* .. := *(";" parameter)
	   parameter := attribute "=" value
	   attribute := token
	   value := token / quoted-string
	*/
	*key_r = NULL;
	*value_r = NULL;

	if (ctx->data == ctx->end)
		return 0;
	if (*ctx->data != ';')
		return -1;
	ctx->data++;

	if (rfc822_skip_lwsp(ctx) <= 0)
		return -1;

	tmp = t_str_new(64);
	if (rfc822_parse_mime_token(ctx, tmp) <= 0)
		return -1;
	str_append_c(tmp, '\0');
	value_pos = str_len(tmp);

	if (*ctx->data != '=')
		return -1;
	ctx->data++;

	if ((ret = rfc822_skip_lwsp(ctx)) <= 0) {
		/* broken / no value */
	} else if (*ctx->data == '"') {
		ret = rfc822_parse_quoted_string(ctx, tmp);
		(void)str_unescape(str_c_modifiable(tmp) + value_pos);
	} else if (ctx->data != ctx->end && *ctx->data == '=') {
		/* workaround for broken input:
		   name==?utf-8?b?...?= */
		while (ctx->data != ctx->end && *ctx->data != ';' &&
		       *ctx->data != ' ' && *ctx->data != '\t' &&
		       *ctx->data != '\r' && *ctx->data != '\n') {
			str_append_c(tmp, *ctx->data);
			ctx->data++;
		}
	} else {
		ret = rfc822_parse_mime_token(ctx, tmp);
	}

	*key_r = str_c(tmp);
	*value_r = *key_r + value_pos;
	return ret < 0 ? -1 : 1;
}
Exemple #3
0
ADTList list_from_str(char *str, void *(*from_str)(char *)) {
    ADTList list = list_new();
    int len = (int) strlen(str);
    for (int i = 0, escape = 0, start = 0; i <= len; i++) {
        if ((str[i] == ',' && !escape) || (i == len && len > 0)) {
            char *substr = str_substr(str, start, i - start);
            char *unescaped = str_unescape(substr);
            list_append(list, from_str(unescaped));
            start = i + 1;
            free(unescaped);
            free(substr);
        }
        if (str[i] == '\\' && !escape)
            escape = 1;
        else
            escape = 0;
    }
    return list;
}
Exemple #4
0
int str_unescape_next(const char **str, const char **unescaped_r)
{
	const char *p;
	char *escaped;
	bool esc_found = FALSE;

	for (p = *str; *p != '\0'; p++) {
		if (*p == '"')
			break;
		else if (*p == '\\') {
			if (p[1] == '\0')
				return -1;
			esc_found = TRUE;
			p++;
		}
	}
	if (*p != '"')
		return -1;
	escaped = p_strdup_until(unsafe_data_stack_pool, *str, p);
	*str = p+1;
	*unescaped_r = !esc_found ? escaped : str_unescape(escaped);
	return 0;
}
Exemple #5
0
static bool lsb_distro_get(const char *path, const char **name_r)
{
	const char *data, *const *p, *str, *end;

	if (!readfile(path, &data))
		return FALSE;

	for (p = t_strsplit(data, "\n"); *p != NULL; p++) {
		if (strncmp(*p, "DISTRIB_DESCRIPTION=", 20) == 0)
			break;
	}
	if (*p == NULL)
		return FALSE;

	str = t_strcut(*p + 20, '\n');
	if (*str != '"')
		*name_r = str;
	else {
		end = strrchr(++str, '"');
		*name_r = str_unescape(p_strdup_until(unsafe_data_stack_pool,
						      str, end));
	}
	return TRUE;
}
Exemple #6
0
static void imap_parser_save_arg(struct imap_parser *parser,
				 const unsigned char *data, size_t size)
{
	struct imap_arg *arg;
	char *str;

	arg = imap_arg_create(parser);

	switch (parser->cur_type) {
	case ARG_PARSE_ATOM:
	case ARG_PARSE_TEXT:
		if (size == 3 && i_memcasecmp(data, "NIL", 3) == 0) {
			/* NIL argument. it might be an actual NIL, but if
			   we're reading astring, it's an atom and we can't
			   lose its case. */
			arg->type = IMAP_ARG_NIL;
		} else {
			/* simply save the string */
			arg->type = IMAP_ARG_ATOM;
		}
		arg->_data.str = imap_parser_strdup(parser, data, size);
		arg->str_len = size;
		break;
	case ARG_PARSE_STRING:
		/* data is quoted and may contain escapes. */
		i_assert(size > 0);

		arg->type = IMAP_ARG_STRING;
		str = p_strndup(parser->pool, data+1, size-1);

		/* remove the escapes */
		if (parser->str_first_escape >= 0 &&
		    (parser->flags & IMAP_PARSE_FLAG_NO_UNESCAPE) == 0) {
			/* -1 because we skipped the '"' prefix */
			(void)str_unescape(str + parser->str_first_escape-1);
		}
		arg->_data.str = str;
		arg->str_len = strlen(str);
		break;
	case ARG_PARSE_LITERAL_DATA:
		if ((parser->flags & IMAP_PARSE_FLAG_LITERAL_SIZE) != 0) {
			/* save literal size */
			arg->type = parser->literal_nonsync ?
				IMAP_ARG_LITERAL_SIZE_NONSYNC :
				IMAP_ARG_LITERAL_SIZE;
			arg->_data.literal_size = parser->literal_size;
			arg->literal8 = parser->literal8;
			break;
		}
		/* fall through */
	case ARG_PARSE_LITERAL_DATA_FORCED:
		if ((parser->flags & IMAP_PARSE_FLAG_LITERAL_TYPE) != 0)
			arg->type = IMAP_ARG_LITERAL;
		else
			arg->type = IMAP_ARG_STRING;
		arg->_data.str = imap_parser_strdup(parser, data, size);
		arg->literal8 = parser->literal8;
		arg->str_len = size;
		break;
	default:
                i_unreached();
	}

	parser->cur_type = ARG_PARSE_NONE;
}
Exemple #7
0
bool settings_read_i(const char *path, const char *section,
		     settings_callback_t *callback,
		     settings_section_callback_t *sect_callback, void *context,
		     const char **error_r)
{
	/* pretty horrible code, but v2.0 will have this rewritten anyway.. */
	struct input_stack root, *input;
	const char *errormsg, *next_section, *name, *last_section_path = NULL;
	char *line, *key, *p, quote;
	string_t *full_line;
	size_t len;
	int fd, last_section_line = 0, skip, sections, root_section;

	fd = open(path, O_RDONLY);
	if (fd < 0) {
		*error_r = t_strdup_printf(
			"Can't open configuration file %s: %m", path);
		return FALSE;
	}

	if (section == NULL) {
		skip = 0;
                next_section = NULL;
	} else {
		skip = 1;
		next_section = t_strcut(section, '/');
	}

	memset(&root, 0, sizeof(root));
	root.path = path;
	input = &root;

	full_line = t_str_new(512);
	sections = 0; root_section = 0; errormsg = NULL;
	input->input = i_stream_create_fd_autoclose(&fd, (size_t)-1);
	i_stream_set_return_partial_line(input->input, TRUE);
prevfile:
	while ((line = i_stream_read_next_line(input->input)) != NULL) {
		input->linenum++;

		/* @UNSAFE: line is modified */

		/* skip whitespace */
		while (IS_WHITE(*line))
			line++;

		/* ignore comments or empty lines */
		if (*line == '#' || *line == '\0')
			continue;

		/* strip away comments. pretty kludgy way really.. */
		for (p = line; *p != '\0'; p++) {
			if (*p == '\'' || *p == '"') {
				quote = *p;
				for (p++; *p != quote && *p != '\0'; p++) {
					if (*p == '\\' && p[1] != '\0')
						p++;
				}
				if (*p == '\0')
					break;
			} else if (*p == '#') {
				if (!IS_WHITE(p[-1])) {
					i_warning("Configuration file %s line %u: "
						  "Ambiguous '#' character in line, treating it as comment. "
						  "Add a space before it to remove this warning.",
						  input->path, input->linenum);
				}
				*p = '\0';
				break;
			}
		}

		/* remove whitespace from end of line */
		len = strlen(line);
		while (IS_WHITE(line[len-1]))
			len--;
		line[len] = '\0';

		if (len > 0 && line[len-1] == '\\') {
			/* continues in next line */
			len--;
			while (IS_WHITE(line[len-1]))
				len--;
			str_append_n(full_line, line, len);
			str_append_c(full_line, ' ');
			continue;
		}
		if (str_len(full_line) > 0) {
			str_append(full_line, line);
			line = str_c_modifiable(full_line);
		}

		/* a) key = value
		   b) section_type [section_name] {
		   c) } */
		key = line;
		while (!IS_WHITE(*line) && *line != '\0' && *line != '=')
			line++;
		if (IS_WHITE(*line)) {
			*line++ = '\0';
			while (IS_WHITE(*line)) line++;
		}

		if (strcmp(key, "!include_try") == 0 ||
		    strcmp(key, "!include") == 0) {
			if (settings_include(fix_relative_path(line, input),
					     &input,
					     strcmp(key, "!include_try") == 0,
					     &errormsg) == 0)
				goto prevfile;
		} else if (*line == '=') {
			/* a) */
			*line++ = '\0';
			while (IS_WHITE(*line)) line++;

			len = strlen(line);
			if (len > 0 &&
			    ((*line == '"' && line[len-1] == '"') ||
			     (*line == '\'' && line[len-1] == '\''))) {
				line[len-1] = '\0';
				line = str_unescape(line+1);
			}

			errormsg = skip ? NULL :
				callback(key, line, context);
		} else if (strcmp(key, "}") != 0 || *line != '\0') {
			/* b) + errors */
			line[-1] = '\0';

			if (*line == '{')
				name = "";
			else {
				name = line;
				while (!IS_WHITE(*line) && *line != '\0')
					line++;

				if (*line != '\0') {
					*line++ = '\0';
					while (IS_WHITE(*line))
						line++;
				}
			}

			if (*line != '{')
				errormsg = "Expecting '='";
			else {
				sections++;
				if (next_section != NULL &&
				    strcmp(next_section, name) == 0) {
					section += strlen(next_section);
					if (*section == '\0') {
						skip = 0;
						next_section = NULL;
						root_section = sections;
					} else {
						i_assert(*section == '/');
						section++;
						next_section =
							t_strcut(section, '/');
					}
				}

				if (skip > 0)
					skip++;
				else {
					skip = sect_callback == NULL ? 1 :
						!sect_callback(key, name,
							       context,
							       &errormsg);
					if (errormsg != NULL &&
					    last_section_line != 0) {
						errormsg = t_strdup_printf(
							SECTION_ERRORMSG,
							errormsg,
							last_section_path,
							last_section_line);
					}
				}
				last_section_path = input->path;
				last_section_line = input->linenum;
			}
		} else {
			/* c) */
			if (sections == 0)
				errormsg = "Unexpected '}'";
			else {
				if (skip > 0)
					skip--;
				else {
					i_assert(sect_callback != NULL);
					sect_callback(NULL, NULL, context,
						      &errormsg);
					if (root_section == sections &&
					    errormsg == NULL) {
						/* we found the section,
						   now quit */
						break;
					}
				}
				last_section_path = input->path;
				last_section_line = input->linenum;
				sections--;
			}
		}

		if (errormsg != NULL) {
			*error_r = t_strdup_printf(
				"Error in configuration file %s line %d: %s",
				input->path, input->linenum, errormsg);
			break;
		}
		str_truncate(full_line, 0);
	}

	i_stream_destroy(&input->input);
	input = input->prev;
	if (line == NULL && input != NULL)
		goto prevfile;

	return errormsg == NULL;
}
Exemple #8
0
void test_strescape(void)
{
	static struct strinput unesc[] = {
		{ "foo", "foo" },
		{ "\\\\\\\\\\\"\\\"\\\'\\\'", "\\\\\"\"\'\'" },
		{ "\\a\\n\\r\\", "anr" }
	};
	static struct strinput tabesc[] = {
		{ "foo", "foo" },
		{ "\001", "\0011" },
		{ "\t", "\001t" },
		{ "\r", "\001r" },
		{ "\n", "\001n" },
		{ "\001\001\t\t\r\r\n\n", "\0011\0011\001t\001t\001r\001r\001n\001n" }
	};
	unsigned char buf[1 << CHAR_BIT];
	const char *escaped, *tabstr;
	string_t *str;
	unsigned int i;

	test_begin("str_escape");
	for (i = 1; i < sizeof(buf); i++)
		buf[i-1] = i;
	buf[i-1] = '\0';

	escaped = str_escape((char *)buf);
	test_assert(strlen(escaped) == (1 << CHAR_BIT) - 1 + 3);
	test_assert(escaped['\"'-1] == '\\'); /* 34 */
	test_assert(escaped['\"'] == '\"');
	test_assert(escaped['\''+1-1] == '\\'); /* 39 */
	test_assert(escaped['\''+1] == '\'');
	test_assert(escaped['\\'+2-1] == '\\'); /* 92 */
	test_assert(escaped['\\'+2] == '\\');
	test_assert(strcmp(str_escape("\\\\\"\"\'\'"),
			   "\\\\\\\\\\\"\\\"\\\'\\\'") == 0);
	test_end();

	str = t_str_new(256);
	test_begin("str_unescape");
	for (i = 0; i < N_ELEMENTS(unesc); i++) {
		test_assert(strcmp(str_unescape(t_strdup_noconst(unesc[i].input)),
				   unesc[i].output) == 0);
		str_truncate(str, 0);
		str_append_unescaped(str, unesc[i].input, strlen(unesc[i].input));
		test_assert(strcmp(str_c(str), unesc[i].output) == 0);
	}
	test_end();

	test_begin("str_tabescape");
	for (i = 0; i < N_ELEMENTS(tabesc); i++) {
		test_assert(strcmp(str_tabunescape(t_strdup_noconst(tabesc[i].output)),
				   tabesc[i].input) == 0);
		test_assert(strcmp(str_tabescape(tabesc[i].input),
				   tabesc[i].output) == 0);
		str_truncate(str, 0);
		str_append_tabunescaped(str, tabesc[i].output, strlen(tabesc[i].output));
		test_assert(strcmp(str_c(str), tabesc[i].input) == 0);
	}
	str_truncate(str, 0);
	tabstr = "\0012\001l\001";
	str_append_tabunescaped(str, tabstr, strlen(tabstr));
	test_assert(strcmp(str_c(str), "2l") == 0);
	test_assert(strcmp(str_c(str), str_tabunescape(t_strdup_noconst(tabstr))) == 0);
	test_end();
}