/***************************************************************************
 *   copyright           : (C) 2004 by Hendrik Sattler                     *
 *   mail                : post@hendrik-sattler.de                         *
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 ***************************************************************************/

#include "smifile.h"
#include <helper.h>
#include <options.h>
#include <disclaimer.h>

#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <locale.h>

static
struct sms_slot_data* smifile_get_slot_data (const struct smi_entry* ptr) {
  struct sms_slot_data* encoded = NULL;

  encoded = mem_alloc(sizeof(*encoded),0);
  sms_slot_data_init(encoded);

  /* inpect the direction code */
  switch (ptr->status) {
  case SMI_READ:
  case SMI_UNREAD:
    encoded->dir = SMS_INCOMING;
    break;
  case SMI_SENT:
  case SMI_UNSENT:
    encoded->dir = SMS_OUTGOING;
    break;
  default:
    return mem_realloc(encoded,0);
  }

  /* copy the PDU data */
  memcpy(encoded->tpdu.data,ptr->data,SMI_DATA_SIZE);

  /* fix the size */
  encoded->tpdu.size = SMI_DATA_SIZE;
  encoded->tpdu.size = sms_tpdu_len(encoded->dir,&encoded->tpdu);
  if (encoded->tpdu.size == 0) return encoded = mem_realloc(encoded,0);
  else encoded->tpdu.size += encoded->tpdu.data[0]+1;

  return encoded;
}

static
struct sms_slot_data** smifile_get_all_slot_data (uint8_t* ptr,
						  unsigned int headersize,
						  unsigned int message_count,
						  char* file)
{
  struct sms_slot_data** messages = mem_alloc((message_count+1)*sizeof(*messages),0);
  unsigned int i = 0;
  unsigned int offset = 0;

  while(i+offset < message_count) {
    ptr += headersize;
    messages[i] = smifile_get_slot_data((struct smi_entry*)ptr);
    if (messages[i] == NULL) ++offset;
    else ++i;
    ptr += sizeof(struct smi_entry);
  }
  messages[i] = NULL;

  if (message_count > i) {
    fprintf(stderr,"%s: %s\n",file,"Warning: not all message were decoded due to errors");
  }
  return messages;
}
  
struct sms_slot_data** smifile_read (char* file) {
  struct mmapped_file fs;
  struct smi_header* ptr;
  uint16_t headersize = 0;
  unsigned int extraheader = 0; //header before each entry (to skip)
  unsigned int message_count = 0;


  if (mem_map(file,&fs) < 0) {
    fprintf(stderr,"%s: %s\n",file,strerror(errno));
    exit(EXIT_FAILURE);
  }

  ptr = (struct smi_header*)fs.ptr;
  
  //check the magic strings
  if (ptr->magic[0] == 0x0b && ptr->magic[1] == 0x0b) {
    /* This handles the .smi and .smo files that come from
     * the /SMS/ flexmem folder.
     */
    headersize = sizeof(struct smi_header)+letohs(ptr->headerlen);

    fprintf(stderr,"This is a file from the following model: ");
    switch(ptr->format) {
    case SMI_FORMAT_SL42:
      fprintf(stderr,"SL42/SL45");
      break;
    case SMI_FORMAT_S55:
      fprintf(stderr,"S55");
#ifdef DEBUG
      fprintf(stderr,"\nMessages (total): %d",((struct smi_head_s55*)(ptr+1))->parts.total);
      fprintf(stderr,"\nMessages (file): %d",((struct smi_head_s55*)(ptr+1))->parts.file);
      fprintf(stderr,"\nUnknown part: 0x%04x",((struct smi_head_s55*)(ptr+1))->unknown1);
      fprintf(stderr,"\nUnknown part: 0x%02x",((struct smi_head_s55*)(ptr+1))->unknown2);
      fprintf(stderr,"\nData starts at 0x%x",headersize);
#endif
      break;
    }
    fprintf(stderr,"\n");


  } else if (ptr->magic[0] == 0xff && ptr->magic[1] == 0xff) {
    /* This handles the SMS.dat file that comes from
     * the /PersistentData/SMS/ flexmem folder.
     */
    headersize = 2;
    extraheader = 2;

  } else {
    fprintf(stderr,"%s: %s\n",file,"not a Siemens short message file");
    exit(EXIT_FAILURE);      
  }

  if (((fs.size - headersize)%(sizeof(struct smi_entry)+extraheader)) != 0) {
    fprintf(stderr,"%s: %s\n",file,"file size does not match expected size");
    exit(EXIT_FAILURE);
  } else {
    message_count = (fs.size - headersize)/(sizeof(struct smi_entry)+extraheader);
  }
  if (message_count == 0) return NULL;

  return smifile_get_all_slot_data(((uint8_t*)fs.ptr)+headersize,extraheader,message_count,file);

  mem_unmap(&fs);
}
