/* ftp_parser.c
 *
 * This file contains functions to parse FTP headers.
 *
 * File begun on 2018-11-13
 *
 * Created by:
 *  - Théo Bertin (theo.bertin@advens.fr)
 *
 * With:
 *  - François Bernard (francois.bernard@isen.yncrea.fr)
 *  - Tianyu Geng (tianyu.geng@isen.yncrea.fr)
 *
 * This file is part of rsyslog.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *       -or-
 *       see COPYING.ASL20 in the source distribution
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "config.h"
#include "parsers.h"

static const int ftp_cds[] = {
		100, 110, 120, 125, 150,
		200, 202, 211, 212, 213, 214, 215, 220, 221, 225, 226, 227, 228, 229, 230, 231, 232, 250, 257,
		300, 331, 332, 350,
		400, 421, 425, 426, 430, 434, 450, 451, 452,
		500, 501, 502, 503, 504, 530, 532, 550, 551, 552, 553,
		600, 631, 632, 633,
		10000, 100054, 10060, 10061, 10066, 10068,
		0
};

static const char *ftp_cmds[] = {
		"STOR",
		"TYPE",
		"ABOR",
		"ACCT",
		"ALLO",
		"APPE",
		"CDUP",
		"CWD",
		"DELE",
		"HELP",
		"LIST",
		"MKD",
		"MODE",
		"NLST",
		"NOOP",
		"PASS",
		"PASV",
		"PORT",
		"PWD",
		"QUIT",
		"REIN",
		"REST",
		"RETR",
		"RMD",
		"RNFR",
		"RNTO",
		"SITE",
		"SMNT",
		"STAT",
		"STOU",
		"STRU",
		"SYST",
		"USER",
		NULL
};

/*
 * This function searches for a valid command in the header (from the list defined in ftp_cmds[])
 * and returns either the command or a NULL pointer
*/
static const char *check_Command_ftp(uchar *first_part_packet) {
	DBGPRINTF("in check_Command_ftp\n");
	DBGPRINTF("first_part_packet : '%s' \n", first_part_packet);
	int i = 0;
	for (i = 0; ftp_cmds[i] != NULL; i++) {
		if (strncmp((const char *)first_part_packet, ftp_cmds[i], strlen((const char *)ftp_cmds[i]) + 1) == 0) {
			return ftp_cmds[i];
		}
	}
	return "UNKNOWN";
}

/*
 * This function searches for a valid code in the header (from the list defined in ftp_cds[])
 * and returns either the command or a NULL pointer
*/
static int check_Code_ftp(uchar *first_part_packet) {
	DBGPRINTF("in check_Code_ftp\n");
	DBGPRINTF("first_part_packet : %s \n", first_part_packet);
	int i = 0;
	for (i = 0; ftp_cds[i] != 0; i++) {
		if (strtol((const char *)first_part_packet, NULL, 10) == ftp_cds[i]) {
			return ftp_cds[i];
		}
	}
	return 0;
}

/*
 *  This function parses the bytes in the received packet to extract FTP metadata.
 *
 *  its parameters are:
 *    - a pointer on the list of bytes representing the packet
 *        the first byte must be the beginning of the FTP header
 *    - the size of the list passed as first parameter
 *    - a pointer on a json_object, containing all the metadata recovered so far
 *      this is also where FTP metadata will be added
 *
 *  This function returns a structure containing the data unprocessed by this parser
 *  or the ones after (as a list of bytes), and the length of this data.
*/
data_ret_t *ftp_parse(const uchar *packet, int pktSize, struct json_object *jparent) {
	DBGPRINTF("ftp_parse\n");
	DBGPRINTF("packet size %d\n", pktSize);

	if (pktSize < 5) {  /* too short for ftp packet*/
		RETURN_DATA_AFTER(0)
	}
	uchar *packet2 = (uchar *)malloc(pktSize * sizeof(uchar));

	memcpy(packet2, packet, pktSize); // strtok changes original packet
	uchar *frst_part_ftp;
	frst_part_ftp = (uchar *)strtok((char *)packet2, " "); // Get first part of packet ftp
	strtok(NULL, "\r\n");

	if (frst_part_ftp) {
		int code = check_Code_ftp(frst_part_ftp);
		const char *command = check_Command_ftp(frst_part_ftp);
		if (code != 0) {
			json_object_object_add(jparent, "FTP_response", json_object_new_int(code));
		} else if (command != NULL) {
			json_object_object_add(jparent, "FTP_request", json_object_new_string(command));
		}
	}
	free(packet2);
	RETURN_DATA_AFTER(0)
}
