
/*
 *  read GSM SMS
 *
 *  Peter M. Dambier  2002-10-06
 */


#include <stdio.h>
#include "gsmdev.h"


/*
 * find next token; terminate (0) this token
 */

char *nextoken( pbuf )
   unsigned char *pbuf;
{
   if( *pbuf == 0 )
      return( pbuf );

   while( *pbuf != '\r' )
      pbuf++;

   *pbuf = 0;
   pbuf++;

   while( (*pbuf == '\n') || (*pbuf == '\r') )
      pbuf++;

   return( pbuf );
}


/*
 * get result
 */
 
int result( cmd, answer, buffer )
   char *cmd, *answer, buffer[];
{
   char *ucmd, *uresult, *ucode;
 
   com_exch( cmd, buffer, 8192 );
 
   ucmd    = buffer;
   uresult = nextoken( ucmd );
   ucode   = nextoken( uresult );
   nextoken( ucode );
 
   sprintf( answer, uresult );
 
   if( strcmp( ucode, "OK" ) == 0 )
      return( 0 );
 
   if( strcmp( uresult, "OK" ) == 0 )
      return( 0 );
 
   printf( ">>> (%s) (%s) (%s) <<<\n", ucmd, uresult, ucode );
 
   return( 1 );
}


/*
 * time stamp
 */

show_time( fd, txt )
   int fd;
   char *txt;
{
   char buffer[40];

   clock_get( buffer );
   fprintf( fd, "# %s %s\n", txt, buffer );
}


/*
 * gsm time >>> cp/m
 */
 
date2cpm( date )
   char date[];
{
  char year[3], month[3], day[3],
       hour[3], min[3], sec[3];
 
  year[0]  = date[8];   year[1]  = date[9];    year[2]  = 0;
  month[0] = date[11];  month[1] = date[12];   month[2] = 0;
  day[0]   = date[14];  day[1]   = date[15];   day[2]   = 0;
 
  hour[0]  = date[17];  hour[1]  = date[18];   hour[2]  = 0;
  min[0]   = date[20];  min[1]   = date[21];   min[2]   = 0;
  sec[0]   = date[23];  sec[1]   = date[24];   sec[2]   = 0;
 
  sprintf( date, "%s/%s/%s,%s:%s:%s",
     month, day, year,  hour, min, sec );
}


/*
 * identify hand held
 */
 
identify( brand, model, version, imei, imsi, gsmdate, battery )
   char *brand, *model, *version, *imei, *imsi, *gsmdate, *battery;
{
   char buffer[8192];
   int code;
 
   code = 0;
 
   result( "AT\r", buffer, buffer );
   result( "AT\r", buffer, buffer );
 
   code |= result( "AT+CGMI\r",  brand,   buffer );
   code |= result( "AT+CGMM\r",  model,   buffer );
   code |= result( "AT+CGMR\r",  version, buffer );
   code |= result( "AT+CGSN\r",  imei,    buffer );
   code |= result( "AT+CIMI\r",  imsi,    buffer );
   code |= result( "AT+CCLK?\r", gsmdate, buffer );
   code |= result( "AT+CBC\r",   battery, buffer );
 
   result( "AT\r", buffer, buffer );
 
   if( code == 0 )
      return( 0 );
 
   printf( "Error: reading handheld identification.\n" );
 
   return( 1 );
}


/*
 * get a character 7 bit, make printable
 */

char aget( ww )
   int ww;
{
   ww &= 0x7f;

   switch( ww )
   {
      case 0x00: return( '@' );
      case 0x01: return( '$' );
      case 0x02: return( '$' );
      case 0x03: return( '$' );
      case 0x04: return( 'e' );
      case 0x05: return( 'e' );
      case 0x06: return( 'u' );
      case 0x07: return( 'i' );
      case 0x08: return( 'o' );
      case 0x09: return( 'C' );
      case 0x0a: return( '\n' );
      case 0x0b: return( 'O' );
      case 0x0c: return( 'o' );
      case 0x0d: return( ' ' );
      case 0x0e: return( 'A' );
      case 0x0f: return( 'a' );

      case 0x10: return( 'd' );
      case 0x11: return( '-' );
      case 0x12: return( 'f' );
      case 0x13: return( 'd' );
      case 0x14: return( 'g' );
      case 0x15: return( 'o' );
      case 0x16: return( 'p' );
      case 0x17: return( 'x' );
      case 0x18: return( 's' );
      case 0x19: return( '0' );
      case 0x1a: return( '=' );
      case 0x1b: return( '1' );
      case 0x1c: return( 'A' );
      case 0x1d: return( 'a' );
      case 0x1e: return( 's' );
      case 0x1f: return( 'E' );

      case 0x40: return( 'i' );
      case 0x5b: return( 'A' );
      case 0x5c: return( 'O' );
      case 0x5d: return( 'N' );
      case 0x5e: return( 'U' );
      case 0x5f: return( '$' );

      case 0x60: return( '?' );
      case 0x7b: return( 'a' );
      case 0x7c: return( 'o' );
      case 0x7d: return( 'n' );
      case 0x7e: return( 'u' );
      case 0x7f: return( 'a' );
      default:   return( ww );
   }

   return( ww );
}


/*
 * unpack 8 ascii from 7 binary
 */

unpack8_x1( xin, xout )
   char xin[], xout[];
{
   int w1, w2, w3, w4, w5, w6;

   w1      = xin[1] + (xin[0] << 8);
   w2      = xin[2] + (xin[1] << 8);
   w3      = xin[3] + (xin[2] << 8);
   w4      = xin[4] + (xin[3] << 8);
   w5      = xin[5] + (xin[4] << 8);
   w6      = xin[6] + (xin[5] << 8);

   xout[0] = aget(w1 >> 9);    /* 0000 0001 1111 1122 */
   xout[1] = aget(w1 >> 2);
   xout[2] = aget(w2 >> 3);    /* 1111 1122 2222 2333 */
   xout[3] = aget(w3 >> 4);    /* 2222 2333 3333 4444 */
   xout[4] = aget(w4 >> 5);    /* 3333 4444 4445 5555 */
   xout[5] = aget(w5 >> 6);    /* 4445 5555 5566 6666 */
   xout[6] = aget(w6 >> 7);    /* 5566 6666 6777 7777 */
   xout[7] = aget( w6 );
   xout[8] = 0;
}


/*
 * unpack 8 ascii from 7 binary
 */

unpack8( xin, xout )
   char xin[], xout[];
{
   int w1, w2, w3, w4, w5, w6;

   /* 1000.000  2211.1111  3332.2222  4444.3333  5555.5444  6666.6655  7777.7776 */

   w1 = (xin[1] << 8) + xin[0];  /* 2211.1111 1000.0000 */
   w2 = (xin[2] << 8) + xin[1];  /* 3332.2222 2211.1111 */
   w3 = (xin[3] << 8) + xin[2];  /* 4444.3333 3332.2222 */
   w4 = (xin[4] << 8) + xin[3];  /* 5555.5444 4444.3333 */
   w5 = (xin[5] << 8) + xin[4];  /* 6666.6655 5555.5444 */
   w6 = (xin[6] << 8) + xin[5];  /* 7777.7776 6666.6655 */

   xout[0] = aget( w1 );
   xout[1] = aget( w1 >> 7 );
   xout[2] = aget( w2 >> 6 );
   xout[3] = aget( w3 >> 5 );
   xout[4] = aget( w4 >> 4 );
   xout[5] = aget( w5 >> 3 );
   xout[6] = aget( w6 >> 2 );
   xout[7] = aget( w6 >> 9 );
   xout[8] = 0;
}


/*
 * hex to binary
 */

int hex2bin( px, pa )
   char *px, *pa;
{
   static char x[18] = {"0123456789ABCDEFz"};
   int len;
   char nib1, nib2;

   len  = 0;
   nib1 = 0;
   nib2 = 0;

   while( (nib1 < 16) && (nib2 < 16) )
   {
      for( nib1 = 0; nib1 < 16; nib1++ )
         if( x[nib1] == *px )
            break;

      px++;

      for( nib2 = 0; nib2 < 16; nib2++ )
         if( x[nib2] == *px )
            break;

      px++;

      if( (nib1 < 16) && (nib2 < 16) )
      {
         *pa = (nib1 * 16) + nib2;
         len++;
      }
      else
         *pa = 0;

      pa++;
      *pa = 0;
   }

   return( len );
}


/*
 * get first gsm digit
 */


char dig1( x2dig )
   int x2dig;
{
   static char hexdig[18] = { "0123456789ABCDEF" };

   x2dig &= 0x0f;

   return( hexdig[ x2dig ] );
}


/*
 * get second gsm digit
 */


char dig2( x2dig )
   int x2dig;
{
   static char hexdig[18] = { "0123456789ABCDE " };

   x2dig  = x2dig >> 4;
   x2dig &= 0x0f;

   return( hexdig[ x2dig ] );
}


/*
 * get fone number
 */

char *get_fone( from, to )
   char *from, *to;
{
   int len, type, cnt, b1, b2;
   char buffer[40], *pbuf, *pfrom;

   pbuf  = buffer;

   len   = *from;
   from++;

   type  = *from;

   if( type == 0x91 )
   {
      from++;
      *pbuf = '+';
      pbuf++;
   }

   if( type == 0x81 )
      from++;

   if( type == 0xd1 )
      from++;

   *pbuf = 0;

   if( len )
   {
      if( (type == 0x91) || (type == 0x81) )
         for( cnt=1; cnt<len; cnt++ )
         {
            *pbuf = dig1(*from);
            pbuf++;
            *pbuf = dig2(*from);
            pbuf++;
            from++;
            *pbuf = 0;
         }
      else if( type == 0xd1 )
      {
         unpack8( from,    pbuf );
         unpack8( from +7, pbuf +8 );

         for( cnt = 0; cnt < 30; cnt++ )
            if( buffer[cnt] == '@' )
               buffer[cnt] = 0;

         while( *from != 0x00 )
            from++;
      }
   }

   b1 = *from; 
   from++;
   b2 = *from;
   from++;

   sprintf( to, "%s", buffer );

   return( from );
}


/*
 * hex dump 1 line
 */

hex_line( fd, buffer, len, xbuf )
   int fd, len, xbuf;
   char *buffer;
{
   int sum;

   sum = len + xbuf;

   fprintf( fd, ":%02x %02x  ", len, xbuf );

   while( len )
   {
      fprintf( fd, "%02x ", *buffer );
      sum += *buffer;
      len--;
      buffer++;
   }

   sum  = 0 - sum;
   sum &= 0xff;

   fprintf( fd, "  %02x\n", sum );
}


/*
 * hex dump
 */

hex_dump( fd, buffer, len )
   int fd, len;
   char *buffer;
{
   int xbuf, xlen;

   xbuf = 0;
   xlen = 20;

   while( len > xlen )
   {
      hex_line( fd, buffer, xlen, xbuf );
      buffer += xlen;
      xbuf   += xlen;
      len    -= xlen;
   }

   if( len )
      hex_line( fd, buffer, len, xbuf );
}


/*
 * dump sms file
 */

dump_sms( fd, cmd )
   int fd;
   char *cmd;
{
   char *here, *next;
   char buffer[8192];
   char *hdtxt, num1[48], num2[48], *pbin;
   char xbuf[256], abuf[80], bbuf[80], cbuf[80];
   int len, cnt, mlen, mtype;


   /* read all sms */

   com_exch( cmd, buffer, 8192 );

   here = buffer;

   while( *here != 0 )
   {
      next = nextoken( here );

      if( *here == '+' )
      {
         mtype = 0;
         hdtxt = here;
         here  = next;
         next  = nextoken( here );

         for( cnt = 0; cnt < 256; cnt++ )
            xbuf[cnt] = 0;

         len   = hex2bin( here, xbuf );

         pbin  = get_fone( xbuf, num1 );
         pbin  = get_fone( pbin, num2 );

         mlen  = *pbin;
         pbin++;

         if( mlen > 160 )
         {
            mtype = mlen -160;
            mlen  = *pbin;
            pbin++;
         }

         fprintf( fd, "# %s server: %s fone: %s\n", hdtxt, num1, num2 );
         printf( "%s server: %s fone: %s\n", hdtxt, num1, num2 );

         hex_dump( fd, xbuf, len );

         for( cnt = 0; cnt < 21; cnt++ )
         {
            unpack8( pbin, &abuf[8*cnt] );
            pbin+= 7;
         }

         for( cnt = 0; cnt < 160; cnt++ )
         {
            if( (abuf[cnt]=='@') && (abuf[cnt+1]=='@') && (abuf[cnt+2]=='@') )
            {
               abuf[cnt] = 0;
               break;
            }
         }

         fprintf( fd, "%s\n", abuf );
         printf( "%s\n", abuf );
      }

      here = next;
   }
}


/*
 * dump all
 */

dump_all( fd )
   int fd;
{
   char buffer[2048];
   char smsz[30], smst[30], ubuf[256];


   /* read all sms */

   result( "AT+CSCA?\r",  smsz, buffer );   /* number of SMS service center */
   result( "AT+CMGL=?\r", smst, buffer );   /* types of SMS supported */


   fprintf( fd, "# %s %s\n", smsz, smst );
   printf( "%s %s\n", smsz, smst );

   result( "AT+CMGF=0\r", ubuf, buffer ); /* pdu mode */

   dump_sms( fd, "AT+CMGL=4\r" );
}


/*
 *  * * *
 */

main( argc, argv )
    int argc;
    char *argv[];
{
    char gsmdate[30], ubuf[256], buffer[ 40 ];
    char imsi[30], imei[30], battery[30];
    char brand[30], model[30], version[30];
    char par1[30], par2[30], par3[30], buffer[256];
    int port, opfile, inifile;


    /* get parameters */

    port = 0;
    opfile = 0;

    inifile = fopen( "GSM.INI", "r" );
    
    if( inifile == 0 )
    {
       printf( "Error: Could not open (GSM.INI).\n" );
       exit( 1 );
    }   

    while( fgets( buffer, 256, inifile ) != 0 )
    {
       if( buffer[0] == '#' )
          continue;

       sscanf( buffer, "%s %s %s", par1, par2, par3 );

       if( strcmp( "=", par2 ) != 0 )
          continue;

       if( strcmp( "GSMPORT", par1 ) == 0 )
          port = atoi( par3 );

       if( strcmp( "SMSFILE", par1 ) == 0 )
          opfile = fopen( par3, "a" );
    }

    fclose( inifile );

    if( port == 0 )
    {
       printf( "Error: GSMPORT = 0\n" );
       fclose( opfile );
       exit( 1 );
    }

    if( opfile == 0 )
    {
       printf( "Error: SMSFILE = 0\n" );
       exit( 1 );
    }


    /* read handheld, dump */

    com_init( port );
    show_time( opfile, "Begin  GSM read SMS at" );

    if( identify( brand, model, version, imei, imsi, gsmdate, battery ) == 0 )
    {
       printf( "Hardware: %s %s %s   %s\n", brand, model, version, battery );
       printf( "IMEI/IMSI: %s %s\n", imei, imsi );

       clock_get( buffer );
       date2cpm( gsmdate );
       printf( "CP/M clock: %s   GSM clock: %s\n", buffer, gsmdate);

       fprintf( opfile, "# Hardware: %s %s %s\n", brand, model, version );
       fprintf( opfile, "# IMEI/IMSI: %s %s\n", imei, imsi );
       
       dump_all( opfile );
    }

    show_time( opfile, "Finish GSM read SMS at" );
    com_stop();
    fclose( opfile );
}


