/*

                                   _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-2010
       "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

*/

/* ulirc.c :: Midnight Code UDP LIRC client 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>
#include "ulirc.h"


u_int8_t * packet_data;
int code_length;
int packet_length;


int
remote_to_lirc(
                     struct remote_head_t * remotes) {
  struct remote_element_t * remote;
  char *buffer;
  char *buf_ptr;
  int cr_flag;
  int buffer_size;


  if(!remotes)
    return -1;

  fprintf(stdout, "#\n");

  buffer_size = midnightcode_logo_buffer(&buffer, 0,
    MIDNIGHTCODE_COLOUR_STYLE_ASCII);
  if(buffer == NULL)
    return -1;
  if(buffer_size <= 0) {
    if(buffer)
      free(buffer);
    return -1;
  }
  cr_flag = 1;
  for(buf_ptr = buffer; *buf_ptr != '\0'; buf_ptr++) {
    if(cr_flag)
      fprintf(stdout, "# ");
    fprintf(stdout, "%c", *buf_ptr);
    if(*buf_ptr == 0x0a) {
      cr_flag = 1;
    } else {
      cr_flag = 0;
    }
  }
  free(buffer);

  buffer_size = midnightcode_license_buffer(&buffer, 0,
    MIDNIGHTCODE_COLOUR_STYLE_ASCII, MIDNIGHTCODE_LICENSE_TEXT_ALL);
  if(buffer == NULL)
    return -1;
  if(buffer_size <= 0) {
    if(buffer)
      free(buffer);
    return -1;
  }
  for(buf_ptr = buffer; *buf_ptr != '\0'; buf_ptr++) {
    if(cr_flag)
      fprintf(stdout, "# ");
    fprintf(stdout, "%c", *buf_ptr);
    if(*buf_ptr == 0x0a) {
      cr_flag = 1;
    } else {
      cr_flag = 0;
    }
  }
  free(buffer);

  midnightcode_list_for_each(remote, remotes) {

    fprintf(stdout, "\n");
    fprintf(stdout, "begin remote\n");
    fprintf(stdout, "\n");
    fprintf(stdout, "  name\t\t%s\n", remote->name);
    fprintf(stdout, "\n");
    fprintf(stdout, "  bits\t\t%d\n", remote->signal_data_bits);
    fprintf(stdout, "  flags\t\tSPACE_ENC|CONST_LENGTH\n");
    fprintf(stdout, "\n");
    fprintf(stdout, "  eps\t\t30\n");
    fprintf(stdout, "  aeps\t\t100\n");

    /* SIGNALS ----------------------------------------------------------- */

    fprintf(stdout, "  header\t%d\t%d\n",
      remote->signal_header_pulse, remote->signal_header_space);
    fprintf(stdout, "  one\t\t%d\t%d\n",
      remote->signal_one_pulse, remote->signal_one_space);
    fprintf(stdout, "  zero\t\t%d\t%d\n",
      remote->signal_zero_pulse, remote->signal_zero_space);
    fprintf(stdout, "  ptrail\t%d\n",
      remote->signal_trail_pulse);
    fprintf(stdout, "  gap\t\t%d\n",
      remote->signal_gap_space);
    fprintf(stdout, "  toggle_bit\t0\n");

    /* BUTTONS ----------------------------------------------------------- */

    fprintf(stdout, "\n");
    fprintf(stdout, "  begin codes\n");
    fprintf(stdout, "  \tVolDown\t\t\t%s\n", remote->button_voldown_s);
    fprintf(stdout, "  \tVolUp\t\t\t%s\n", remote->button_volup_s);
    fprintf(stdout, "  \tMute\t\t\t%s\n", remote->button_mute_s);
    fprintf(stdout, "  \tChanUp\t\t\t%s\n", remote->button_chanup_s);
    fprintf(stdout, "  \tChanDown\t\t%s\n", remote->button_chandown_s);
    fprintf(stdout, "  \tUp\t\t\t%s\n", remote->button_up_s);
    fprintf(stdout, "  \tDown\t\t\t%s\n", remote->button_down_s);
    fprintf(stdout, "  \tLeft\t\t\t%s\n", remote->button_left_s);
    fprintf(stdout, "  \tRight\t\t\t%s\n", remote->button_right_s);
    fprintf(stdout, "  \tEnter\t\t\t%s\n", remote->button_enter_s);
    fprintf(stdout, "  \tRewind\t\t\t%s\n", remote->button_rewind_s);
    fprintf(stdout, "  \tPlay\t\t\t%s\n", remote->button_play_s);
    fprintf(stdout, "  \tForward\t\t\t%s\n", remote->button_forward_s);
    fprintf(stdout, "  \tStop\t\t\t%s\n", remote->button_stop_s);
    fprintf(stdout, "  \tPause\t\t\t%s\n", remote->button_pause_s);
    fprintf(stdout, "  end codes\n");
    fprintf(stdout, "\n");

    fprintf(stdout, "end remote\n");
  }
  fflush(stdout);

  return 0;
}


int
button_code_to_number(
                     long long * remote_code_n,
                     char * remote_code_s) {
  const char * num_ptr;
  char * end_ptr;
  long long value;
  int ret_i;

  ret_i = -1;
  num_ptr = remote_code_s;
  errno = 0;
  value = strtoll(num_ptr, &end_ptr, 0);
  if(errno == ERANGE || (errno != 0 && value == 0)) {
    perror("strtol");
    return ret_i;
  }
  if(end_ptr - num_ptr == strlen(num_ptr) && end_ptr != num_ptr) {
    ret_i = 0;
    *remote_code_n = value;
  }

  return ret_i;
}


int
remote_from_config(
                     struct remote_head_t * remote_elements,
                     struct midnightcode_config_head_t * config_elements) {
  struct remote_element_t * remote_element;
  struct midnightcode_config_section_element_t * section_element;
  struct midnightcode_config_section_element_t * hold_section_element;
  struct midnightcode_config_section_head_t * section_elements;
  void * tmp_void_p;
  int ret_i;
  midnightcode_list_init(config_section_struct_head,
                         midnightcode_config_section_element_t);


  if(!remote_elements || !config_elements)
    return -1;

  tmp_void_p = (void *)&config_section_struct_head;
  section_elements = tmp_void_p;

  if(!midnightcode_config_get_sections(config_elements,
                                       section_elements,
                                       REMOTE_STRUCTURE))
    return -1;

  ret_i = 0;
  midnightcode_list_for_each_safe(section_element, hold_section_element,
    section_elements) {

    remote_element = malloc(
                          sizeof(struct remote_element_t));
    if(!remote_element)
      break;
    memset(remote_element, 0,
      sizeof(struct remote_element_t));

    snprintf(remote_element->name, 63, "%s", section_element->section);

    /* SERVER ------------------------------------------------------------ */

    ret_i = -1;
    if(midnightcode_config_get_pair(config_elements,
                                    REMOTE_STRUCTURE,
                                    remote_element->name,
                                    "lirc_server",
                                    &remote_element->lirc_address, 0,
                                    MIDNIGHTCODE_PARSE_TYPE_HOST)) {
      break;
    } else {
      inet_ntop(AF_INET, &remote_element->lirc_address,
        remote_element->lirc_address_s, 31);
    }

    if(midnightcode_config_get_pair(config_elements,
                                    REMOTE_STRUCTURE,
                                    remote_element->name,
                                    "lirc_port",
                                    &remote_element->lirc_port, 0,
                                    MIDNIGHTCODE_PARSE_TYPE_INT))
      break;

    /* SIGNALS ----------------------------------------------------------- */

    if(midnightcode_config_get_pair(config_elements,
                                    REMOTE_STRUCTURE,
                                    remote_element->name,
                                    "signal_data_bits",
                                    &remote_element->signal_data_bits, 0,
                                    MIDNIGHTCODE_PARSE_TYPE_INT))
      break;

    if(midnightcode_config_get_pair(config_elements,
                                    REMOTE_STRUCTURE,
                                    remote_element->name,
                                    "signal_header_pulse",
                                    &remote_element->signal_header_pulse, 0,
                                    MIDNIGHTCODE_PARSE_TYPE_INT))
      break;

    if(midnightcode_config_get_pair(config_elements,
                                    REMOTE_STRUCTURE,
                                    remote_element->name,
                                    "signal_header_space",
                                    &remote_element->signal_header_space, 0,
                                    MIDNIGHTCODE_PARSE_TYPE_INT))
      break;

    if(midnightcode_config_get_pair(config_elements,
                                    REMOTE_STRUCTURE,
                                    remote_element->name,
                                    "signal_one_pulse",
                                    &remote_element->signal_one_pulse, 0,
                                    MIDNIGHTCODE_PARSE_TYPE_INT))
      break;

    if(midnightcode_config_get_pair(config_elements,
                                    REMOTE_STRUCTURE,
                                    remote_element->name,
                                    "signal_one_space",
                                    &remote_element->signal_one_space, 0,
                                    MIDNIGHTCODE_PARSE_TYPE_INT))
      break;

    if(midnightcode_config_get_pair(config_elements,
                                    REMOTE_STRUCTURE,
                                    remote_element->name,
                                    "signal_zero_pulse",
                                    &remote_element->signal_zero_pulse, 0,
                                    MIDNIGHTCODE_PARSE_TYPE_INT))
      break;

    if(midnightcode_config_get_pair(config_elements,
                                    REMOTE_STRUCTURE,
                                    remote_element->name,
                                    "signal_zero_space",
                                    &remote_element->signal_zero_space, 0,
                                    MIDNIGHTCODE_PARSE_TYPE_INT))
      break;

    if(midnightcode_config_get_pair(config_elements,
                                    REMOTE_STRUCTURE,
                                    remote_element->name,
                                    "signal_trail_pulse",
                                    &remote_element->signal_trail_pulse, 0,
                                    MIDNIGHTCODE_PARSE_TYPE_INT))
      break;

    if(midnightcode_config_get_pair(config_elements,
                                    REMOTE_STRUCTURE,
                                    remote_element->name,
                                    "signal_gap_space",
                                    &remote_element->signal_gap_space, 0,
                                    MIDNIGHTCODE_PARSE_TYPE_INT))
      break;

    /* BUTTONS ----------------------------------------------------------- */

    if(midnightcode_config_get_pair(config_elements,
                                    REMOTE_STRUCTURE,
                                    remote_element->name,
                                    "button_voldown",
                                    &remote_element->button_voldown_s, 16,
                                    MIDNIGHTCODE_PARSE_TYPE_STRING))
      break;

    if(button_code_to_number(&remote_element->button_voldown_n,
      (char *)&remote_element->button_voldown_s))
      break;

    if(midnightcode_config_get_pair(config_elements,
                                    REMOTE_STRUCTURE,
                                    remote_element->name,
                                    "button_volup",
                                    &remote_element->button_volup_s, 16,
                                    MIDNIGHTCODE_PARSE_TYPE_STRING))
      break;

    if(button_code_to_number(&remote_element->button_volup_n,
      (char *)&remote_element->button_volup_s))
      break;

    if(midnightcode_config_get_pair(config_elements,
                                    REMOTE_STRUCTURE,
                                    remote_element->name,
                                    "button_mute",
                                    &remote_element->button_mute_s, 16,
                                    MIDNIGHTCODE_PARSE_TYPE_STRING))
      break;

    if(button_code_to_number(&remote_element->button_mute_n,
      (char *)&remote_element->button_mute_s))
      break;

    if(midnightcode_config_get_pair(config_elements,
                                    REMOTE_STRUCTURE,
                                    remote_element->name,
                                    "button_chanup",
                                    &remote_element->button_chanup_s, 16,
                                    MIDNIGHTCODE_PARSE_TYPE_STRING))
      break;

    if(button_code_to_number(&remote_element->button_chanup_n,
      (char *)&remote_element->button_chanup_s))
      break;

    if(midnightcode_config_get_pair(config_elements,
                                    REMOTE_STRUCTURE,
                                    remote_element->name,
                                    "button_chandown",
                                    &remote_element->button_chandown_s, 16,
                                    MIDNIGHTCODE_PARSE_TYPE_STRING))
      break;

    if(button_code_to_number(&remote_element->button_chandown_n,
      (char *)&remote_element->button_chandown_s))
      break;

    if(midnightcode_config_get_pair(config_elements,
                                    REMOTE_STRUCTURE,
                                    remote_element->name,
                                    "button_up",
                                    &remote_element->button_up_s, 16,
                                    MIDNIGHTCODE_PARSE_TYPE_STRING))
      break;

    if(button_code_to_number(&remote_element->button_up_n,
      (char *)&remote_element->button_up_s))
      break;

    if(midnightcode_config_get_pair(config_elements,
                                    REMOTE_STRUCTURE,
                                    remote_element->name,
                                    "button_down",
                                    &remote_element->button_down_s, 16,
                                    MIDNIGHTCODE_PARSE_TYPE_STRING))
      break;

    if(button_code_to_number(&remote_element->button_down_n,
      (char *)&remote_element->button_down_s))
      break;

    if(midnightcode_config_get_pair(config_elements,
                                    REMOTE_STRUCTURE,
                                    remote_element->name,
                                    "button_left",
                                    &remote_element->button_left_s, 16,
                                    MIDNIGHTCODE_PARSE_TYPE_STRING))
      break;

    if(button_code_to_number(&remote_element->button_left_n,
      (char *)&remote_element->button_left_s))
      break;

    if(midnightcode_config_get_pair(config_elements,
                                    REMOTE_STRUCTURE,
                                    remote_element->name,
                                    "button_right",
                                    &remote_element->button_right_s, 16,
                                    MIDNIGHTCODE_PARSE_TYPE_STRING))
      break;

    if(button_code_to_number(&remote_element->button_right_n,
      (char *)&remote_element->button_right_s))
      break;

    if(midnightcode_config_get_pair(config_elements,
                                    REMOTE_STRUCTURE,
                                    remote_element->name,
                                    "button_enter",
                                    &remote_element->button_enter_s, 16,
                                    MIDNIGHTCODE_PARSE_TYPE_STRING))
      break;

    if(button_code_to_number(&remote_element->button_enter_n,
      (char *)&remote_element->button_enter_s))
      break;

    if(midnightcode_config_get_pair(config_elements,
                                    REMOTE_STRUCTURE,
                                    remote_element->name,
                                    "button_rewind",
                                    &remote_element->button_rewind_s, 16,
                                    MIDNIGHTCODE_PARSE_TYPE_STRING))
      break;

    if(button_code_to_number(&remote_element->button_rewind_n,
      (char *)&remote_element->button_rewind_s))
      break;

    if(midnightcode_config_get_pair(config_elements,
                                    REMOTE_STRUCTURE,
                                    remote_element->name,
                                    "button_play",
                                    &remote_element->button_play_s, 16,
                                    MIDNIGHTCODE_PARSE_TYPE_STRING))
      break;

    if(button_code_to_number(&remote_element->button_play_n,
      (char *)&remote_element->button_play_s))
      break;

    if(midnightcode_config_get_pair(config_elements,
                                    REMOTE_STRUCTURE,
                                    remote_element->name,
                                    "button_forward",
                                    &remote_element->button_forward_s, 16,
                                    MIDNIGHTCODE_PARSE_TYPE_STRING))
      break;

    if(button_code_to_number(&remote_element->button_forward_n,
      (char *)&remote_element->button_forward_s))
      break;

    if(midnightcode_config_get_pair(config_elements,
                                    REMOTE_STRUCTURE,
                                    remote_element->name,
                                    "button_stop",
                                    &remote_element->button_stop_s, 16,
                                    MIDNIGHTCODE_PARSE_TYPE_STRING))
      break;

    if(button_code_to_number(&remote_element->button_stop_n,
      (char *)&remote_element->button_stop_s))
      break;

    if(midnightcode_config_get_pair(config_elements,
                                    REMOTE_STRUCTURE,
                                    remote_element->name,
                                    "button_pause",
                                    &remote_element->button_pause_s, 16,
                                    MIDNIGHTCODE_PARSE_TYPE_STRING))
      break;

    if(button_code_to_number(&remote_element->button_pause_n,
      (char *)&remote_element->button_pause_s))
      break;

    ret_i = 0;
    midnightcode_list_append(remote_elements, remote_element);

    midnightcode_list_remove(section_elements, section_element);
    if(section_element != NULL)
      free(section_element);

    midnightcode_list_for_each_safe_loop(section_element, hold_section_element,
      section_elements);
  }
  midnightcode_list_for_each_safe(section_element, hold_section_element,
    section_elements) {
    midnightcode_list_remove(section_elements, section_element);
    if(section_element != NULL)
      free(section_element);
    midnightcode_list_for_each_safe_loop(section_element, hold_section_element,
      section_elements);
  }


  return ret_i;
}


u_int8_t
get_high_byte(
                     int code) {
  unsigned int value;
  u_int8_t ret_i;

  value = (code * 256) / 15625;
  value = value / 256;
  ret_i = (u_int8_t)value;

  return ret_i;
}


u_int8_t
get_low_byte(
                     int code) {
  unsigned int value;
  u_int8_t ret_i;

  value = (code * 256) / 15625;
  value = value % 256;
  ret_i = (u_int8_t)value;

  return ret_i;
}


int
packet_init(
                     struct remote_element_t * remote) {
  int pd_offset;

  /*
      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
      | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
      |        Gap Space (Low)        |        Gap Space (High)       |
      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
      |      Header Pulse (Low)       |      Header Pulse (High)      |
      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
      |      Header Space (Low)       |      Header Space (High)      |
      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+

  Button (Byte n, Bit n): 5 bytes x 8 bits = 40 messages x 4 bytes
      .                                                               .
      :                                                               :
      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
      |     [One|Zero] Pulse (Low)    |    [One|Zero] Pulse (High)    |
      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
      |     [One|Zero] Space (Low)    |    [One|Zero] Space (High)    |
      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
      :                                                               :
      .                                                               .

      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
      |       Trail Pulse (Low)       |      Trail Pulse (High)       |
      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
  */


  if(!remote)
    return -1;
  code_length = remote->signal_data_bits / 8;
  packet_length = 6 + (remote->signal_data_bits * 4) + 2;
  packet_data = malloc(packet_length);
  if(!packet_data)
    return -1;
  memset(packet_data, 0, packet_length);

  pd_offset = 0;
  *(packet_data + pd_offset++) = get_low_byte(remote->signal_gap_space);
  *(packet_data + pd_offset++) =
    get_high_byte(remote->signal_gap_space) | 0x080;
  *(packet_data + pd_offset++) = get_low_byte(remote->signal_header_pulse);
  *(packet_data + pd_offset++) = get_high_byte(remote->signal_header_pulse);
  *(packet_data + pd_offset++) = get_low_byte(remote->signal_header_space);
  *(packet_data + pd_offset++) =
    get_high_byte(remote->signal_header_space) | 0x080;

  pd_offset = 6 + (remote->signal_data_bits * 4);
  *(packet_data + pd_offset++) = get_low_byte(remote->signal_trail_pulse);
  *(packet_data + pd_offset++) = get_high_byte(remote->signal_trail_pulse);


  return 0;
}


int
packet_code(
                     struct remote_element_t * remote,
                     long long code) {
  int pd_offset;
  int bit;
  int byte;
  u_int8_t data;
  u_int8_t mask;
  u_int8_t * uint_p;

  uint_p = (u_int8_t *)&code;
  pd_offset = 6;

  if(!remote)
    return -1;
  for(byte = code_length - 1; byte >= 0; byte--) {
    data = *(uint_p + byte);
    for(bit = 7; bit >= 0; bit--) {
      mask = 1 << bit;
      if((data & mask) == 0) {
        *(packet_data + pd_offset++) = get_low_byte(remote->signal_zero_pulse);
        *(packet_data + pd_offset++) = get_high_byte(remote->signal_zero_pulse);
        *(packet_data + pd_offset++) = get_low_byte(remote->signal_zero_space);
        *(packet_data + pd_offset++) = 
          get_high_byte(remote->signal_zero_space) | 0x080;
      } else {
        *(packet_data + pd_offset++) = get_low_byte(remote->signal_one_pulse);
        *(packet_data + pd_offset++) = get_high_byte(remote->signal_one_pulse);
        *(packet_data + pd_offset++) = get_low_byte(remote->signal_one_space);
        *(packet_data + pd_offset++) = 
          get_high_byte(remote->signal_one_space) | 0x080;
      }
    }
  }

  return 0;
}


int
packet_send(
                     struct remote_element_t * remote) {

  struct sockaddr_in si_other;
  int sock;

  if(!remote)
    return -1;
  if((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
    return -1;

  memset((char *) &si_other, 0, sizeof(si_other));
  si_other.sin_family = AF_INET;
  si_other.sin_addr.s_addr = inet_addr(remote->lirc_address_s);
  si_other.sin_port = htons(remote->lirc_port);

  if(sendto(sock, packet_data, packet_length, 0, 
    (struct sockaddr *)&si_other, sizeof(si_other)) == -1) {
    perror("sendto");
    return -1;
  }

  close(sock);

  return 0;
}


long long 
code_for_button(
                     struct remote_element_t * remote,
                     char * cfg_send) {

  if(!remote)
    return -1;

  if(!strcasecmp("voldown", cfg_send))
    return remote->button_voldown_n;
  if(!strcasecmp("volup", cfg_send))
    return remote->button_volup_n;
  if(!strcasecmp("mute", cfg_send))
    return remote->button_mute_n;
  if(!strcasecmp("chanup", cfg_send))
    return remote->button_chanup_n;
  if(!strcasecmp("chandown", cfg_send))
    return remote->button_chandown_n;
  if(!strcasecmp("up", cfg_send))
    return remote->button_up_n;
  if(!strcasecmp("down", cfg_send))
    return remote->button_down_n;
  if(!strcasecmp("left", cfg_send))
    return remote->button_left_n;
  if(!strcasecmp("right", cfg_send))
    return remote->button_right_n;
  if(!strcasecmp("enter", cfg_send))
    return remote->button_enter_n;
  if(!strcasecmp("rewind", cfg_send))
    return remote->button_rewind_n;
  if(!strcasecmp("play", cfg_send))
    return remote->button_play_n;
  if(!strcasecmp("forward", cfg_send))
    return remote->button_forward_n;
  if(!strcasecmp("stop", cfg_send))
    return remote->button_stop_n;
  if(!strcasecmp("pause", cfg_send))
    return remote->button_pause_n;

  return -1;
}


int
main(int argc, char **argv) {
  int cfg_help = 0;
  int cfg_lirc = 0;
  char cfg_file[128];
  char cfg_remote[128];
  char cfg_send[128];
  struct midnightcode_config_head_t * config_list_head_p;
  struct remote_head_t * remotes;
  struct remote_element_t * remote;
  long long button_n;
  void * tmp_void_p;
  int ret_i;

 
  // Prepare switches
  struct midnightcode_switch_t switches[] = {
    { "c", "config", "Config file [ulirc.cfg]",
      MIDNIGHTCODE_PARSE_TYPE_STRING, 64, 0, &cfg_file },
    { "l", "lirc", "Generate lirc.conf-kinect and exit",
      MIDNIGHTCODE_PARSE_TYPE_NONE, 0, 0, &cfg_lirc },
    { "r", "remote", "Which remote this button is for [kinect]",
      MIDNIGHTCODE_PARSE_TYPE_STRING, 64, 0, &cfg_remote },
    { "s", "send", "Which button is to be sent [play]",
      MIDNIGHTCODE_PARSE_TYPE_STRING, 64, 0, &cfg_send },
    { "h", "help", "Display this help/usage screen",
      MIDNIGHTCODE_PARSE_TYPE_NONE, 0, 0, &cfg_help },
    { 0 }
  };


  // Set-up initial values;
  memset(&cfg_file, 0, sizeof(cfg_file));
  snprintf(cfg_file, sizeof(cfg_file), "ulirc.cfg");
  memset(&cfg_remote, 0, sizeof(cfg_remote));
  snprintf(cfg_remote, sizeof(cfg_remote), "kinect");
  memset(&cfg_send, 0, sizeof(cfg_send));
  snprintf(cfg_send, sizeof(cfg_send), "play");
  cfg_lirc = 0;
  cfg_help = 0;

  midnightcode_list_init(config_struct_head,
                         midnightcode_config_element_t);
  tmp_void_p = (void *)&config_struct_head;
  config_list_head_p = tmp_void_p;
  midnightcode_list_init(remote_struct_head,
                         remote_element_t);
  tmp_void_p = (void *)&remote_struct_head;
  remotes = tmp_void_p;


  // 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);


  // Generate lircd.conf-kinect and exit
  if(cfg_lirc) {
    if((ret_i = midnightcode_config_read_file(cfg_file,
                           config_list_head_p,
                           MIDNIGHTCODE_CONFIG_TYPE_NEWSET,
                           MIDNIGHTCODE_CONFIG_OPTION_AUTONEW |
                           MIDNIGHTCODE_CONFIG_OPTION_MERGEARGS |
                           MIDNIGHTCODE_CONFIG_OPTION_SILENT )) != 0) {
      fprintf(stdout, "Error: failed to load and parse config file %s\n",
        cfg_file);
      fflush(stdout);
      exit(1);
    }
    if(remote_from_config(remotes, config_list_head_p) != 0) {
      fprintf(stdout, "Error: failed to retrieve configuration from file %s\n",
        cfg_file);
      fflush(stdout);
      exit(1);
    }
    remote_to_lirc(remotes);
    exit(0);
  }


  // 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, "UDP LIRC client: %s", argv[0]);

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


  midnightcode_status_text(MIDNIGHTCODE_STATUS_TYPE_TEXT,
                           MIDNIGHTCODE_STATUS_STYLE_NORMAL,
                           "Config file [%s] load and parse",
                           cfg_file);
  if((ret_i = midnightcode_config_read_file(cfg_file,
                           config_list_head_p,
                           MIDNIGHTCODE_CONFIG_TYPE_NEWSET,
                           MIDNIGHTCODE_CONFIG_OPTION_AUTONEW |
                           MIDNIGHTCODE_CONFIG_OPTION_MERGEARGS |
                           MIDNIGHTCODE_CONFIG_OPTION_SILENT )) != 0) {
    midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_FAIL);
    fflush(stdout);
    exit(1);
  } else {
    midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_OKAY);
  }

  midnightcode_status_text(MIDNIGHTCODE_STATUS_TYPE_TEXT,
                           MIDNIGHTCODE_STATUS_STYLE_NORMAL,
                           "Retrieving remote configuration");
  if(remote_from_config(remotes, config_list_head_p) != 0) {
    midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_FAIL);
    fflush(stdout);
    exit(1);
  } else {
    midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_OKAY);
  }

  midnightcode_list_for_each(remote, remotes) {

    if(!strcasecmp(cfg_remote, remote->name)) {
  
      midnightcode_status_text(MIDNIGHTCODE_STATUS_TYPE_TEXT,
                               MIDNIGHTCODE_STATUS_STYLE_NORMAL,
                               "Remote match [%s]", remote->name);
      midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_OKAY);

      midnightcode_status_text(MIDNIGHTCODE_STATUS_TYPE_TEXT,
                               MIDNIGHTCODE_STATUS_STYLE_NORMAL,
                               "Packet Init");
      if(packet_init(remote) != 0) {
        midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_FAIL);
        fflush(stdout);
        exit(1);
      } else {
        midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_OKAY);
      }

      midnightcode_status_text(MIDNIGHTCODE_STATUS_TYPE_TEXT,
                               MIDNIGHTCODE_STATUS_STYLE_NORMAL,
                               "Finding code for button [%s]", cfg_send);
      if((button_n = code_for_button(remote, cfg_send)) < 0) {
        midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_FAIL);
        fflush(stdout);
        exit(1);
      } else {
        midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_OKAY);
      }

      midnightcode_status_text(MIDNIGHTCODE_STATUS_TYPE_TEXT,
                               MIDNIGHTCODE_STATUS_STYLE_NORMAL,
                               "Packet built for [%s]", cfg_send);
      if(packet_code(remote, button_n) != 0) {
        midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_FAIL);
        fflush(stdout);
        exit(1);
      } else {
        midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_OKAY);
      }

      midnightcode_status_text(MIDNIGHTCODE_STATUS_TYPE_TEXT,
                               MIDNIGHTCODE_STATUS_STYLE_NORMAL,
                               "Packet sent");
      if(packet_send(remote) != 0) {
        midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_FAIL);
        fflush(stdout);
        exit(1);
      } else {
        midnightcode_status_flag(MIDNIGHTCODE_STATUS_FLAG_OKAY);
      }

    }

  }

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

  exit(0);
}



