<commit_before>/*
 * Copyright (c) 2014 <NAME> <<EMAIL>>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

/* Implementation file for handling various TDS tokens. */
#include <string.h>
#include <stdlib.h>

#include "constants.h"
#include "tds_buf.h"
#include "tds_log.h"
#include "tds_tokens.h"
#include "utils.h"

#define TOKEN_COLMETADATA 0x81
#define TOKEN_ERROR 0xaa
#define TOKEN_INFO 0xab
#define TOKEN_LOGINACK 0xad
#define TOKEN_ROW 0xd1
#define TOKEN_ENVCHANGE 0xe3
#define TOKEN_DONE 0xfd

enum {
	EC_DATABASE = 1,
	EC_LANGUAGE = 2,
	EC_PKTSIZE = 4,
	EC_COLLATION = 7
};

static void handle_envchange(struct connection *conn, uint16_t token_len);
static void handle_message(struct connection *conn, const char *type, uint16_t token_len);
static void handle_loginack(struct connection *conn, uint16_t token_len);
static void handle_done(struct connection *conn);

/* Token: DONE (2.2.7.4) */
static void
handle_done(struct connection *conn)
{
	uint16_t status;
	uint16_t current_command;
	uint32_t row_count;

	status = buf_get16_le(conn);
	current_command = buf_get16_le(conn);
	row_count = buf_get32_le(conn);
	tds_debug(0, "Done (CurCmd: %d)\n", current_command);
	tds_debug(0, "Done, status %d, rows affected\n", status, row_count);

	if (status == 0) {
		if (conn->stage == TDS_LOGGING_IN) {
			conn->stage = TDS_LOGGED_IN;
		} else if (conn->stage == TDS_QUERY) {
			if (conn->on_done)
				conn->on_done(conn, row_count);
		}
	}

}

static void
handle_message(struct connection *conn, const char *type, uint16_t token_len)
{
	uint32_t number;
	uint8_t state;
	uint8_t severity;
	uint16_t text_len;
	char text[512];
	uint8_t sname_len;
	char server_name[256];
	uint8_t pname_len;
	char proc_name[256];
	uint16_t line;

	*text = *server_name = *proc_name = 0;

	tds_debug(0, "+%s: %d\n", type, token_len);
	number = buf_get32_le(conn);
	state = buf_get8(conn);
	severity = buf_get8(conn);
	text_len = buf_get16_le(conn) * 2;
	ucs2_to_str(buf_getraw(conn, text_len), text_len, text, sizeof(text));
	sname_len = buf_get8(conn) * 2;
	ucs2_to_str(buf_getraw(conn, sname_len), sname_len, server_name, sizeof(server_name));
	pname_len = buf_get8(conn) * 2;
	ucs2_to_str(buf_getraw(conn, pname_len), pname_len, proc_name, sizeof(proc_name));
	line = buf_get16_le(conn);

	if (number > 0 && severity > 0) {
		tds_debug(0, "Msg %d, Level %d, State %d\n", number, severity, state);
		tds_debug(0, "Server '%s'", server_name);
		if (*proc_name != '\0')
			tds_debug(0, ", Procedure '%s'", proc_name);
		if (line > 0)
			tds_debug(0, ", Line %d\n", line);
		tds_debug(0, "%s\n", text);
		exit(1);
	} else {
		tds_debug(0, "%s\n", text);
	}
}

/* 2.2.7.11 */
static void
handle_loginack(struct connection *conn, uint16_t token_len)
{
	uint8_t interface;
	uint32_t tds_version;
	uint8_t len;
	char prog_name[256];
	uint8_t major, minor;
	uint16_t build;

	tds_debug(0, "+LOGINACK: %d bytes\n", token_len);
	interface = buf_get8(conn);
	tds_version = buf_get32_le(conn);
	tds_debug(0, "Version: %x\n", tds_version);
	len = buf_get8(conn) * 2;
	ucs2_to_str(buf_getraw(conn, len), len, prog_name, sizeof(prog_name));
	tds_debug(0, "Prog: %s\n", prog_name);
	major = buf_get8(conn);
	minor = buf_get8(conn);
	build = buf_get16_le(conn);
	tds_debug(0, "Major: %d Minor: %d Build: %d\n", major, minor, build);
}

/* 2.2.7.8 */
static void
handle_envchange(struct connection *conn, uint16_t token_len)
{
	uint8_t change_type;
	char *dest;
	char old[256];
	uint8_t len;

	change_type = buf_get8(conn);
	tds_debug(0, "+ENVCHANGE: (%d) %d bytes\n", change_type, token_len);

	if (change_type == EC_COLLATION) {
		unsigned char o_col[5];

		/* Grab new collation info */
		len = buf_get8(conn);
		memcpy(conn->env.collation, buf_getraw(conn, len), len);

		/* TODO What to do with old collation info? */
		len = buf_get8(conn);
		memcpy(o_col, buf_getraw(conn, len), len);
		return;
	}

	if (change_type != EC_DATABASE && change_type != EC_LANGUAGE &&
	    change_type != EC_PKTSIZE) {
		tds_debug(0, "  Change: %d (unknown)\n", change_type);
		return;
	}

	if (change_type == EC_DATABASE) {
		dest = conn->env.database;
	} else if (change_type == EC_LANGUAGE) {
		dest = conn->env.language;
	}

	len = buf_get8(conn) * 2;
	dest = malloc(len + 1);
	ucs2_to_str(buf_getraw(conn, len), len, dest, len);
	dest[len] = '\0';

	old[0] = '\0';
	len = buf_get8(conn) * 2;
	ucs2_to_str(buf_getraw(conn, len), len, old, sizeof(old));
	tds_debug(0, "%s -> %s\n", old, dest);

	if (change_type == EC_PKTSIZE) {
		conn->env.packet_size = atoi(dest);
		free(dest);
	}
}
<commit_msg>Lower the verbosity when processing the ENVCHANGE token. At this point it, we only need a verbose message when an ENVCHANGE change type is unknown.<commit_after>/*
 * Copyright (c) 2014 <NAME> <<EMAIL>>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

/* Implementation file for handling various TDS tokens. */
#include <string.h>
#include <stdlib.h>

#include "constants.h"
#include "tds_buf.h"
#include "tds_log.h"
#include "tds_tokens.h"
#include "utils.h"

#define TOKEN_COLMETADATA 0x81
#define TOKEN_ERROR 0xaa
#define TOKEN_INFO 0xab
#define TOKEN_LOGINACK 0xad
#define TOKEN_ROW 0xd1
#define TOKEN_ENVCHANGE 0xe3
#define TOKEN_DONE 0xfd

enum {
	EC_DATABASE = 1,
	EC_LANGUAGE = 2,
	EC_PKTSIZE = 4,
	EC_COLLATION = 7
};

static void handle_envchange(struct connection *conn, uint16_t token_len);
static void handle_message(struct connection *conn, const char *type, uint16_t token_len);
static void handle_loginack(struct connection *conn, uint16_t token_len);
static void handle_done(struct connection *conn);

/* Token: DONE (2.2.7.4) */
static void
handle_done(struct connection *conn)
{
	uint16_t status;
	uint16_t current_command;
	uint32_t row_count;

	status = buf_get16_le(conn);
	current_command = buf_get16_le(conn);
	row_count = buf_get32_le(conn);
	tds_debug(0, "Done (CurCmd: %d)\n", current_command);
	tds_debug(0, "Done, status %d, rows affected\n", status, row_count);

	if (status == 0) {
		if (conn->stage == TDS_LOGGING_IN) {
			conn->stage = TDS_LOGGED_IN;
		} else if (conn->stage == TDS_QUERY) {
			if (conn->on_done)
				conn->on_done(conn, row_count);
		}
	}

}

static void
handle_message(struct connection *conn, const char *type, uint16_t token_len)
{
	uint32_t number;
	uint8_t state;
	uint8_t severity;
	uint16_t text_len;
	char text[512];
	uint8_t sname_len;
	char server_name[256];
	uint8_t pname_len;
	char proc_name[256];
	uint16_t line;

	*text = *server_name = *proc_name = 0;

	tds_debug(0, "+%s: %d\n", type, token_len);
	number = buf_get32_le(conn);
	state = buf_get8(conn);
	severity = buf_get8(conn);
	text_len = buf_get16_le(conn) * 2;
	ucs2_to_str(buf_getraw(conn, text_len), text_len, text, sizeof(text));
	sname_len = buf_get8(conn) * 2;
	ucs2_to_str(buf_getraw(conn, sname_len), sname_len, server_name, sizeof(server_name));
	pname_len = buf_get8(conn) * 2;
	ucs2_to_str(buf_getraw(conn, pname_len), pname_len, proc_name, sizeof(proc_name));
	line = buf_get16_le(conn);

	if (number > 0 && severity > 0) {
		tds_debug(0, "Msg %d, Level %d, State %d\n", number, severity, state);
		tds_debug(0, "Server '%s'", server_name);
		if (*proc_name != '\0')
			tds_debug(0, ", Procedure '%s'", proc_name);
		if (line > 0)
			tds_debug(0, ", Line %d\n", line);
		tds_debug(0, "%s\n", text);
		exit(1);
	} else {
		tds_debug(0, "%s\n", text);
	}
}

/* 2.2.7.11 */
static void
handle_loginack(struct connection *conn, uint16_t token_len)
{
	uint8_t interface;
	uint32_t tds_version;
	uint8_t len;
	char prog_name[256];
	uint8_t major, minor;
	uint16_t build;

	tds_debug(0, "+LOGINACK: %d bytes\n", token_len);
	interface = buf_get8(conn);
	tds_version = buf_get32_le(conn);
	tds_debug(0, "Version: %x\n", tds_version);
	len = buf_get8(conn) * 2;
	ucs2_to_str(buf_getraw(conn, len), len, prog_name, sizeof(prog_name));
	tds_debug(0, "Prog: %s\n", prog_name);
	major = buf_get8(conn);
	minor = buf_get8(conn);
	build = buf_get16_le(conn);
	tds_debug(0, "Major: %d Minor: %d Build: %d\n", major, minor, build);
}

/* 2.2.7.8 */
static void
handle_envchange(struct connection *conn, uint16_t token_len)
{
	uint8_t change_type;
	char *dest;
	char old[256];
	uint8_t len;

	change_type = buf_get8(conn);

	if (change_type == EC_COLLATION) {
		unsigned char o_col[5];

		/* Grab new collation info */
		len = buf_get8(conn);
		memcpy(conn->env.collation, buf_getraw(conn, len), len);

		/* TODO What to do with old collation info? */
		len = buf_get8(conn);
		memcpy(o_col, buf_getraw(conn, len), len);
		return;
	}

	if (change_type != EC_DATABASE && change_type != EC_LANGUAGE &&
	    change_type != EC_PKTSIZE) {
		tds_debug(0, "+ENVCHANGE: (change type unknown: %d) %d bytes\n",
		    change_type, token_len);
		return;
	}

	if (change_type == EC_DATABASE) {
		dest = conn->env.database;
	} else if (change_type == EC_LANGUAGE) {
		dest = conn->env.language;
	}

	len = buf_get8(conn) * 2;
	dest = malloc(len + 1);
	ucs2_to_str(buf_getraw(conn, len), len, dest, len);
	dest[len] = '\0';

	old[0] = '\0';
	len = buf_get8(conn) * 2;
	ucs2_to_str(buf_getraw(conn, len), len, old, sizeof(old));
	tds_debug(1, "ENVCHANGE (change type %d): %s -> %s\n", change_type, old,
	    dest);

	if (change_type == EC_PKTSIZE) {
		conn->env.packet_size = atoi(dest);
		free(dest);
	}
}

{'fraction_non_alphanumeric': 0.1347691150192796, 'fraction_numerical': 0.028684284773817362, 'mean_word_length': 4.751216873985938, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 39, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 6, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '708073', 'n_tokens_mistral': 4478, 'n_tokens_neox': 4172, 'n_words': 1095}