/* ALink85 by Shawn D'Alimonte (aa600@torfree.net)                      */
/* Based on:                                                            */
/* XLink85  -  TI85<->PC  link  program,  Copyright (c) 1996 Jani Halme	*/
/* My work is mostly in tiport.c, which is the low level port access    */
/* routines.  The rest is by Jani Halme, but has been reorganized.      */
/*                                                                      */
/* !!!!!!!!!!!!!!!!!!!!!!!!!WARNING!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!       */
/*                                                                      */
/* This program uses the CIA registers directly without telling the OS  */
/* Therefore it will interfere with and be interefered by an serial and */
/* possiblly parallel port activity.  Also it will not function on any  */
/* possible future Amiga's unless the serial port handshaking bits stay */
/* put.  It will not work with any add-on serial cards                  */
/*									*/
/* 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;  it  now,  write  to  the  Free Software	*/
/* Foundation, Inc., Mass Ave, Cambridge, MA02139.			*/
/*									*/  
/* The author can be contacted by email at:aa600@torfree.net*/
									
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include "tiport.h"
#include "packet.h"
#include "version.h"
#include "recv85.h"

extern const char identifier[8];
extern const char var_extensions[31][5];
extern const char var_types[31][6];
extern unsigned char *buffer;
extern unsigned short last_packet_size;

/* receive variable from calculator */
void receive()
{
	int received;
	char ch;
	char var_name[9];
	char var_filename[13];
	UWORD var_length, seekword, i, ii;
	UWORD var_type, packet_type;
	UWORD var_namelength;
	FILE *var_file=NULL;
	struct stat statbuf;
	
	char groupheader[11]={ '*','*','T','I','8','5','*','*',0x1a,0x0c,0x00};
	char description[42]="File received by ALink85                 \0";
	
	i=0;
	printf("recv85: Listening for packets...\n");	
	received=0;
	packet_type=0;
	while (packet_type!=PAK_LASTVAR)
	{
		packet_type=get_packet();
#ifdef DEBUG
		printf("Packet Type is %x\n",packet_type);
#endif
		switch (packet_type)
		{
			case PAK_VARHEADER: 
				strcpy(var_name, ""); 
				if (buffer[2]!=0x1d)
				{
					var_length=buffer[0]|(buffer[1]<<8);
					var_type=buffer[2]; 
					var_namelength=buffer[3];
					memcpy(&var_name, buffer+4, var_namelength);
					var_name[var_namelength]='\0';
					memcpy(&var_filename, buffer+4, var_namelength);
					memcpy(&(var_filename[var_namelength]), &var_extensions[var_type], 4); 
					var_filename[var_namelength+4]='\0';
					printf("recv85: Receiving %8s, type %5s, to %12s\n", 
					       var_name, var_types[var_type], var_filename);
				} 
				else
				{
					strcpy(var_filename, "backup.85b");
					printf("recv85: Receiving system backup to '%s'\n",var_filename);
					
					/* write group file header */
					var_file=fopen(var_filename, "wb");
					fwrite(&groupheader, sizeof(char), 11, var_file);
					fwrite(&description, sizeof(char), 42, var_file);
					seekword=8+last_packet_size+(buffer[0]|(buffer[1]<<8))+
								   +(buffer[3]|(buffer[4]<<8))+
								   +(buffer[5]|(buffer[6]<<8));
					seekword=WORDSWAP(seekword);
					fwrite(&seekword, sizeof(short), 1, var_file);
					seekword=WORDSWAP(9);
					fwrite(&seekword, sizeof(short), 1, var_file);					
					fwrite(buffer, sizeof(char), 9, var_file); 
					
					/* request rest of backup */
					put_packet(PAK_REQDATA, 0);
					if (get_packet()==PAK_ACKNOWLEDGE)
					{
						for(i=0;i<3;i++)
						{
							get_packet();
							last_packet_size=WORDSWAP(last_packet_size);
							fwrite(&last_packet_size, sizeof(short),1,var_file);
							fwrite(buffer, sizeof(char), WORDSWAP(last_packet_size), var_file); 
						}
						/* write checksum */
						fclose(var_file);
						var_file=fopen(var_filename, "rb");
						fseek(var_file, 0x35, 1);
						fread(&ii, sizeof(short), 1, var_file);
						fread(buffer, sizeof(char), WORDSWAP(ii), var_file);
						fclose(var_file);
						
						seekword=0;
						for(i=0;i<WORDSWAP(ii);i++) seekword+=buffer[i];
						var_file=fopen(var_filename, "ab");
						seekword=WORDSWAP(seekword);
						fwrite(&seekword, sizeof(short), 1, var_file);
						fclose(var_file);						
						
						printf("recv85: Backup received OK!\n");
						exit(0);
					} else
					{
						printf("recv85: Data request not acknowledged!\n");
						exit(-1);
					}
					
				}
				
				/* check if file exists already */
				i=2;
				if (stat(var_filename, &statbuf)==0) 
				{
					i=0;
					do
					{
						printf("recv85: Duplicate filename - overwrite (y/n/x)? ");					
						ch=getchar();
						switch (ch)
						{
							case 'x': case 'X': 
							{
								buffer[0]=1;
								put_packet(PAK_SKIPVAR,1);
								printf("recv85: Transfer aborted!\n");
								exit(-1); 
							}
							case 'n': case 'N': 
							{
								buffer[0]=2;
								put_packet(PAK_SKIPVAR,1);
								i=1; 
								printf("recv85: Variable skipped!\n");
								break;
							}
							case 'y': case 'Y': 
							{
								i=2; 
								break;
							}
							default: break;
						}
					}
					while (i==0);
				}
				
				if (i==2)
				{
					put_packet(PAK_REQDATA, 0);
					if (get_packet()==PAK_ACKNOWLEDGE) get_packet();
				
					var_file=fopen(var_filename, "wb");
					fwrite(&groupheader, sizeof(char), 11, var_file);
					fwrite(&description, sizeof(char), 42, var_file);
					seekword=8+var_namelength+var_length;
					seekword=WORDSWAP(seekword);
					fwrite(&seekword, sizeof(short), 1, var_file);
					seekword=WORDSWAP(4+var_namelength);
					fwrite(&seekword, sizeof(short), 1, var_file);
					var_length=WORDSWAP(var_length);
					fwrite(&var_length, sizeof(short), 1, var_file);
					/*fwrite(&var_type, sizeof(char), 1, var_file);*/
					fputc((char)var_type,var_file);
#ifdef DBG
					printf("var_namelength: %x\n",var_namelength);
#endif
					/*fwrite(&var_namelength, sizeof(char), 1, var_file);*/
					fputc((char)var_namelength,var_file);
					fwrite(&var_name, sizeof(char), var_namelength, var_file);
					fwrite(&var_length, sizeof(UWORD), 1, var_file);
					fwrite(buffer, sizeof(char), WORDSWAP(var_length), var_file);
					fclose(var_file);
				
					var_file=fopen(var_filename, "rb");
					fseek(var_file, 0x35, 1);
					fread(&ii, sizeof(short), 1, var_file);
					fread(buffer, sizeof(char), WORDSWAP(ii), var_file);
					fclose(var_file);
					seekword=0;
					for(i=0;i<WORDSWAP(ii);i++) seekword+=buffer[i];
				
					var_file=fopen(var_filename, "ab");
					seekword=WORDSWAP(seekword);
					fwrite(&seekword, sizeof(short), 1, var_file);
					fclose(var_file);
					printf("recv85: OK!\n");
					received++;
				}
				break;
			case PAK_LASTVAR: 
				put_packet(PAK_ACKNOWLEDGE, 0);
				break;
			default: 
				printf("recv85: Invalid packet received!\n");
				break;
		}
	}
	printf("recv85: %d variables received\n", received);
}


int main(int agc, char** argv)
{
	printf(VERSION_HDR);
	/* More buffer space than we will ever need! */
	if (!(buffer=(UBYTE *)malloc(64*1024*sizeof(UBYTE))))
	  {
	    printf("\aDrats, can't get 64K ram.  Buy more!\n"); /*We really can't get 64K ?*/
	    abort();
	  }
	initport(); 	
	receive();
	free(buffer);
}




