/* Interaction of the child process with the client */
void Talk_to_client ( int cfd )
{
   char id[10], pw[10];
   int nbytes, status;
   int src_addr, dest_addr;
   int abc, xyz=0, maskedpw;
   int i = 0, flag, j;
   Msg send_msg;
   Msg recv_msg;
   FILE *fp;
   long int q, alpha, secret_key, public_key, private_key;
   long int X_B, Y_A, Y_B;

   dest_addr = inet_addr("DEFAULT_SERVER");
   src_addr = inet_addr("192.168.1.245");
   
     
   /* Wait for responses from the clent (Alice, User A) */
   while ( 1 )
   {
   	/* receive messages from server */
   	nbytes = recv(cfd, &recv_msg, sizeof(Msg), 0);
   	if (nbytes == -1)
	{
	      	fprintf(stderr, "*** Client error: unable to receive\n");
   	}
 	switch ( recv_msg.hdr.opcode )
	{
    
		case REGISTER :	/* Registration from Client */
				printf("\n\nMessage:: REGISTER received from source (%d)\n", recv_msg.hdr.src_addr);
				strcpy(id, recv_msg.m.auth.id);
				strcpy(pw, recv_msg.m.auth.pw);
				printf("Received ID:\t%s\nPW:\t%s\n", id, pw);	
				make_clist(id, pw);
				
				fp = fopen("ClientList.txt", "a"); // append mode
 
  				if( fp == NULL )
   				{
      					perror("Error while opening the file.\n");
    				  	exit(EXIT_FAILURE);
   				}
 				
				fwrite(&clist, sizeof(clist), 1, fp);
								
				fclose(fp);
    				printf("Written to file.\n");

				printf("\nUpdated Client List is:");
				display_clist();

				break;

   		case LOGINREQ :	/* Login Request from Client */
				printf("\n\nMessage:: LOGINREQ received from source (%d)\n", recv_msg.hdr.src_addr);
				strcpy(id, recv_msg.m.auth.id);
				strcpy(pw, recv_msg.m.auth.pw);
				printf("Received ID:\t%s\nPW:\t%s\n", id, pw);			
				send_msg.hdr.opcode = LOGINREP;
   				send_msg.hdr.src_addr = src_addr;
   				send_msg.hdr.dest_addr = dest_addr;

				flag = 0;
				fp = fopen("ClientList.txt", "r"); // read mode
 
  				if( fp == NULL )
   				{
					printf("Clientlist does not exist!");
					send_msg.hdr.opcode = REQCOM;
   					send_msg.hdr.src_addr = src_addr;
   					send_msg.hdr.dest_addr = dest_addr;
					strcpy(send_msg.m.buf, "No user registered!");

					status = send(cfd, &send_msg, sizeof(Msg), 0);
  					if (status == -1)
					{
      						fprintf(stderr, "*** Client error: unable to send\n");
     						return;
    					}
   				}
				else
				{
					while(fread(&clist, sizeof(clist), 1, fp) != 0)
					{
						if( strcmp(id, clist.id) == 0 )
						{
						 	 xyz = 0;
    							 for(i = 0; pw[i] != '\0'; i++)
    							 {
								abc = (int) pw[i];
								xyz = xyz ^ abc;
    							 }
    							 maskedpw = clist.salt ^ xyz;
							 if(maskedpw == clist.maskedpw)
							 {
								
								flag = 1;
								break;
		   					 }
						}
					}

					fclose(fp);

                                	if(flag == 0)
					{
						printf("Wrong ID/Password!\n");					
						strcpy(send_msg.m.buf, "Wrong ID/Password!");
					}
					else
					{
						printf("Authenticated!\n");
						strcpy(send_msg.m.buf, "Authenticated!");
					}
					status = send(cfd, &send_msg, sizeof(Msg), 0);
  					if (status == -1)
					{
      						fprintf(stderr, "*** Client error: unable to send\n");
     						return;
    					}
				}
				break;

		case PUBKEY :   /* Public key */
                		printf("\n\nMessage:: PUBKEY received from source (%d)\n", recv_msg.hdr.src_addr); 

		                /* Compute the secret shared key based on public key received from Bob (User B) */
		                q =   recv_msg.m.dhpubkey.q;
		                alpha = recv_msg.m.dhpubkey.g;
        		        Y_A = recv_msg.m.dhpubkey.Y;
       			        printf("Received public values from Alice are q = %ld, alpha = %ld, Y_A = %ld\n\r", 
        	                q, alpha, Y_A);
               
      			        /* Select a private key X_B < q */
               			private_key = rand() % q;
         		        X_B = private_key;
   		                printf("Private key for Bob (User B) is %ld\n\r", X_B);              
 
        		        /* Compute the public key Y_B */
       			        public_key = ModPower(alpha, X_B, q);
        		        Y_B = public_key;
               			printf("Public key for Bob (User B) is %ld\n\r", Y_B); 

		                /* Send the public key to Alice */
   				printf("Sending the public key to Alice (User A)\n");          
   				send_msg.hdr.opcode = PUBKEY;
   				send_msg.hdr.src_addr = src_addr;
   				send_msg.hdr.dest_addr = dest_addr;
   				
   				/* send the public key to Alice */
   				send_msg.m.dhpubkey.q = q;  /* q */
   				send_msg.m.dhpubkey.g = alpha; /* alpha */
   				send_msg.m.dhpubkey.Y = Y_B;  /* value of public key */
	     
               			/* Now compute the secret key shared between Alice and Bob */
            			secret_key = ModPower(Y_A, X_B, q);             
               			printf("Computed secret key between Alice and Bob (by User B, Bob ) is %ld\n\r", secret_key); 
        		        /* Send an acknowledgement to Alice that the secret key is computed */ 
			
				status = send(cfd, &send_msg, sizeof(Msg), 0);
  				if (status == -1)
				{
      					fprintf(stderr, "*** Client error: unable to send\n");
     					return;
    				}    
  
              		        break;      
                               
		case REQSERV :	/* Request from Client for Encrypted data */
				printf("\n\nMessage:: REQSERV received from source (%d)\n", recv_msg.hdr.src_addr);
				printf("%s\n", recv_msg.m.buf);
				
				int count;
   				
  				fp = fopen(recv_msg.m.buf, "r"); // read mode
 
  				if( fp == NULL )
   				{
					send_msg.hdr.opcode = REQCOM;
   					send_msg.hdr.src_addr = src_addr;
   					send_msg.hdr.dest_addr = dest_addr;
					strcpy(send_msg.m.buf, "File does not exist!");

					status = send(cfd, &send_msg, sizeof(Msg), 0);
  					if (status == -1)
					{
      						fprintf(stderr, "*** Client error: unable to send\n");
     						return;
    					}
   				}
				else
				{
   					printf("The contents of %s file are :- \n", recv_msg.m.buf);

 					while( (count = fread(buffer, 1, MAX_LEN - 1, fp) ) != 0)
    					{
						buffer[count] = '\0';
						printf("\nPlain Text is:\n\n%s\n", buffer);
						EncryptionAlgorithm(buffer, secret_key);
						printf("\nEncrypted Text is:\n\n%s\n", buffer);
					
						send_msg.hdr.opcode = ENCMSG;
   						send_msg.hdr.src_addr = src_addr;
   						send_msg.hdr.dest_addr = dest_addr;
						strcpy(send_msg.m.buf, buffer);

						status = send(cfd, &send_msg, sizeof(Msg), 0);
  						if (status == -1)
						{
      							fprintf(stderr, "*** Client error: unable to send\n");
     							return;
    						}
    					}
				  								
   					fclose(fp);
				
					send_msg.hdr.opcode = REQCOM;
   					send_msg.hdr.src_addr = src_addr;
   					send_msg.hdr.dest_addr = dest_addr;
					strcpy(send_msg.m.buf, "Request Complete!");

					status = send(cfd, &send_msg, sizeof(Msg), 0);
  					if (status == -1)
					{
      						fprintf(stderr, "*** Client error: unable to send\n");
     						return;
    					}
				}
				break;

		case DISCONNECT :/* Disconnect */
				printf("\n\nMessage:: DISCONNECT received from source (%d)\n", recv_msg.hdr.src_addr);
				printf("%s\n", recv_msg.m.buf);
				send_msg.hdr.opcode = DISCONNECT;
   				send_msg.hdr.src_addr = src_addr;
   				send_msg.hdr.dest_addr = dest_addr;
				strcpy(send_msg.m.buf, "Disconnect...");
				
				status = send(cfd, &send_msg, sizeof(Msg), 0);
  				if (status == -1)
				{
      					fprintf(stderr, "*** Client error: unable to send\n");
     					return;
    				}
				exit(0);

				break;

   	}
   
  }
}
/* Interaction of the child process with the client */
void Talk_to_client ( int cfd )
{
	int status;
   	int nbytes;
   	int src_addr, dest_addr;
   	Msg send_msg;
   	Msg recv_msg;
   	PubKey clientPublicKey;

   	dest_addr = inet_addr("127.0.0.1");
   	src_addr = inet_addr(DEFAULT_SERVER);
 
	while (1) 
   	{
		/* Receive response from client */
		nbytes = recv(cfd, &recv_msg, sizeof(Msg), 0);

		if (nbytes == -1) 
		{
			fprintf(stderr, "*** Server error: unable to receive\n");
			return;
		}
		switch ( recv_msg.hdr.opcode ) 
		{
			
         case PUBKEY : /* Public Key Message */
				printf("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
				printf("Message:: with opcode %d (PUBKEY) received from source (%d)\n", recv_msg.hdr.opcode, recv_msg.hdr.src_addr);  
				printf("Received public key\n");
				printf("Pub Key n : %ld\t", recv_msg.pubkey.n);
				printf("Pub Key e : %ld\n" , recv_msg.pubkey.e);
				
            //assign the values to the client Public Key structure
				clientPublicKey.e = recv_msg.pubkey.e;
				clientPublicKey.n = recv_msg.pubkey.n;
				break;

         case REQ: /* Request file message */
				printf("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
				printf("Message:: with opcode %d (REQ) received from source (%d)\n", recv_msg.hdr.opcode, recv_msg.hdr.src_addr);
            printf("Requested file name : \"%s\"", recv_msg.data);

				FILE *fp;
				fp = fopen(recv_msg.data, "r");
				if(fp == NULL)
				{
					printf("File is not present...\n");
					printf("Sending DISCONNECT message to the client\n");
					send_msg.hdr.opcode = DISCONNECT;
           		send_msg.hdr.src_addr = src_addr;
           		send_msg.hdr.dest_addr = dest_addr;
           		send_msg.status = FAIL;
           		memset(send_msg.data, '\0', MAX_LEN);
              		memset(send_msg.sha1, '\0', MAX_LEN);
					send_msg.pubkey.e = 0;
					send_msg.pubkey.n = 0;
					status = send(cfd, &send_msg, sizeof(Msg), 0);
					if (status == -1) 
					{
						fprintf(stderr, "*** Client error: unable to send\n");
						return;
					}
					exit(0);
				}
				else
				{
					printf("Requested file found on server...\nStarting the encryption...\n");
					long int blockSize = 16, counter = 0, intermediateNumber, flag = 0, j;
					char c, encryptedData[MAX_LEN], intermediateString[MAX_LEN], orgData[MAX_LEN];
					unsigned char hash[SHA_DIGEST_LENGTH];
               memset(encryptedData, '\0', sizeof encryptedData);
               memset(orgData, '\0', sizeof orgData);
               memset(hash, '\0', sizeof hash);
					while((c = fgetc(fp)) != EOF)
					{
						if(counter == blockSize)
						{
							//Generate the hash for the original data and send encrypted data to the client
							printf("++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
                     printf("Encrypted data : %s\n", encryptedData);
                     printf("original data : %s\n", orgData);

                     SHA1(orgData, sizeof(orgData) - 1, hash);

							printf("SHA1 -> ");
							for(j = 0; j < SHA_DIGEST_LENGTH; j++)
							  printf("%u", hash[j]);

							//Send the data to client
							printf("\nSending data...\n");
							send_msg.hdr.opcode = REP;
           				send_msg.hdr.src_addr = src_addr;
           				send_msg.hdr.dest_addr = dest_addr;
           				send_msg.status = SUCCESS;
           				//copy the data 
           				strcpy(send_msg.data, encryptedData);
           				//copy the sha1
           				for(j = 0; j < SHA_DIGEST_LENGTH; j++)
           					send_msg.sha1[j] = hash[j];
							send_msg.pubkey.e = 0;
							send_msg.pubkey.n = 0;
							status = send(cfd, &send_msg, sizeof(Msg), 0);
							if (status == -1) 
							{
								fprintf(stderr, "*** Client error: unable to send\n");
								return;
							}
							//data sent
							counter = 0;
							memset(encryptedData, '\0', sizeof encryptedData);
							memset(orgData, '\0', sizeof orgData);
                     memset(hash, '\0', sizeof hash);
							flag = 1;
						}
						orgData[counter] = c;
						intermediateNumber = EncryptionAlgorithm(encode(c), recv_msg.pubkey);
						
                  int i = 0;
						//Convert the number to the string here
						while(intermediateNumber != 0)
						{
							intermediateString[i++] = intermediateNumber % 10 + '0';
							intermediateNumber /= 10;
						}
						intermediateString[i] = '\0';
						reverse_string(intermediateString);
						strcat(encryptedData, intermediateString);

						strcat(encryptedData, ",");

						flag = 0;
						counter++;
					}

					if(flag == 0)  // means the data is formed less than the block size
					{
                  printf("Encrypted data : %s\n", encryptedData);
                  printf("Original data : %s\n", orgData );
						SHA1(orgData, sizeof(orgData) - 1, hash);
						printf("SHA1\n");
						for(j = 0; j < SHA_DIGEST_LENGTH; j++)
						   printf("%u", hash[j]);
						//Sending the data
						printf("Sending data...\n");
						send_msg.hdr.opcode = REP;
       				send_msg.hdr.src_addr = src_addr;
       				send_msg.hdr.dest_addr = dest_addr;
       				send_msg.status = SUCCESS;
       				//copy the data 
       				strcpy(send_msg.data, encryptedData);
       				//copy the sha1
       				for(j = 0; j < SHA_DIGEST_LENGTH; j++)
       					send_msg.sha1[j] = hash[j];
						send_msg.pubkey.e = 0;
						send_msg.pubkey.n = 0;
						status = send(cfd, &send_msg, sizeof(Msg), 0);
						if (status == -1) 
						{
							fprintf(stderr, "*** Client error: unable to send\n");
							return;
						}
               }

					//  File data transferred completely
               //    Send the DISCONNECT message to the client and close
					printf("Sending REQCOMM message to the client\n");
					send_msg.hdr.opcode = REQCOM;
           		send_msg.hdr.src_addr = src_addr;
           		send_msg.hdr.dest_addr = dest_addr;
           		send_msg.status = SUCCESS;
           		memset(send_msg.data, '\0', MAX_LEN);
           		memset(send_msg.sha1, '\0', MAX_LEN);
					send_msg.pubkey.e = 0;
					send_msg.pubkey.n = 0;
					status = send(cfd, &send_msg, sizeof(Msg), 0);
					if (status == -1) 
					{
						fprintf(stderr, "*** Client error: unable to send\n");
						return;
					}
					fclose(fp);
				}
				break;

			case DISCONNECT:
				printf("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
				printf("Message:: with opcode %d (DISCONNECT) received from source (%d)\n", recv_msg.hdr.opcode, recv_msg.hdr.src_addr);
				printf("Exiting...\n");
				exit(0);

			default: 
				printf("message received with opcode: %d\n", recv_msg.hdr.opcode);
				exit(0);  
		}
 	}
}