/*
 * Kodowanie wiadmosci SMS w formacie 7 i 8 bitowym. Do kodowania
 * wiadomsci w formacie 7bitowym wykorzystano fragmenty kody
 * napisanego na PW - szczegoly ponizej.
 *
 * Mirek Nazaruk, mirnaz@icm.edu.pl, 1998
 */

#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>

#define TRUE 1
#define FALSE 0

#undef DEBUG

#define UD_8BIT		8
#define UD_7BIT		7

#define  CR             13
#define  CTRLZ          26
#define  ESC 	        27

typedef unsigned char byte;

/* Fragment kodu wziety z sms.cpp z PW */

#define mod8(a) (a & 0x07)

/*
//-----------------------------------------------------------------------//
// SMS.cpp -  plik z definicjami metod klasy SMS.Klasa ta obsluguje      //
//            wymiane krotkich tekstowych komunikatow przy pomocy        //
//            telefonu M1                                                //
//                                                                       //
// UWAGA :    Wlascicielem kodu jest Instytut Informatyki Politechniki   //
//            Warszawskiej.Moze byc wykorzystywany do celow komercyjnych //
//            pod warunkiem,ze naglowek ten nie zostanie usuniety.       //
//                                                                       //
// AUTORZY :  Jaroslaw Grzelak, Rafal Benesz, Andrzej Ciski              //
//-----------------------------------------------------------------------//
*/
/*
//-----------------------------------------------------------------------
// Funkcja dostaje na wejsciu jednobajtowa liczbe zwraca zas jej postac
// szesnastkowa w formacie tekstowym
*/
char *btohex(char *buf,int numb)
{
    unsigned char res,rest;

    res = numb >> 4;
    rest = numb & 0x0F;

    buf[0] = (res > 9) ? res - 10 + 'A' : res + '0';
    buf[1] = (rest > 9) ? rest - 10 + 'A' : rest + '0';
    buf[2] = '\0';
    return buf;
}

/*
//-----------------------------------------------------------------------
// Metoda otrzymuje na wejsciu dwa kolejne bajty z UD (user data), liczbe
// n - mowiaca ktora 'rotacja' zachodzi ( n = 0..7 ) oraz miejsce w ktorym
// zostanie zlozona zakodowana 7b cyfra w tekstowym hex.
*/
void puthexbyte(char *dst,byte first,byte second,byte n)
{
    unsigned int hlp,hlp2;          /* pojemniki na first i second */

    hlp2 = first;
    hlp2 &= 0x007F;                    /* wyzeruj najstarzy bit mlod. 
bajtu */
    hlp = second;
    hlp <<= 7;                      /* 7 - !!!  najstarszy bit niewazny */
    hlp |= hlp2;                    /* sumuj obie liczby */
    hlp >>= n;                      /* i rotuj o n */

    if(hlp & 0x00FF) btohex(dst,(byte) hlp); /* wpisanie tekst. liczby w 
hex. */
}

/*
//-----------------------------------------------------------------------
// Matoda dostaje na wejsciu bufor (src) w ktorym znajduje sie okreslona
// ilosc bajtow zapisanych w tekstowym hex.Nastepnie dane te zakodowuje
// w wyjsciowym buforze (dst) juz w formacie 7b. tekstowego hexa.
// Uwaga : bufor we. zawiera count * 2 znakow.
*/
void setdata(char *dst,char *src,int count)
{
    int odd = count & 0x01;                 /* czy parzysta ilosc danych */
    byte i,j;

    if(count < 1) return;

    if(count == 1)
       btohex(dst,(byte) src[0] & 0x7F);    /* jeden bajt danych*/
    else {
       count--;                             /* optymalizacja */

       for(i = 0, j = 0 ; ; i++, j = j + 2)
          if(i < count) {                    /* przetwarzaj dwojke */
              if(mod8(i) == 7) {
                  puthexbyte(dst + j,src[i + 1],
                            (i + 2 <= count) ? src[i + 2] : 0,0);
                  i++;
              }
              else puthexbyte(dst + j,src[i],src[i + 1],mod8(i));
          }
          else {
                 if(i == count)              /* ostatni nieparzysty czlon 
*/
                     puthexbyte(dst + j,src[i],odd ? 0 : src[i + 
1],mod8(i));

                 break;
          }
    }
}

byte hextob(char first,char second)
{
    byte f,s;

    if(isalpha(first)) f = toupper(first) - 'A' + 10;
    else f = first - '0';

    if(isalpha(second)) s = toupper(second) - 'A' + 10;
    else s = second - '0';

    return (f << 4) + s;
}

/*
//-----------------------------------------------------------------------
// Metoda pobiera z zakodowanego 7b tekstu dwa sasiednie bajty oraz numer
// 'rotacji' poczym zwraca odkodowana pierwotna wartosc bajtu (dane 8b).
*/
byte gethexbyte(byte curr,byte prev,int n)
{
    unsigned int num,hlp;

    hlp = prev;
    num = curr;
    num <<= 8;
    num |= prev;
    num >>= (8 - n);

    return (byte) (num & 0x007F);      /* z wyzerowanym najst. bitem */
}

/*
//-----------------------------------------------------------------------
// Metoda pobiera zakodowane w 7b dane ( tekstowy hex ) z bufora src
// poczym odkodowoje te dane i umieszcza w buforze dst.
*/
void getdata(char *dst,char *src,int count)
{
    byte curr,prev = 0;
    byte i,j;

    count -= count >> 3;               /* 'spakowane znaki' */
    count <<= 1;                       /* dwa razy wiecej znakow niz 
bajtow */

    for(i = 0, j = 0 ; i < count ; i = i + 2, j++) {
        curr = hextob(src[i],src[i + 1]);
        dst[j] = (char) gethexbyte(curr,prev,mod8(j));
        if(mod8(j) == 6) {
            dst[++j] = (char) gethexbyte(0,curr,7);
            curr = 0;
        }

        prev = curr;
    }
}

/* Koniec funkcji z PW */
/* ***** */


/*
  funkcja przedstawiajaca unsigned char (byte) w postaci
  dwoch znakow w hexie, wzorowana na kodzie sms.cpp z pw
*/
char *byte_to_2hex(buf, b, reverse)
char buf[2];
unsigned char b;
int reverse;
{
  unsigned char h1, h2;

  h1 = (b>>4) & 0x0f;
  h2 = b & 0x0f;
  if (reverse) {
    buf[0]= (h2 > 9)? 'A'+(h2-10) : h2+'0';
    buf[1]= (h1 > 9)? 'A'+(h1-10) : h1+'0';
  } else {
    buf[0]= (h1 > 9)? 'A'+(h1-10) : h1+'0';
    buf[1]= (h2 > 9)? 'A'+(h2-10) : h2+'0';
  }
  buf[2]= '\0';
  return(buf);
} /* byte_to_2hex */

/*
 * funkcja koduje numer MS (mobile station) na format BCD
 * (dodaje tez naglowek)
*/
char *encode_da(bcd, da)
char *bcd;
char *da;
{
  char buf[24], *a, t;
  int i, l, in=FALSE;

  if (strchr(da, '+')!=NULL) {
    in=TRUE; /* numer miedzynarodowy */
    a=da+1;  /* pomin plus przed numerem */
  } else a=da;
  strcpy(buf, a);
  l=strlen(a);
  /* uzupelnij F'em jesli liczba cyfr nieparzysta */
  if (l%2) { buf[l]='F'; buf[l+1]='\0'; }
  for (i=0; i<strlen(buf); i=i+2) {
    t=buf[i];
    buf[i]=buf[i+1];
    buf[i+1]=t;
  }
  bcd[0]='\0';
  byte_to_2hex(bcd, (unsigned char)l, FALSE);
  if (in) strcat(bcd, "91"); else strcat(bcd, "81");
  strcat(bcd, buf);
#ifdef DEBUG
  printf("encode_da: %s(l=%d) -> %s\n", da, l, bcd);
#endif
  return(bcd);
} /* encode_da */

/*
 * funkcja koduje 8bitowo string msg
*/
char *encode_ud8(ud, msg)
char *ud;
char *msg;
{
  int i;

#ifdef DEBUG
  printf("encode_ud8: %s\n", msg);
#endif
  for (i=0; i<strlen(msg); i++)
    byte_to_2hex(ud+2*i, (unsigned char)msg[i], FALSE);

#ifdef DEBUG
  printf("encode_ud8: %s -> %s\n", msg, ud);
#endif
  return(ud);
} /* encode_ud8 */

/*
 * encodes short message and returns coresponding pdu
*/
char *encode_sms(pdu, da, msg, enc)
char *pdu;
char *da;
char *msg;
int enc;
{
  char buf[24];

#ifdef DEBUG
  printf("encode_sms: %s -> %s\n", msg, da);
#endif

  pdu[0]='\0';
  /* pdu type=message originated, vp in integer format */
  strcat(pdu, "11");
  /* mr =message reference = 0 */
  strcat(pdu, "00");
  /* da=recipient number */
  strcat(pdu, encode_da(buf, da) );
  /* pid =protocol identifier, 00h=sms */
  strcat(pdu, "00");
  /* dcs= coding scheme, f6h=UD 8bit coding, 00h = 7bit */
  if (enc==UD_8BIT) strcat(pdu, "F6");
  else strcat(pdu, "00");

  /* vp=validity period=(vp+1)*5 minuts */
  byte_to_2hex(pdu+strlen(pdu), (unsigned char)5, FALSE);

  /* udl=ud length */
  byte_to_2hex(pdu+strlen(pdu), (unsigned char)strlen(msg), FALSE);

  if (enc==UD_8BIT) {
    /* ud - in 8bit encoding, sizeof(msg)<=140 */
    encode_ud8(pdu+strlen(pdu), msg);
  } else {
    setdata(pdu+strlen(pdu), msg, strlen(msg));
  }
#ifdef DEBUG
  printf("encode_sms: %s -> %s ===> %s\n", msg, da, pdu);
#endif
  return(pdu);
} /* encode_sms */


void main(argc, argv)
int argc;
char *argv[];
{
  char pdu[512];
  int enc;

  if (argc < 3) {
    printf("Usage: %s telno message [7|8]\n", argv[0]);
    exit(1);
  } else {
    enc=UD_8BIT;
    if (argc==4)
      if (argv[3][0]=='7') enc=UD_7BIT;
    encode_sms(pdu, argv[1], argv[2], enc);
    printf("%s\n", pdu);
  }
  exit(0);
} /* main */


