/*

                                   _JNJ`                        
                               .JNMH`                           
                              JMMF`       `;.                   
                            .NMM)          `MN.                 
                            MMM)            (MML                
                           (MMM`             MMML               
                     M  I  D  N  I  G  H  T    C  o  D  E       
                           (NMMF             MHNH               
                            NMML            .MMM                
                             NMML          .NMH                 
                              4MMNL       .#F                   
                               `4HNNL_   `                      
                                   `"""`                        

                          Copyright (C) 2004-2006
       "Ian (Larry) Latter" <ian dot latter at midnightcode dot org>

    Midnight Code is a registered trademark of Ian Latter.

    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, and mirrored at the Midnight Code web
    site; as at version 2 of the License only.
  
    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
    (version 2) along with this program; if not, write to the Free
    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    02111-1307 USA, or see http://midnightcode.org/gplv2.txt

*/

/* tftpg.c :: Midnight Code TFTP-get client example program		*/


#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <errno.h>
#include <time.h>


#include <libmidnightcode.h>


int
main(int argc, char **argv) {
  char cfg_input_file_name[128] = "\0";
  char cfg_output_file_name[128] = "\0";
  struct in_addr cfg_to_host;
  int cfg_port;
  int cfg_help = 0;
  char to_host_s[21];
  void * tmp_void_p;
  struct midnightcode_socket_head_t * sockets;
  FILE * ofp;
  char * buffer;
  int buffer_len;
  int buffer_total;
  time_t time_start;
  time_t time_stop;
  int time_taken;
  int ret_i;

 
  // Prepare switches
  struct midnightcode_switch_t switches[] = {
    { "s", "server", "Server to connect to",
      MIDNIGHTCODE_PARSE_TYPE_HOST, 0, 0, &cfg_to_host.s_addr },
    { "p", "port", "Port connect to (default is 69/UDP)",
      MIDNIGHTCODE_PARSE_TYPE_INT, 0, 0, &cfg_port },
    { "g", "get", "Retrieve this file/path",
      MIDNIGHTCODE_PARSE_TYPE_STRING, 128, 0, &cfg_input_file_name },
    { "o", "output_file", "Target file, to write to",
      MIDNIGHTCODE_PARSE_TYPE_STRING, 128, 0, &cfg_output_file_name },
    { "h", "help", "Display this help/usage screen",
      MIDNIGHTCODE_PARSE_TYPE_NONE, 0, 0, &cfg_help },
    { 0 }
  };



  // Set-up initial values;
  memset(&cfg_input_file_name, 0, sizeof(cfg_input_file_name));
  memset(&cfg_output_file_name, 0, sizeof(cfg_output_file_name));
  memset(&cfg_to_host, 0, sizeof(struct in_addr));
  cfg_port = 0;




  // Process switches
  if((ret_i = midnightcode_switch_process(argc, argv, switches)) != 0) {
    fprintf(stdout, "\n");
    midnightcode_logo(0, MIDNIGHTCODE_COLOUR_STYLE_BLOOD_MOON);
    midnightcode_license(0, MIDNIGHTCODE_COLOUR_STYLE_BLOOD_MOON, 
      MIDNIGHTCODE_LICENSE_TEXT_COPYRIGHT);
    fprintf(stdout, "    Error in switches, switch \"%s\" is unkown"
      " at parameter number %d.\n\n", argv[ret_i], ret_i);
    midnightcode_switch_usage(MIDNIGHTCODE_SWITCH_STYLE_SOFT, argv[0],
      switches);
    exit(1);
  }
  if(cfg_help) {
    midnightcode_logo(0, MIDNIGHTCODE_COLOUR_STYLE_BLOOD_MOON);
    midnightcode_license(0, MIDNIGHTCODE_COLOUR_STYLE_BLOOD_MOON, 
      MIDNIGHTCODE_LICENSE_TEXT_COPYRIGHT);
    midnightcode_switch_usage(MIDNIGHTCODE_SWITCH_STYLE_SOFT, argv[0],
      switches);
    exit(1);
  }
  fflush(stdout);



  // Process license and logo
  midnightcode_logo(0, MIDNIGHTCODE_COLOUR_STYLE_BLOOD_MOON);
  midnightcode_license(0, MIDNIGHTCODE_COLOUR_STYLE_BLOOD_MOON, 
    MIDNIGHTCODE_LICENSE_TEXT_ALL);



  // Program title
  midnightcode_status_text(MIDNIGHTCODE_STATUS_TYPE_H1,
    MIDNIGHTCODE_STATUS_STYLE_NORMAL, "Network copy example: %s", argv[0]);

  fprintf(stdout, "\n");
  fflush(stdout);




  // Validate user params
  midnightcode_status_text(MIDNIGHTCODE_STATUS_TYPE_TEXT,
                           MIDNIGHTCODE_STATUS_STYLE_NORMAL,
                           "Validating user parameters");
  if(!strlen(cfg_input_file_name) || !strlen(cfg_output_file_name)) {
    midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_FAIL);
    fprintf(stdout, "\n");
    exit(1);
  }
  midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_OKAY);
  /*
    if(midnightcode_ip_isspecial(MIDNIGHTCODE_IP_SPECIAL_RFC3171|
      MIDNIGHTCODE_IP_SPECIAL_RFC3171, cfg_to_host.s_addr) ||
      strlen(cfg_output_file_name)) {
      midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_FAIL);
      fprintf(stdout, "\n");
      exit(1);
    } else {
  */
  memset(&to_host_s, 0, 21);
  snprintf(to_host_s, 21, "%s", inet_ntoa(cfg_to_host));



  // Socket Initialisation
  midnightcode_list_init(socket_struct_head, midnightcode_socket_element_t);
  tmp_void_p = (void *)&socket_struct_head;
  sockets = tmp_void_p;

  midnightcode_status_text(MIDNIGHTCODE_STATUS_TYPE_TEXT,
                           MIDNIGHTCODE_STATUS_STYLE_NORMAL,
                           "Initialising socket library");
  if(midnightcode_socket_initialise(sockets) < 0) {
    midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_FAIL);
    fprintf(stdout, "\n");
    exit(1);
  } else {
    midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_OKAY);
  }

  time_taken = 0;



  // Opening output file
  midnightcode_status_text(MIDNIGHTCODE_STATUS_TYPE_TEXT,
                           MIDNIGHTCODE_STATUS_STYLE_NORMAL,
                           "Opening output file");
  if((ofp = fopen(cfg_output_file_name, "w")) == NULL) {
    midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_FAIL);
    fprintf(stdout, "\n");
    exit(1);
  } else {
    midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_OKAY);
  }



  // Start timer
  buffer_total = 0;
  time(&time_start);
    


  // Get TFTP File
  ret_i = midnightcode_tftp_get(&buffer, &buffer_len, to_host_s, cfg_port,
    cfg_input_file_name);
  midnightcode_status_text(MIDNIGHTCODE_STATUS_TYPE_TEXT,
    MIDNIGHTCODE_STATUS_STYLE_NORMAL,
    "Retrieving TFTP file");
  if(ret_i <= 0) {
    midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_FAIL);
    printf("Error was [%d]\n", ret_i);
    fprintf(stdout, "\n");
    exit(1);
  } else {
    midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_OKAY);
  }



  // Writing output file
  midnightcode_status_text(MIDNIGHTCODE_STATUS_TYPE_TEXT,
    MIDNIGHTCODE_STATUS_STYLE_NORMAL,
    "Writing output file; %d bytes", buffer_len);
  if((ret_i = fwrite(buffer, sizeof(char), buffer_len, ofp)) < 1) {
    midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_FAIL);
    printf("Error was [%d]\n", ret_i);
    fprintf(stdout, "\n");
    exit(1);
  } else {
    midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_OKAY);
  }


  // Keep track of totals
  buffer_total += buffer_len;



  // Received terminate count
  midnightcode_status_text(MIDNIGHTCODE_STATUS_TYPE_TEXT,
    MIDNIGHTCODE_STATUS_STYLE_NORMAL,
    "Received total file count of %d bytes", buffer_len);
  midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_OKAY);




  // Stop timer
  time(&time_stop);
  time_taken = (int)(time_stop - time_start);
  if(time_taken < 1)
    time_taken = 1;



  // Closing output file
  midnightcode_status_text(MIDNIGHTCODE_STATUS_TYPE_TEXT,
    MIDNIGHTCODE_STATUS_STYLE_NORMAL,
    "Closing output file");
  if(fclose(ofp)) {
    midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_FAIL);
    fprintf(stdout, "\n");
    exit(1);
  } else {
    midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_OKAY);
  }



  // Socket shutdown
  midnightcode_status_text(MIDNIGHTCODE_STATUS_TYPE_TEXT,
                           MIDNIGHTCODE_STATUS_STYLE_NORMAL,
                           "Shutdown socket library");
  if(midnightcode_socket_shutdown(sockets) < 0) {
    midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_FAIL);
    fprintf(stdout, "\n");
    exit(1);
  } else {
    midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_OKAY);
  }



  // Transfer rate
  fprintf(stdout, "\n");
  midnightcode_status_text(MIDNIGHTCODE_STATUS_TYPE_BLURB,
                           MIDNIGHTCODE_STATUS_STYLE_UNKNOWN,
    "%d bytes in %d seconds = %02.2fMbytes/sec",
    buffer_total, time_taken,
    (float)((float)buffer_total / (float)(time_taken)) / (float)1000000);
  fprintf(stdout, "\n");



  exit(0);
}
