/*
  Released under the antivirial license.  Basically, you can do anything
  you want with it as long as what you want doesn't involve the GNU GPL.
  See http://www.ecstaticlyrics.com/antiviral/ for more information.
*/

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <math.h>
#include <string.h>

int analyze_step () {

  static short audio_samples[8];
  static int schmitt = 0;

  /* Read the next sub-sample of a bit from stdin! */

  memmove(audio_samples, audio_samples + 1, 7 * sizeof(audio_samples[0]));
  if (0 >= fread(audio_samples + 7, sizeof(audio_samples[0]), 1, stdin)) exit(0);

  /* Analyze the samples for the presence of each frequency! */

  int mark_cos = audio_samples[0] + audio_samples[1] - audio_samples[4] - audio_samples[5];
  int mark_sin = audio_samples[2] + audio_samples[3] - audio_samples[6] - audio_samples[7];
  int mark = sqrt( mark_cos * mark_cos + mark_sin * mark_sin );

  int space_cos = audio_samples[0] - audio_samples[2] + audio_samples[4] - audio_samples[6];
  int space_sin = audio_samples[1] - audio_samples[3] + audio_samples[5] - audio_samples[7];
  int space = sqrt( space_cos * space_cos + space_sin * space_sin );

  int level = mark - space;

  /* Apply a minimal amount of schmitt-trigger action! */

  if (schmitt == 0) {
    if (level > 0) {
      schmitt = 1;
    };
  } else {
    if (level < 0) {
      schmitt = 0;
    };
  };

  return schmitt;

};

void wait_for_break() {

  BREAK_WAIT:

  for (int i = 0; i < 480; i++) {
    if (analyze_step() == 0) {
      goto BREAK_WAIT;
    };
  };

};

unsigned char receive_byte() {

  /* Wait until half-way into the start bit! */

  START_BIT_WAIT:

  for (int i = 0; i < 4; i++) {
    if (analyze_step() == 1) {
      goto START_BIT_WAIT;
    };
  };

  /* Then read each bit afterwards... */

  unsigned char byte = 0;
  for (int bit = 0; bit < 8; bit++) {
    for (int i = 1; i < 8; i++) {
      analyze_step();
    };
    byte += analyze_step() << bit;
  };

  /* Then suck up the stop bit! */;

  for (int i = 0; i < 8; i++) {
    analyze_step();
  };

  /* Happy, happy, joy, joy! */

  return byte;

};

int main() {

  /* Decode Caller ID data! */

  int type, length, size, checksum;

  FUCK:

    wait_for_break();

    type = receive_byte();
    if (type == 0x80) {
      printf("Caller ID with name detected!\n");
      length = receive_byte();
      while (length > 0) {
        type = receive_byte(); length--;
        if (type == 0x01) {
          size = receive_byte(); length--;
          if (size > length) goto ERROR;
          printf("Date: ");
          printf("%c", receive_byte()); length--;
          printf("%c", receive_byte()); length--;
          printf("/");
          printf("%c", receive_byte()); length--;
          printf("%c", receive_byte()); length--;
          printf(" ");
          printf("%c", receive_byte()); length--;
          printf("%c", receive_byte()); length--;
          printf(":");
          printf("%c", receive_byte()); length--;
          printf("%c", receive_byte()); length--;
          printf("\n");
        } else if (type == 0x07) {
          size = receive_byte(); length--;
          if (size > length) goto ERROR;
          printf("Name: ");
          for (int i = 0; i < size; i++) {
            printf("%c", receive_byte()); length--;
          };
          printf("\n");
        } else if (type == 0x02) {
          size = receive_byte(); length--;
          if (size > length) goto ERROR;
          printf("Phone: ");
          for (int i = 0; i < size; i++) {
            printf("%c", receive_byte()); length--;
          };
          printf("\n");
        } else {
          printf("Error: Unknown data type 0x%.2X in Caller ID message...\n", type);
          size = receive_byte(); length--;
          if (size > length) goto ERROR;
          printf("Data Type 0x%.2X:", type);
          for (int i = 0; i < size; i++) {
            printf(" 0x%.2X", receive_byte()); length--;
          };
          printf("\n");
        };
      };
      checksum = receive_byte();
      printf("End of Caller ID packet!\n");
    } else if (type == 0x04) {
      printf("Error: Caller ID without name detected!  I can only do Caller ID with name.\n");
    } else {
      printf("Error: Unknown CallerID message type 0x%.2X...\n", type);
    };

    fflush(stdout);

  goto FUCK;

  ERROR:

    printf("Error: Length of sub-message exceeds message length.\n");

    fflush(stdout);

  goto FUCK;

};
