/*
 * write.c -- chooses output data
 * Part of the tcpick project
 *
 * Author: Francesco Stablum <duskdruid @ despammed.com>
 *
 * Copyright (C) 2003, 2004  Francesco Stablum
 * Licensed under the GPL
 *
 */

/*
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

#include "tcpick.h"
#include "extern.h"

__inline__ char * 
avail_filename(struct CONN * conn_ptr, 
	       enum PART side, char * ext)
/*
  finds an available name for the connection file,
  i.e. sometimes there are same filenames, this is useful
  to invent a different filename
*/
{
	char * client_server;
	char * base_name;
	char * dir_name;
	char * test_name;
	char * ret;
	struct stat stat_struct;
	/* this gets the name of the host */
	char * clientname;
	char * servername;
	int server_port=conn_ptr->server.port;
	int num = 0;
  
	client_server = (char *)S_calloc(MAX_FILENAME_LENGHT,1);
	base_name     = (char *)S_calloc(MAX_FILENAME_LENGHT,1);
	dir_name      = (char *)S_calloc(MAX_FILENAME_LENGHT,1);
	test_name     = (char *)S_calloc(MAX_FILENAME_LENGHT,1);
	
	if (flags.dirs > 0) {
		/* -D option */
		sprintf(dir_name,"%06u", conn_ptr->num / flags.dirs);
		if( stat(dir_name, &stat_struct) == -1 ) {
			switch (errno) {
			case ENOENT:
				/* directory don't exist: create it! */
				if( mkdir(dir_name, 666) == -1 )
					fault("avail_filename", "mkdir");
				break;
			default:
				fault("avail_filename", "stat");
			}
		}

	} else {
		sprintf(dir_name,".");
	}

	clientname = (char *)lookup(conn_ptr->client.ip);
	sprintf(client_server,"%s", clientname);

	servername=(char *)lookup(conn_ptr->server.ip);
	sprintf(client_server,"%s_%s_%s",
		client_server,
		servername,
		getportname(server_port)
		);

	if(flags.writer.type == UNIQUE) {
		/* this was Saumil Shah's wish ;^) */
		switch( flags.filenaming ) {
		case 1:
			sprintf(base_name, "%s/tcpick_%s.both", dir_name, client_server);
			break;
		case 2:
			sprintf(base_name, "%s/tcpick_%06u_%s.both", dir_name, conn_ptr->num, client_server);
			break;
		}
	} else { /* flags.writer.type == SEPARATE,
		  * so, give different filenames! 
		  * this is by default.
		  */

		switch( flags.filenaming ) {
		case 1:
			switch( side ) {
			case CLIENT:

				sprintf(base_name, "%s/tcpick_%s.clnt", dir_name, client_server);
				break;
				
			case SERVER:
				
				sprintf(base_name,"%s/tcpick_%s.serv", dir_name, client_server);
				break;
			}
			break;
			
		case 2:
			switch( side ) {
			case CLIENT:
				
				sprintf(base_name, "%s/tcpick_%06u_%s.clnt", dir_name, conn_ptr->num, client_server);
				break;
				
			case SERVER:
				
				sprintf(base_name,"%s/tcpick_%06u_%s.serv", dir_name, conn_ptr->num, client_server);
				break;
			}
			break;
		}
	}

	sprintf( test_name, "%s.%s", base_name, ext );
	while(! stat( test_name, &stat_struct )) {
		num++;
		sprintf( test_name, "%s.%x.%s", base_name, num, ext );
	}

	/* returning the right pointer and freeing wasted memory */
	
#ifdef HAVE_STRNDUP
	ret = (char *)strndup( test_name, MAX_FILENAME_LENGHT );
#else
	ret = (char *)strdup( test_name );
#endif
	S_free( test_name );
	S_free( dir_name );
	S_free( base_name );
	S_free( client_server );
	return ret;
}

void
open_file( struct CONN * conn_ptr, 
		  struct HOST_DESC * desc )
{
	static char * s;
	FILE * lockfile;
	/* preparing for the connection side file */
	if(flags.writer.type == UNIQUE 
	   && desc->oth->file != NULL ) {
		/* user want  a unique output file, 
		   and it was just opened! */
		desc->file = desc->oth->file;
		desc->filename = desc->oth->filename;
	} else {
		s = (char *)avail_filename( conn_ptr, desc->side, "dat" );
		
		desc->file = fopen( s , "a" );
		if( desc->file == NULL )
			fault("open_file", "fopen returned NULL");
		desc->filename = s;

		s = (char *)avail_filename( conn_ptr, desc->side, "lck");
		
		lockfile = fopen( s , "a" );
		if( lockfile == NULL )
			fault("open_file", "fopen returned NULL");
		fclose(lockfile);
		desc->lockfilename = s;
	}
	return;
}

__inline__ int
flowflush ( struct CONN * conn_ptr, 
	    struct HOST_DESC * desc, 
	    u_char * buf,
	    int buflen )
/* data that are acknowledged come here in order to be written to
   their file, or to stdout */
{
	/* -b set of options */
	if ( desc->side == flags.display_rebuild.side )
		
		out_flavour ( flags.display_rebuild.flavour,
			      stdout, buf, buflen );
	
	else if ( flags.display_rebuild.side == BOTH )
		
		out_flavour ( flags.display_rebuild.flavour,
			      stdout, buf, buflen );
	
	/* -w set of options */
	if ( desc->side == flags.writer.side ) {
		
		if(! desc->file ) 
			open_file( conn_ptr, desc ); 
		
		out_flavour ( flags.writer.flavour,
			      desc->file, buf, buflen );
	}
	else if ( flags.writer.side == BOTH ) {
		
		if(! desc->file )
			open_file( conn_ptr, desc ); 

		if ( flags.writer.banner == 1 ) {
		/* -wb */
			/* FIXME: add it to `-b' too? Do a function for this? */
			fprintf(desc->file, 
				(desc->side == CLIENT)
				? "\n[client] %d:%d (%d)\n" 
				: "\n[server] %d:%d (%d)\n",
				desc->wlen,
				desc->wlen + buflen,
				buflen);
		}
		
		out_flavour ( flags.writer.flavour,
			      desc->file, buf, buflen );
	}
}

int 
out_flavour( enum FLAVOUR flavour, 
	     FILE * out, 
	     u_char * buf, 
	     int buflen )
/* chooses the function to call, according to the specified flavour */
{
	if( flags.separator && ( out == stdout ) ) /* FIXME: sucks? */
		color( c_SEPARATOR, stdout, SEPARATOR "\n" );

	switch ( flavour ) {
	case HEX_ASCII_DUMP:
		out_xa( out, buf, buflen );
		break;
	case HEX_DUMP:
		out_x( out, buf, buflen );
		break;
	case RAW:
		fwrite( buf, sizeof(u_char), buflen, out );
		if( DISPLAY_NL )
			fprintf( out, "\n" );
		break;
	case PRINTABLE:
		out_p( out, buf, buflen );
		break;
	case HEX:
		out_h( out, buf, buflen );
		break;
	case HEX_NON_PRINT:
		out_hn( out, buf, buflen );
		break;
	default: /* SILENT ??? */
		break;
	}
}


syntax highlighted by Code2HTML, v. 0.9.1