/*
 * Program: Synonym
 * File: disclaimer.c
 * Author: Cristian Draghici
 * Date: 09 Sep 2003
 *
 * $Id: disclaimer.c,v 1.3.2.1 2004/01/30 08:12:11 diciu Exp $
 *
 * Licensed under the Modulo Consulting Software License
 * (see file license.txt)
 * 
 */

#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>

#include <unistd.h>
#include <sys/stat.h>
#include <syslog.h>

#include <assert.h>
#include <errno.h>

#include <sys/types.h>
#include <signal.h>

#include "c-client/mail.h"
#include "c-client/osdep.h"
#include "c-client/rfc822.h"
#include "c-client/flstring.h"

#include "disclaimer.h"
#include "html_parser.h"

/* recursion level while parsing MIME parts. After this level we stop parsing considering attack. */
#define MIME_RECURSION_DEPTH	10
#define MAX_HOSTNAME_LENGTH	255

char SUBTYPE_PLAIN_STRING[]	=	"plain";
char SUBTYPE_HTML_STRING[]	=	"html";

#define print_debug syslog

/* declarations for internal use functions */
int disclaimer_text_read(char *buffer, int buffer_size, FILE*input_stream, disclaimer_state *current_state);
int disclaimer_html_read(char *buffer, int buffer_size, FILE*input_stream, disclaimer_state *current_state);
int disclaimer_html_read_encoding(char *buffer, int buffer_size, FILE*input_stream, disclaimer_state *current_state);
void read_text_offset(BODY * body,char * pfx,long i, disclaimer_state *current_state);
char *old_get_server_hostname(char *hostname);
int compute_additional_html_offset(char * buffer, int buffer_size, FILE * input_stream, disclaimer_state *current_state);

/* add the text disclaimer to a text part.
 * content =  the decoded content of the text/plain
 * size = the size of the part.
 */
char * add_text_disclaimer(char *content, long size, long *processed_size, disclaimer_state *current_state)
{
	char * processed_content = NULL;
	/* skip end of string char */
	long localsize = size - 1;
	
	if(current_state->disclaimer_text == NULL)
		return NULL;
		
	processed_content = fs_get(localsize + strlen(current_state->disclaimer_text) + 1);
	memcpy(processed_content, content, localsize);
	memcpy((void *)(processed_content + localsize), current_state->disclaimer_text, strlen(current_state->disclaimer_text));
	*processed_size = localsize + strlen(current_state->disclaimer_text) + 1;
	
	/* mark the end of string for printf and friends */
	processed_content[localsize + strlen(current_state->disclaimer_text)] = '\0';
	
	current_state->disclaimer_text_processed = 1;
	return processed_content;
}

char * add_html_disclaimer(char *content, long size, long *processed_size, disclaimer_state *current_state)
{
	char * processed_content = NULL;
	int end_of_body_offset = 0;
	int column, line, retval;
	/* skip end of string char */
	long localsize = size - 1;
	if(current_state->disclaimer_html == NULL)
		return NULL;
		
	processed_content = fs_get(localsize + strlen(current_state->disclaimer_html) + 1);
	
	/* get the end of the body tag */
	retval = locate_end_tag_in_string(content, processed_content, 
		size + strlen(current_state->disclaimer_html), &column, &line, localsize);	
	if(retval == DISCLAIMER_FAILURE)
	{
		print_debug(LOG_ERR, "Error in locate_end_tag_in_string result!");
		/* TODO: treat this error */
		return DISCLAIMER_FAILURE;
	}

	print_debug(LOG_DEBUG, "disclaimer: Body is ending at line %d and column %d", line, column);
	/* transform the line/column offset into byte offset */
	end_of_body_offset = linecolumn_to_byte(content, localsize, line, column);

	memcpy(processed_content, content, end_of_body_offset);
	memcpy((void *)(processed_content+end_of_body_offset), current_state->disclaimer_html, 
		strlen(current_state->disclaimer_html));
	if(end_of_body_offset < localsize)
	memcpy((void *)(processed_content+end_of_body_offset+strlen(current_state->disclaimer_html)), 
		(content+end_of_body_offset), 
		localsize-end_of_body_offset);
		
	processed_content[localsize + strlen(current_state->disclaimer_html)] = '\0';
	
	*processed_size = localsize + strlen(current_state->disclaimer_html) + 1;
	
	current_state->disclaimer_html_processed = 1;
	
	return processed_content;
}

/* Convert a line/column offset to byte offset.
 * Line terminator is \r\n */
int linecolumn_to_byte(char *content, int size, int lin, int col)
{
	char *pos;
	int line_count = 0;
	
	pos = content;
	while(line_count < lin-1) //lin is 1 based, linecount is 0 based
	{
		//print_debug(LOG_DEBUG, "linecolumn_to_byte: at line %d", line_count);
		if(pos != NULL)
		{
			if(pos+1 < content+size)
			{
				pos = memchr(pos+1, '\n', content+size-pos);
				
				if(pos != NULL)
					if(*(pos-1) == '\r')
						line_count++;
			}
			else
			{
				/* this happens when the body tag is not closed or not present at all */
				print_debug(LOG_DEBUG, "linecolumn_to_byte: Cannot reach line! Position would go over. Line count is %d, line offset is %d", line_count, lin-1);
				break;
			}
		}
		else
		{
			/* this happens when the body tag is not closed or not present at all */
			print_debug(LOG_DEBUG, "linecolumn_to_byte: Cannot reach line! line count is %d, line offset is %d", line_count, lin-1);
			break;
		}
	}
	if(pos == NULL)
	{
		print_debug(LOG_DEBUG, "linecolumn_to_byte: Assertion failed! (the line offset is bigger than the total number of lines).");
		pos = content + size;
	}
	else
	{
		if(pos + col <= content + size)
			pos += (col-1);
		else
			print_debug(LOG_DEBUG, "linecolumn_to_byte: Assertion failed! (end of body exceeds end of HTML).");
	}
	/* if we found a position.
	second condition is there because libxml simply reports the end of the file as </body> if the tag is missing, so we need to avoid deducting the size of the tag in that case*/
	if(pos != NULL && *pos == '<')
	{
		return pos - content - 6; // 6 is strlen("</body");
	}
	else
		return size;	//if failure add at the end.
}


/* see header file for comments */
int disclaimer_init(disclaimer_state *current_state)
{
	current_state->disclaimer_text_processed = 0;
	current_state->disclaimer_html_processed = 0;
	
	return DISCLAIMER_SUCCESS;
}



syntax highlighted by Code2HTML, v. 0.9.1