Found in "gnokii-working" directory, some November-patches version
[gnokii.git] / common / gsm-sms.c
index a06c3c5..b28454c 100644 (file)
 
   Library for parsing and creating Short Messages (SMS).
 
+  $Log$
+  Revision 1.1.1.8  2002/04/03 00:08:04  short
+  Found in "gnokii-working" directory, some November-patches version
+
+  Revision 1.1  2001/11/08 16:23:21  pkot
+  New version of libsms. Not functional yet, but it reasonably stable API.
+
+  Revision 1.1  2001/07/09 23:06:26  pkot
+  Moved sms.* files from my hard disk to CVS
+
 */
 
 #include <stdlib.h>
-#include <string.h>
 
 #include "gsm-common.h"
 #include "gsm-encoding.h"
-#include "gsm-bitmaps.h"
-
-SMSMessage_PhoneLayout layout;
-static SMSMessage_Layout llayout;
 
 struct udh_data {
        unsigned int length;
        char *header;
 };
 
+/* Number of header specific octets in SMS header (before data) */
+static unsigned short DataOffset[] = {
+       4, /* SMS Deliver */
+       3, /* SMS Deliver Report */
+       5, /* SMS Submit */
+       3, /* SMS Submit Report */
+       3, /* SMS Command */
+       3  /* SMS Status Report */
+};
+
 /* User data headers */
 static struct udh_data headers[] = {
        { 0x00, "" },
-       { 0x05, "\x00\x03\x01\x00\x00" },     /* Concatenated messages */
+       { 0x05, "\x00\x03\x01\x00\x00" }, /* Concatenated messages */
        { 0x06, "\x05\x04\x15\x82\x00\x00" }, /* Operator logos */
-       { 0x06, "\x05\x04\x15\x83\x00\x00" }, /* Caller logos */
+       { 0x06, "\x05\x04\x15\x82\x00\x00" }, /* Caller logos */
        { 0x06, "\x05\x04\x15\x81\x00\x00" }, /* Ringtones */
-       { 0x04, "\x03\x01\x00\x00" },         /* Voice Messages */
-       { 0x04, "\x03\x01\x01\x00" },         /* Fax Messages */
-       { 0x04, "\x03\x01\x02\x00" },         /* Email Messages */
-       { 0x06, "\x05\x04\x23\xf4\x00\x00" }, /* Business Card */
+       { 0x04, "\x03\x01\x00\x00" }, /* Voice Messages */
+       { 0x04, "\x03\x01\x01\x00" }, /* Fax Messages */
+       { 0x04, "\x03\x01\x02\x00" }, /* Email Messages */
        { 0x00, "" }
 };
 
@@ -48,112 +62,101 @@ static struct udh_data headers[] = {
  *** Util functions
  ***/
 
-/* This function implements packing of numbers (SMS Center number and
-   destination number) for SMS sending function. */
-static int SemiOctetPack(char *Number, unsigned char *Output, SMS_NumberType type)
+static char *GetBCDNumber(u8 *Number)
 {
-       unsigned char *IN = Number;  /* Pointer to the input number */
-       unsigned char *OUT = Output; /* Pointer to the output */
-       int count = 0; /* This variable is used to notify us about count of already
-                         packed numbers. */
-
-       /* The first byte in the Semi-octet representation of the address field is
-          the Type-of-Address. This field is described in the official GSM
-          specification 03.40 version 6.1.0, section 9.1.2.5, page 33. We support
-          only international and unknown number. */
-
-       *OUT++ = type;
-       if (type == SMS_International) IN++; /* Skip '+' */
-       if ((type == SMS_Unknown) && (*IN == '+')) IN++; /* Optional '+' in Unknown number type */
-
-       /* The next field is the number. It is in semi-octet representation - see
-          GSM scpecification 03.40 version 6.1.0, section 9.1.2.3, page 31. */
-       while (*IN) {
-               if (count & 0x01) {
-                       *OUT = *OUT | ((*IN - '0') << 4);
-                       OUT++;
-               }
-               else
-                       *OUT = *IN - '0';
-               count++; IN++;
-       }
+        static char Buffer[20] = "";
 
-       /* We should also fill in the most significant bits of the last byte with
-          0x0f (1111 binary) if the number is represented with odd number of
-          digits. */
-       if (count & 0x01) {
-               *OUT = *OUT | 0xf0;
-               OUT++;
-       }
-
-       return (2 * (OUT - Output - 1) - (count % 2));
-}
+       /* This is the length of BCD coded number */
+        int length=Number[0];
+        int count;
+        int Digit;
 
-char *GetBCDNumber(u8 *Number)
-{
-       static char Buffer[20] = "";
-       int length = Number[0]; /* This is the length of BCD coded number */
-       int count, Digit;
+        switch (Number[1]) {
 
-       memset(Buffer, 0, 20);
-       switch (Number[1]) {
-       case SMS_Alphanumeric:
+       case 0xd0:
                Unpack7BitCharacters(0, length, length, Number+2, Buffer);
                Buffer[length] = 0;
                break;
-       case SMS_International:
-               sprintf(Buffer, "+");
-       case SMS_Unknown:
-       case SMS_National:
-       case SMS_Network:
-       case SMS_Subscriber:
-       case SMS_Abbreviated:
        default:
+               if (Number[1] == SMS_International)
+                       sprintf(Buffer, "+");
+               else
+                       Buffer[0] = '\0';
                for (count = 0; count < length - 1; count++) {
                        Digit = Number[count+2] & 0x0f;
                        if (Digit < 10) sprintf(Buffer, "%s%d", Buffer, Digit);
                        Digit = Number[count+2] >> 4;
                        if (Digit < 10) sprintf(Buffer, "%s%d", Buffer, Digit);
                }
-               break;
+                break;
+        }
+        return Buffer;
+}
+
+#if 0
+char *GetBCDNumber(u8 *Number, int maxdigits, int maxbytes) 
+{
+       static char Buffer[22] = "";
+       int length = Number[0]; /* This is the length of BCD coded number */
+       int bytes = 0, digits = 0;
+       int Digit = 0;
+       
+       dprintf("%i\n", length);
+       
+       if (Number[1] == 0x91) {
+               sprintf(Buffer, "+");
+       } else {
+               Buffer[0] = '\0';
        }
+       
+       while ((Digit < 10) && (bytes < length) && (digits < maxdigits)) {
+               Digit = Number[bytes + 2] & 0x0f;
+               if (Digit < 10) {
+                       sprintf(Buffer, "%s%d", Buffer, Digit);
+                       digits++;
+                       Digit = Number[bytes + 2] >> 4;
+                       if (Digit < 10) {
+                               sprintf(Buffer, "%s%d", Buffer, Digit);
+                               digits++;
+                       }
+               }
+               bytes++;
+       } 
+       
        return Buffer;
 }
+#endif
 
 static char *PrintDateTime(u8 *Number) 
 {
-       static char Buffer[23] = "";
+        static char Buffer[23] = "";
 
        memset(Buffer, 0, 23);
-       if (Number[0] < 70) sprintf(Buffer, "20");
-       else sprintf(Buffer, "19");
-       sprintf(Buffer, "%s%d%d-", Buffer, Number[0] & 0x0f, Number[0] >> 4);
-       sprintf(Buffer, "%s%d%d-", Buffer, Number[1] & 0x0f, Number[1] >> 4);
-       sprintf(Buffer, "%s%d%d ", Buffer, Number[2] & 0x0f, Number[2] >> 4);
-       sprintf(Buffer, "%s%d%d:", Buffer, Number[3] & 0x0f, Number[3] >> 4);
-       sprintf(Buffer, "%s%d%d:", Buffer, Number[4] & 0x0f, Number[4] >> 4);
-       sprintf(Buffer, "%s%d%d",  Buffer, Number[5] & 0x0f, Number[5] >> 4);
+        sprintf(Buffer, "%d%d-", Number[0] & 0x0f, Number[0] >> 4);
+        sprintf(Buffer, "%s%d%d-", Buffer, Number[1] & 0x0f, Number[1] >> 4);
+        sprintf(Buffer, "%s%d%d ", Buffer, Number[2] & 0x0f, Number[2] >> 4);
+        sprintf(Buffer, "%s%d%d:", Buffer, Number[3] & 0x0f, Number[3] >> 4);
+        sprintf(Buffer, "%s%d%d:", Buffer, Number[4] & 0x0f, Number[4] >> 4);
+        sprintf(Buffer, "%s%d%d",  Buffer, Number[5] & 0x0f, Number[5] >> 4);
        if (Number[6] & 0x08) 
                sprintf(Buffer, "%s-", Buffer);
        else
                sprintf(Buffer, "%s+", Buffer);
        sprintf(Buffer, "%s%02d00", Buffer, (10 * (Number[6] & 0x07) + (Number[6] >> 4)) / 4);
 
-       return Buffer;
+        return Buffer;
 }
 
-SMS_DateTime *UnpackDateTime(u8 *Number, SMS_DateTime *dt)
+static SMS_DateTime *UnpackDateTime(u8 *Number, SMS_DateTime *dt)
 {
-       dt->Year     =  10 * (Number[0] & 0x0f) + (Number[0] >> 4);
-       if (dt->Year < 70) dt->Year += 2000;
-       else dt->Year += 1900;
-       dt->Month    =  10 * (Number[1] & 0x0f) + (Number[1] >> 4);
-       dt->Day      =  10 * (Number[2] & 0x0f) + (Number[2] >> 4);
-       dt->Hour     =  10 * (Number[3] & 0x0f) + (Number[3] >> 4);
-       dt->Minute   =  10 * (Number[4] & 0x0f) + (Number[4] >> 4);
-       dt->Second   =  10 * (Number[5] & 0x0f) + (Number[5] >> 4);
-       dt->Timezone = (10 * (Number[6] & 0x07) + (Number[6] >> 4)) / 4;
-       if (Number[6] & 0x08) dt->Timezone = -dt->Timezone;
+        dt->Year     =  10 * (Number[0] & 0x0f) + (Number[0] >> 4);
+        dt->Month    =  10 * (Number[1] & 0x0f) + (Number[1] >> 4);
+        dt->Day      =  10 * (Number[2] & 0x0f) + (Number[2] >> 4);
+        dt->Hour     =  10 * (Number[3] & 0x0f) + (Number[3] >> 4);
+        dt->Minute   =  10 * (Number[4] & 0x0f) + (Number[4] >> 4);
+        dt->Second   =  10 * (Number[5] & 0x0f) + (Number[5] >> 4);
+        dt->Timezone = (10 * (Number[6] & 0x07) + (Number[6] >> 4)) / 4;
+        if (Number[6] & 0x08) dt->Timezone = -dt->Timezone;
 
        return dt;
 }
@@ -162,60 +165,6 @@ SMS_DateTime *UnpackDateTime(u8 *Number, SMS_DateTime *dt)
  *** ENCODING SMS
  ***/
 
-static GSM_Error EncodeData(GSM_SMSMessage *SMS, char *dcs, char *message)
-{
-       SMS_AlphabetType al;
-       unsigned short length = strlen(SMS->MessageText);
-
-       switch (SMS->DCS.Type) {
-       case SMS_GeneralDataCoding:
-               switch (SMS->DCS.u.General.Class) {
-               case 1: dcs[0] |= 0xf0; break;
-               case 2: dcs[0] |= 0xf1; break;
-               case 3: dcs[0] |= 0xf2; break;
-               case 4: dcs[0] |= 0xf3; break;
-               default: break;
-               }
-               if (SMS->DCS.u.General.Compressed) {
-                       /* Compression not supported yet */
-                       /* dcs[0] |= 0x20; */
-               }
-               al = SMS->DCS.u.General.Alphabet;
-               break;
-       case SMS_MessageWaiting:
-               al = SMS->DCS.u.MessageWaiting.Alphabet;
-               if (SMS->DCS.u.MessageWaiting.Discard) dcs[0] |= 0xc0;
-               else if (SMS->DCS.u.MessageWaiting.Alphabet == SMS_UCS2) dcs[0] |= 0xe0;
-               else dcs[0] |= 0xd0;
-
-               if (SMS->DCS.u.MessageWaiting.Active) dcs[0] |= 0x08;
-               dcs[0] |= (SMS->DCS.u.MessageWaiting.Type & 0x03);
-
-               break;
-       default:
-               return GE_SMSWRONGFORMAT;
-       }
-       switch (al) {
-       case SMS_DefaultAlphabet:
-               Pack7BitCharacters((7 - (SMS->UDH_Length % 7)) % 7, SMS->MessageText, message);
-               SMS->Length = 8 * SMS->UDH_Length + (7 - (SMS->UDH_Length % 7)) % 7 + length;
-               break;
-       case SMS_8bit:
-               dcs[0] |= 0xf4;
-               memcpy(message, SMS->MessageText + 1, SMS->MessageText[0]);
-               SMS->Length = SMS->UDH_Length + SMS->MessageText[0];
-               break;
-       case SMS_UCS2:
-               dcs[0] |= 0x08;
-               EncodeUnicode(message, SMS->MessageText, length);
-               SMS->Length = length;
-               break;
-       default:
-               return GE_SMSWRONGFORMAT;
-       }
-       return GE_NONE;
-}
-
 /* This function encodes the UserDataHeader as described in:
    - GSM 03.40 version 6.1.0 Release 1997, section 9.2.3.24
    - Smart Messaging Specification, Revision 1.0.0, September 15, 1997
@@ -241,7 +190,7 @@ static GSM_Error EncodeUDH(SMS_UDHInfo UDHi, char *UDH)
                memcpy(UDH+pos+1, headers[UDHi.Type].header, headers[UDHi.Type].length);
                break;
        default:
-               dprintf("Not supported User Data Header type\n");
+               fprintf(stderr, _("Not supported User Data Header type\n"));
                break;
        }
        return GE_NONE;
@@ -250,34 +199,28 @@ static GSM_Error EncodeUDH(SMS_UDHInfo UDHi, char *UDH)
 static GSM_Error EncodeSMSSubmitHeader(GSM_SMSMessage *SMS, char *frame)
 {
        GSM_Error error = GE_NONE;
+       int i;
 
-       /* Standard Header: */
-       memcpy(frame + llayout.UserDataHeader, "\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa9\x00\x00\x00\x00\x00\x00", 24);
+       /* SMS Center */
 
        /* Reply Path */
-       if (llayout.ReplyViaSameSMSC > -1) {
-               if (SMS->ReplyViaSameSMSC) frame[llayout.ReplyViaSameSMSC] |= 0x80;
-       }
+       if (SMS->ReplyViaSameSMSC) frame[13] |= 0x80;
 
-       /* User Data Header Indicator */
-       if (llayout.UserDataHeader > -1) {
-               if (SMS->UDH_No) frame[llayout.UserDataHeader] |= 0x40;
+       /* User Data Header */
+       for (i = 0; SMS->UDH[i].Type != SMS_NoUDH; i++) {
+               frame[13] |= 0x40;
+               error = EncodeUDH(SMS->UDH[i], frame);
+               if (error != GE_NONE) return error;
        }
 
        /* Status (Delivery) Report Request */
-       if (llayout.Report > -1) {
-               if (SMS->Report) frame[llayout.Report] |= 0x20;
-       }
+       if (SMS->Report) frame[13] |= 0x20;
 
        /* Validity Period Format: mask - 0x00, 0x10, 0x08, 0x18 */
-       if (llayout.Validity > -1) {
-               frame[llayout.Validity] |= ((SMS->Validity.VPF & 0x03) << 3);
-       }
+       frame[13] |= ((SMS->Validity.VPF & 0x03) << 3);
 
        /* Reject Duplicates */
-       if (llayout.RejectDuplicates > -1) {
-               if (SMS->RejectDuplicates) frame[llayout.RejectDuplicates] |= 0x04;
-       }
+       if (SMS->RejectDuplicates) frame[13] |= 0x04;
 
        /* Message Type is already set */
 
@@ -287,35 +230,31 @@ static GSM_Error EncodeSMSSubmitHeader(GSM_SMSMessage *SMS, char *frame)
        /* Protocol Identifier */
        /* FIXME: allow to change this in better way.
           currently only 0x5f == `Return Call Message' is used */
-       if (llayout.PID > -1) {
-               if (SMS->PID) frame[llayout.PID] = SMS->PID;
-       }
+       frame[16] = SMS->PID;
 
        /* Data Coding Scheme */
-       if (llayout.DataCodingScheme > -1) {
-               switch (SMS->DCS.Type) {
-               case SMS_GeneralDataCoding:
-                       if (SMS->DCS.u.General.Compressed) frame[llayout.DataCodingScheme] |= 0x20;
-                       if (SMS->DCS.u.General.Class) frame[llayout.DataCodingScheme] |= (0x10 | (SMS->DCS.u.General.Class - 1));
-                       frame[llayout.DataCodingScheme] |= ((SMS->DCS.u.General.Alphabet & 0x03) << 2);
-                       break;
-               case SMS_MessageWaiting:
-                       if (SMS->DCS.u.MessageWaiting.Discard) frame[llayout.DataCodingScheme] |= 0xc0;
-                       else if (SMS->DCS.u.MessageWaiting.Alphabet == SMS_UCS2) frame[llayout.DataCodingScheme] |= 0xe0;
-                       else frame[llayout.DataCodingScheme] |= 0xd0;
-                       if (SMS->DCS.u.MessageWaiting.Active) frame[llayout.DataCodingScheme] |= 0x80;
-                       frame[llayout.DataCodingScheme] |= (SMS->DCS.u.MessageWaiting.Type & 0x03);
-                       break;
-               default:
-                       dprintf("Wrong Data Coding Scheme (DCS) format\n");
-                       return GE_SMSWRONGFORMAT;
-               }
+       switch (SMS->DCS.Type) {
+       case SMS_GeneralDataCoding:
+               if (SMS->DCS.u.General.Compressed) frame[17] |= 0x20;
+               if (SMS->DCS.u.General.Class) frame[17] |= (0x10 | (SMS->DCS.u.General.Class - 1));
+               frame[17] |= ((SMS->DCS.u.General.Alphabet & 0x03) << 2);
+               break;
+       case SMS_MessageWaiting:
+               if (SMS->DCS.u.MessageWaiting.Discard) frame[17] |= 0xc0;
+               else if (SMS->DCS.u.MessageWaiting.Alphabet == SMS_UCS2) frame[17] |= 0xe0;
+               else frame[17] |= 0xd0;
+               if (SMS->DCS.u.MessageWaiting.Active) frame[17] |= 0x80;
+               frame[17] |= (SMS->DCS.u.MessageWaiting.Type & 0x03);
+               break;
+       default:
+               fprintf(stderr, _("Wrong Data Coding Scheme (DCS) format\n"));
+               return GE_SMSWRONGFORMAT;
        }
 
+       /* User Data Length */
+       /* Will be filled later. */
+
        /* Destination Address */
-       if (llayout.RemoteNumber > -1) {
-               frame[llayout.RemoteNumber] = SemiOctetPack(SMS->RemoteNumber.number, frame + llayout.RemoteNumber + 1, SMS->RemoteNumber.type);
-       }
 
        /* Validity Period */
        switch (SMS->Validity.VPF) {
@@ -329,7 +268,7 @@ static GSM_Error EncodeSMSSubmitHeader(GSM_SMSMessage *SMS, char *frame)
                break;
        }
 
-       return error;
+       return GE_NONE;
 }
 
 static GSM_Error EncodeSMSDeliverHeader()
@@ -342,11 +281,12 @@ static GSM_Error EncodeSMSHeader(GSM_SMSMessage *SMS, char *frame)
    (for sending or saving in Outbox) message */
 {
        /* Set SMS type */
+       frame[12] |= (SMS->Type >> 1);
        switch (SMS->Type) {
        case SMS_Submit: /* we send SMS or save it in Outbox */
                return EncodeSMSSubmitHeader(SMS, frame);
        case SMS_Deliver: /* we save SMS in Inbox */
-               return EncodeSMSDeliverHeader(SMS, frame);
+               return EncodeSMSSubmitHeader(SMS, frame);
        default: /* we don't create other formats of SMS */
                return GE_SMSWRONGFORMAT;
        }
@@ -355,53 +295,47 @@ static GSM_Error EncodeSMSHeader(GSM_SMSMessage *SMS, char *frame)
 /* This function encodes SMS as described in:
    - GSM 03.40 version 6.1.0 Release 1997, section 9
 */
-int EncodePDUSMS(GSM_SMSMessage *SMS, char *message)
+GSM_Error EncodePDUSMS(GSM_SMSMessage *SMS, char *frame)
 {
        GSM_Error error = GE_NONE;
        int i;
 
-       switch (SMS->Type) {
-       case SMS_Submit:
-               llayout = layout.Submit;
-               dprintf("Sending SMS to %s via message center %s\n", SMS->RemoteNumber.number, SMS->MessageCenter.Number);
-               break;
-       case SMS_Deliver:
-               llayout = layout.Deliver;
-               dprintf("Saving SMS to Inbox\n");
-               break;
-       case SMS_Picture:
-               llayout = layout.Picture;
-               dprintf("Sending Picture Message\n");
-               break;
-       case SMS_Delivery_Report:
-       default:
-               dprintf("Not supported message type: %d\n", SMS->Type);
-               return GE_NOTSUPPORTED;
-       }
+       /* Short Message Data info element id */
+
+       /* Length of Short Message Data */
+
+       /* Short Message Reference value */
+       if (SMS->Number) frame[3] = SMS->Number;
+
+       /* Short Message status */
+       if (SMS->Status) frame[1] = SMS->Status;
+
+       /* Message Type */
 
        /* SMSC number */
-       if (llayout.MessageCenter > -1) {
-               dprintf("%d %s\n", SMS->MessageCenter.Type, SMS->MessageCenter.Number);
-               message[llayout.MessageCenter] = SemiOctetPack(SMS->MessageCenter.Number, message + llayout.MessageCenter + 1, SMS->MessageCenter.Type);
-               if (message[llayout.MessageCenter] % 2) message[llayout.MessageCenter]++;
-               message[llayout.MessageCenter] = message[llayout.MessageCenter] / 2 + 1;
+       if (SMS->MessageCenter.Number) {
+//             error = GSM->GetSMSCenter(&SMS->MessageCenter);
+               
+               if (error != GE_NONE)
+                       return error;
+               strcpy(SMS->MessageCenter.Number, "0");
        }
+       dprintf("Sending SMS to %s via message center %s\n", SMS->Sender, SMS->MessageCenter.Number);
 
-       /* Common Header */
-       error = EncodeSMSHeader(SMS, message);
-       if (error != GE_NONE) return error;
+       /* Header coding */
+//     EncodeUDH(SMS, frame);
+//     if (error != GE_NONE) return error;
 
        /* User Data Header - if present */
-//     for (i = 0; i < SMS->UDH_No; i++) {
-//             error = EncodeUDH(SMS->UDH[i], message + 24);
-//             if (error != GE_NONE) return error;
-//     }
-       SMS->UDH_Length = 0;
+       for (i = 0; SMS->UDH[i].Type != SMS_NoUDH; i++) {
+               error = EncodeUDH(SMS->UDH[i], frame);
+               if (error != GE_NONE) return error;
+       }
 
        /* User Data */
-       EncodeData(SMS, message + llayout.DataCodingScheme, message + llayout.UserData + SMS->UDH_Length);
-       message[llayout.Length] = SMS->Length;
-       return SMS->Length + llayout.UserData - 1;
+       //      EncodeData(&(SMS->MessageText), &(SMS->DCS), frame);
+
+       return error;
 }
 
 /* This function does simple SMS encoding - no PDU coding */
@@ -414,152 +348,148 @@ GSM_Error EncodeTextSMS()
  *** DECODING SMS
  ***/
 
-static GSM_Error SMSStatus(unsigned char status, GSM_SMSMessage *SMS)
+static GSM_Error SMSStatus(unsigned char status, GSM_SMSMessage *sms)
 {
        if (status < 0x03) {
-               strcpy(SMS->MessageText, _("Delivered"));
+               strcpy(sms->MessageText, _("Delivered"));
                switch (status) {
                case 0x00:
-                       dprintf("SM received by the SME");
+                       dprintf(_("SM received by the SME"));
                        break;
                case 0x01:
-                       dprintf("SM forwarded by the SC to the SME but the SC is unable to confirm delivery");
+                       dprintf(_("SM forwarded by the SC to the SME but the SC is unable to confirm delivery"));
                        break;
                case 0x02:
-                       dprintf("SM replaced by the SC");
+                       dprintf(_("SM replaced by the SC"));
                        break;
                }
-               SMS->Length = strlen(_("Delivered"));
+               sms->Length = 10;
        } else if (status & 0x40) {
 
-               strcpy(SMS->MessageText, _("Failed"));
+               strcpy(sms->MessageText, _("Failed"));
 
                /* more detailed reason only for debug */
 
                if (status & 0x20) {
-                       dprintf("Temporary error, SC is not making any more transfer attempts\n");
+                       dprintf(_("Temporary error, SC is not making any more transfer attempts\n"));
 
                        switch (status) {
                        case 0x60:
-                               dprintf("Congestion");
+                               dprintf(_("Congestion"));
                                break;
                        case 0x61:
-                               dprintf("SME busy");
+                               dprintf(_("SME busy"));
                                break;
                        case 0x62:
-                               dprintf("No response from SME");
+                               dprintf(_("No response from SME"));
                                break;
                        case 0x63:
-                               dprintf("Service rejected");
+                               dprintf(_("Service rejected"));
                                break;
                        case 0x64:
-                               dprintf("Quality of service not aviable");
+                               dprintf(_("Quality of service not aviable"));
                                break;
                        case 0x65:
-                               dprintf("Error in SME");
+                               dprintf(_("Error in SME"));
                                break;
                        default:
-                               dprintf("Reserved/Specific to SC: %x", status);
+                               dprintf(_("Reserved/Specific to SC: %x"), status);
                                break;
                        }
                } else {
-                       dprintf("Permanent error, SC is not making any more transfer attempts\n");
+                       dprintf(_("Permanent error, SC is not making any more transfer attempts\n"));
                        switch (status) {
                        case 0x40:
-                               dprintf("Remote procedure error");
+                               dprintf(_("Remote procedure error"));
                                break;
                        case 0x41:
-                               dprintf("Incompatibile destination");
+                               dprintf(_("Incompatibile destination"));
                                break;
                        case 0x42:
-                               dprintf("Connection rejected by SME");
+                               dprintf(_("Connection rejected by SME"));
                                break;
                        case 0x43:
-                               dprintf("Not obtainable");
+                               dprintf(_("Not obtainable"));
                                break;
                        case 0x44:
-                               dprintf("Quality of service not aviable");
+                               dprintf(_("Quality of service not aviable"));
                                break;
                        case 0x45:
-                               dprintf("No internetworking available");
+                               dprintf(_("No internetworking available"));
                                break;
                        case 0x46:
-                               dprintf("SM Validity Period Expired");
+                               dprintf(_("SM Validity Period Expired"));
                                break;
                        case 0x47:
-                               dprintf("SM deleted by originating SME");
+                               dprintf(_("SM deleted by originating SME"));
                                break;
                        case 0x48:
-                               dprintf("SM Deleted by SC Administration");
+                               dprintf(_("SM Deleted by SC Administration"));
                                break;
                        case 0x49:
-                               dprintf("SM does not exist");
+                               dprintf(_("SM does not exist"));
                                break;
                        default:
-                               dprintf("Reserved/Specific to SC: %x", status);
+                               dprintf(_("Reserved/Specific to SC: %x"), status);
                                break;
                        }
                }
-               SMS->Length = strlen(_("Failed"));
+               sms->Length = 6;
        } else if (status & 0x20) {
-               strcpy(SMS->MessageText, _("Pending"));
+               strcpy(sms->MessageText, _("Pending"));
 
                /* more detailed reason only for debug */
-               dprintf("Temporary error, SC still trying to transfer SM\n");
+               dprintf(_("Temporary error, SC still trying to transfer SM\n"));
                switch (status) {
                case 0x20:
-                       dprintf("Congestion");
+                       dprintf(_("Congestion"));
                        break;
                case 0x21:
-                       dprintf("SME busy");
+                       dprintf(_("SME busy"));
                        break;
                case 0x22:
-                       dprintf("No response from SME");
+                       dprintf(_("No response from SME"));
                        break;
                case 0x23:
-                       dprintf("Service rejected");
+                       dprintf(_("Service rejected"));
                        break;
                case 0x24:
-                       dprintf("Quality of service not aviable");
+                       dprintf(_("Quality of service not aviable"));
                        break;
                case 0x25:
-                       dprintf("Error in SME");
+                       dprintf(_("Error in SME"));
                        break;
                default:
-                       dprintf("Reserved/Specific to SC: %x", status);
+                       dprintf(_("Reserved/Specific to SC: %x"), status);
                        break;
                }
-               SMS->Length = strlen(_("Pending"));
+               sms->Length = 7;
        } else {
-               strcpy(SMS->MessageText, _("Unknown"));
+               strcpy(sms->MessageText, _("Unknown"));
 
                /* more detailed reason only for debug */
-               dprintf("Reserved/Specific to SC: %x", status);
-               SMS->Length = strlen(_("Unknown"));
+               dprintf(_("Reserved/Specific to SC: %x"), status);
+               sms->Length = 8;
        }
-       dprintf("\n");
        return GE_NONE;
 }
 
-static GSM_Error DecodeData(char *message, char *output, int length, int size, int udhlen, SMS_DataCodingScheme dcs)
+static GSM_Error DecodeData(char *message, char *output, int length, SMS_DataCodingScheme dcs, int udhlen, int size)
 {
        /* Unicode */
        if ((dcs.Type & 0x08) == 0x08) {
-               dprintf("Unicode message\n");
                length = (length - udhlen)/2;
                DecodeUnicode(output, message, length);
+       /* 8bit SMS */
        } else {
-               /* 8bit SMS */
                if ((dcs.Type & 0xf4) == 0xf4) {
-                       dprintf("8bit message\n");
                        memcpy(output, message, length);
-               /* 7bit SMS */
+                       /* 7bit SMS */
                } else {
-                       dprintf("Default Alphabet\n");
-                       length = length - (udhlen * 8 + ((7-(udhlen%7))%7)) / 7;
+                       length = length - (udhlen * 8 + ((7-udhlen)%7)) / 7;
                        Unpack7BitCharacters((7-udhlen)%7, size, length, message, output);
-                       DecodeAscii(output, output, length);
                }
+               DecodeAscii(output, output, length);
        }
        dprintf("%s\n", output);
        return GE_NONE;
@@ -569,167 +499,144 @@ static GSM_Error DecodeData(char *message, char *output, int length, int size, i
    - GSM 03.40 version 6.1.0 Release 1997, section 9.2.3.24
    - Smart Messaging Specification, Revision 1.0.0, September 15, 1997
 */
-static GSM_Error DecodeUDH(char *message, GSM_SMSMessage *SMS)
+static GSM_Error DecodeUDH(char *SMSMessage, SMS_UDHInfo **UDHi, GSM_SMSMessage *sms)
 {
        unsigned char length, pos, nr;
 
-       SMS->UDH_Length = length = message[0] + 1;
+       length = SMSMessage[0];
        pos = 1;
        nr = 0;
-       while (length > 1) {
+       while (length > 0) {
                unsigned char udh_length;
 
-               udh_length = message[pos+1];
-               switch (message[pos]) {
+               udh_length = SMSMessage[pos+1];
+               switch (SMSMessage[pos]) {
                case 0x00: // Concatenated short messages
-                       dprintf("Concatenated messages\n");
-                       SMS->UDH[nr].Type = SMS_ConcatenatedMessages;
-                       SMS->UDH[nr].u.ConcatenatedShortMessage.ReferenceNumber = message[pos + 2];
-                       SMS->UDH[nr].u.ConcatenatedShortMessage.MaximumNumber   = message[pos + 3];
-                       SMS->UDH[nr].u.ConcatenatedShortMessage.CurrentNumber   = message[pos + 4];
+                       dprintf("Concat UDH length: %d\n", udh_length);
+                       UDHi[nr]->Type = SMS_ConcatenatedMessages;
+                       UDHi[nr]->u.ConcatenatedShortMessage.ReferenceNumber = SMSMessage[pos + 3];
+                       UDHi[nr]->u.ConcatenatedShortMessage.MaximumNumber   = SMSMessage[pos + 4];
+                       UDHi[nr]->u.ConcatenatedShortMessage.CurrentNumber   = SMSMessage[pos + 5];
                        break;
                case 0x01: // Special SMS Message Indication
-                       switch (message[pos + 2] & 0x03) {
+                       switch (SMSMessage[pos + 3] & 0x03) {
                        case 0x00:
-                               dprintf("Voice Message\n");
-                               SMS->UDH[nr].Type = SMS_VoiceMessage;
+                               UDHi[nr]->Type = SMS_VoiceMessage;
                                break;
                        case 0x01:
-                               dprintf("Fax Message\n");
-                               SMS->UDH[nr].Type = SMS_FaxMessage;
+                               UDHi[nr]->Type = SMS_FaxMessage;
                                break;
                        case 0x02:
-                               dprintf("Email Message\n");
-                               SMS->UDH[nr].Type = SMS_EmailMessage;
+                               UDHi[nr]->Type = SMS_EmailMessage;
                                break;
                        default:
-                               dprintf("Unknown\n");
-                               SMS->UDH[nr].Type = SMS_UnknownUDH;
+                               UDHi[nr]->Type = SMS_UnknownUDH;
                                break;
                        }
-                       SMS->UDH[nr].u.SpecialSMSMessageIndication.Store = (message[pos + 2] & 0x80) >> 7;
-                       SMS->UDH[nr].u.SpecialSMSMessageIndication.MessageCount = message[pos + 3];
+                       UDHi[nr]->u.SpecialSMSMessageIndication.Store = (SMSMessage[pos + 3] & 0x80) >> 7;
+                       UDHi[nr]->u.SpecialSMSMessageIndication.MessageCount = SMSMessage[pos + 4];
                        break;
                case 0x04: // Application port addression scheme, 8 bit address
                        break;
                case 0x05: // Application port addression scheme, 16 bit address
-                       switch (((0x00ff & message[pos + 2]) << 8) | (0x00ff & message[pos + 3])) {
-                       case 0x1581:
-                               dprintf("Ringtone\n");
-                               SMS->UDH[nr].Type = SMS_Ringtone;
-                               break;
-                       case 0x1582:
-                               dprintf("Operator Logo\n");
-                               SMS->UDH[nr].Type = SMS_OpLogo;
-                               break;
-                       case 0x1583:
-                               dprintf("Caller Icon\n");
-                               SMS->UDH[nr].Type = SMS_CallerIDLogo;
-                               break;
-                       case 0x23f4:
-                               dprintf("Business Card\n");
-                               SMS->UDH[nr].Type = SMS_BusinessCard;
-                               break;
-                       default:
-                               dprintf("Unknown\n");
-                               SMS->UDH[nr].Type = SMS_UnknownUDH;
-                               break;
-                       }
                        break;
                case 0x06: // SMSC Control Parameters
                        break;
                case 0x07: // UDH Source Indicator
                        break;
                default:
-                       dprintf("Not supported UDH\n");
                        break;
                }
                length -= (udh_length + 2);
                pos += (udh_length + 2);
                nr++;
        }
-       SMS->UDH_No = nr;
+       sms->UDH_No = nr;
+
+       return GE_NONE;
+}
 
+static GSM_Error DecodeSMSSubmit()
+{
        return GE_NONE;
 }
 
-static GSM_Error DecodeSMSHeader(unsigned char *message, GSM_SMSMessage *SMS)
+static GSM_Error DecodeSMSDeliver()
+{
+       return GE_NONE;
+}
+
+static GSM_Error DecodeSMSHeader(unsigned char *message, GSM_SMSMessage *sms)
 {
        /* Short Message Type */
-       SMS->Type = message[layout.Type];
-       switch (SMS->Type) {
+        switch (sms->Type = message[7]) {
        case SMS_Deliver:
-               llayout = layout.Deliver;
                dprintf("Mobile Terminated message:\n");
                break;
        case SMS_Delivery_Report:
-               llayout = layout.DeliveryReport;
                dprintf("Delivery Report:\n");
+               UnpackDateTime(message + 39 + DataOffset[sms->Type], &(sms->Time));
+               dprintf("\tDelivery date: %s\n", PrintDateTime(message + 39 + DataOffset[sms->Type]));
                break;
        case SMS_Submit:
-               llayout = layout.Submit;
                dprintf("Mobile Originated message:\n");
                break;
-       case SMS_Picture:
-               llayout = layout.Picture;
-               dprintf("Picture Message:\n");
-               break;
        default:
-               dprintf("Not supported message type: %d\n", SMS->Type);
-               return GE_NOTSUPPORTED;
+               dprintf("Not supported message:\n");
+               break;
        }
-
-       if (!llayout.IsSupported) return GE_NOTSUPPORTED;
-
-       /* Delivery date */
-       if (llayout.Time > -1) {
-               UnpackDateTime(message + llayout.Time, &(SMS->SMSCTime));
-               dprintf("\tDelivery date: %s\n", PrintDateTime(message + llayout.Time));
+       /* Short Message status */
+       sms->Status = message[4];
+       dprintf("\tStatus: ");
+       switch (sms->Status) {
+       case SMS_Read:
+               dprintf("READ\n");
+               break;
+       case SMS_Unread:
+               dprintf("UNREAD\n");
+               break;
+       case SMS_Sent:
+               dprintf("SENT\n");
+               break;
+       case SMS_Unsent:
+               dprintf("UNSENT\n");
+               break;
+       default:
+               dprintf("UNKNOWN\n");
+               break;
        }
 
        /* Short Message location in memory */
-       if (llayout.Number > -1) {
-               SMS->Number = message[llayout.Number];
-               dprintf("\tLocation: %d\n", SMS->Number);
-       }
+       sms->Number = message[6];
+       dprintf("\tLocation: %d\n", sms->Number);
 
        /* Short Message Center */
-       if (llayout.MessageCenter > -1) {
-               strcpy(SMS->MessageCenter.Number, GetBCDNumber(message + llayout.MessageCenter));
-               dprintf("\tSMS center number: %s\n", SMS->MessageCenter.Number);
-               SMS->ReplyViaSameSMSC = false;
-               if (SMS->RemoteNumber.number[0] == 0 && (message[llayout.ReplyViaSameSMSC] & 0x80)) {
-                       SMS->ReplyViaSameSMSC = true;
-               }
+        strcpy(sms->MessageCenter.Number, GetBCDNumber(message));
+        dprintf("\tSMS center number: %s\n", sms->MessageCenter.Number);
+        sms->ReplyViaSameSMSC = false;
+        if (sms->RemoteNumber.number[0] == 0 && (message[12] & 0x80)) {
+               sms->ReplyViaSameSMSC = true;
        }
 
-       /* Remote number */
-       if (llayout.RemoteNumber > -1) {
-               message[llayout.RemoteNumber] = ((message[llayout.RemoteNumber])+1)/2+1;
-               strcpy(SMS->RemoteNumber.number, GetBCDNumber(message + llayout.RemoteNumber));
-               dprintf("\tRemote number (recipient or sender): %s\n", SMS->RemoteNumber.number);
-       }
-       
-       /* Sending time */
-       if (llayout.SMSCTime > -1) {
-               UnpackDateTime(message + llayout.SMSCTime, &(SMS->Time));
-               dprintf("\tDate: %s\n", PrintDateTime(message + llayout.SMSCTime));
-       }
+        /* Remote number */
+        message[20+DataOffset[sms->Type]] = ((message[20+DataOffset[sms->Type]])+1)/2+1;
+        dprintf("\tRemote number (recipient or sender): %s\n", GSM_GetBCDNumber(message + 20 + DataOffset[sms->Type]));
+        strcpy(sms->RemoteNumber.number, GetBCDNumber(message + 20 + DataOffset[sms->Type]));
 
-       /* Message length */
-       if (llayout.Length > -1)
-               SMS->Length = message[llayout.Length];
+       UnpackDateTime(message + 24 + DataOffset[sms->Type], &(sms->Time));
+        dprintf("\tDate: %s\n", PrintDateTime(message + 24 + DataOffset[sms->Type]));
 
        /* Data Coding Scheme */
-       if (llayout.DataCodingScheme > -1)
-               SMS->DCS.Type = message[llayout.DataCodingScheme];
+       if (sms->Type != SMS_Delivery_Report)
+               sms->DCS.Type = message[18 + DataOffset[sms->Type]];
+       else
+               sms->DCS.Type = 0;
 
        /* User Data Header */
-       if (llayout.UserDataHeader > -1)
-               if (message[llayout.UserDataHeader] & 0x40) { /* UDH header available */
-                       dprintf("UDH found\n");
-                       DecodeUDH(message + llayout.UserData, SMS);
-               }
+        if (message[20] & 0x40) /* UDH header available */
+                DecodeUDH(message + 31 + DataOffset[sms->Type], (SMS_UDHInfo **)sms->UDH, sms);
+       else                    /* No UDH */
+               sms->UDH_No = 0;
 
        return GE_NONE;
 }
@@ -739,43 +646,50 @@ static GSM_Error DecodeSMSHeader(unsigned char *message, GSM_SMSMessage *SMS)
 */
 GSM_Error DecodePDUSMS(unsigned char *message, GSM_SMSMessage *SMS, int MessageLength)
 {
-       int size;
-       GSM_Bitmap bitmap;
-       GSM_Error error;
+       int i, udhlen = 0;
 
-       error = DecodeSMSHeader(message, SMS);
-       if (error != GE_NONE) return error;
-       switch (SMS->Type) {
-       case SMS_Delivery_Report:
-               if (llayout.UserData > -1) SMSStatus(message[llayout.UserData], SMS);
-               break;
-       case SMS_Picture:
-               GSM_ReadSMSBitmap(SMS_Picture, message + llayout.UserData, NULL, &bitmap);
-               GSM_PrintBitmap(&bitmap);
-               size = MessageLength - llayout.UserData - 4 - bitmap.size;
-               SMS->Length = message[llayout.UserData + 4 + bitmap.size];
-               DecodeData(message + llayout.UserData + 5 + bitmap.size,
-                          (unsigned char *)&(SMS->MessageText),
-                          SMS->Length, size, 0, SMS->DCS);
-               SMS->MessageText[SMS->Length] = 0;
-               break;
-       default:
-               size = MessageLength -
-                       llayout.UserData + 1 - /* Header Length */
-                       SMS->UDH_Length;       /* UDH Length */
-               DecodeData(message + llayout.UserData + SMS->UDH_Length,
+       DecodeSMSHeader(message, SMS);
+       for (i = 0; i < SMS->UDH_No; i++) {
+               udhlen += headers[SMS->UDH[i].Type].length;
+       }
+       if (SMS->Type == SMS_Delivery_Report) {
+               SMSStatus(message[22], SMS);
+       } else {
+               int size = MessageLength -
+                          39 -                    /* Header Length */
+                          DataOffset[SMS->Type] - /* offset */
+                          udhlen -                /* UDH Length */
+                          2;                      /* checksum */
+               DecodeData(message + 39 + DataOffset[SMS->Type] + udhlen,
                           (unsigned char *)&(SMS->MessageText),
-                          SMS->Length, size, SMS->UDH_Length, SMS->DCS);
-               /* Just in case */
-               SMS->MessageText[SMS->Length] = 0;
-               break;
+                          SMS->Length, SMS->DCS,
+                          udhlen, size);
        }
-
+       
        return GE_NONE;
 }
 
 /* This function does simple SMS decoding - no PDU coding */
-GSM_Error DecodeTextSMS(unsigned char *message, GSM_SMSMessage *SMS)
+GSM_Error DecodeTextSMS(unsigned char *message, GSM_SMSMessage *sms)
 {
-       return GE_NONE;
+#if 0
+        int w, tmp, i;
+        unsigned char output[161];
+        
+        sms->EightBit = false;
+        w = (7 - off) % 7;
+        if (w < 0) w = (14 - off) % 14;
+        sms->Length = message[9 + 11 + offset] - (off * 8 + w) / 7;
+        offset += off;
+        w = (7 - off) % 7;
+        if (w < 0) w = (14 - off) % 14;
+        tmp = Unpack7BitCharacters(w, length-31-9-offset, sms->Length, message+9+31+offset, output);
+        dprintf("   7 bit SMS, body is (length %i): ",sms->Length);
+        for (i = 0; i < tmp; i++) {
+                dprintf("%c", DecodeWithDefaultAlphabet(output[i]));
+                sms->MessageText[i] = DecodeWithDefaultAlphabet(output[i]);
+        }
+        dprintf("\n");
+#endif
+        return GE_NONE;
 }