/*
+ $Id$
+
G N O K I I
A Linux/Unix toolset and driver for Nokia mobile phones.
- Released under the terms of the GNU GPL, see file COPYING for more details.
-
-*/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#include <time.h>
-
-#include "gsm-api.h"
-#include "gsm-coding.h"
-
-/* User data headers */
-GSM_UDHHeader UDHHeaders[] = {
- { GSM_ConcatenatedMessages, 0x05, "\x00\x03\x01\x00\x00" },
- /* See GSM 03.40 section 9.2.3.24.1 */
- { GSM_DisableVoice, 0x04, "\x01\x02\x00\x00" },
- { GSM_DisableFax, 0x04, "\x01\x02\x01\x00" },
- { GSM_DisableEmail, 0x04, "\x01\x02\x02\x00" },
- { GSM_EnableVoice, 0x04, "\x01\x02\x00\x01" },
- { GSM_EnableFax, 0x04, "\x01\x02\x01\x01" },
- { GSM_EnableEmail, 0x04, "\x01\x02\x02\x01" },
- /* See GSM 03.40 section 9.2.3.24.2 for voice, fax and email messages */
- { GSM_VoidSMS, 0x08, "\x01\x02\x02\x01\x01\x02\x02\x00" },
- /* When send such SMS to some phones, they don't display anything,
- only beep and enable vibra/light */
- { GSM_BugSMS, 0x09, "\x01\x02\x02\x01\x01\x02\x02\x00\xc0" },
-
- /* Short Smart Messaging UDH */
- /* General format: */
- /* 1 byte 0x05 : IEI application port addressing scheme, 16 bit address */
- /* 1 byte 0x04 : IEI length */
- /* 2 bytes : destination address: high & low byte */
- /* 2 bytes 0x00 0x00: originator address: high & low byte */
- { GSM_RingtoneUDH, 0x06, "\x05\x04\x15\x81\x00\x00" },
- { GSM_OpLogo, 0x06, "\x05\x04\x15\x82\x00\x00" },
- { GSM_CallerIDLogo, 0x06, "\x05\x04\x15\x83\x00\x00" },
- { GSM_WAPBookmarkUDH, 0x06, "\x05\x04\xc3\x4f\x00\x00" },
-
- /* Long Smart Messaging UDH */
- /* General format: */
- /* 1 byte 0x05 : IEI application port addressing scheme, 16 bit address */
- /* 1 byte 0x04 : IEI length */
- /* 2 bytes 0x00 0x00: destination address: high & low byte */
- /* 2 bytes 0x00 0x00: originator address: high & low byte */
- /* 1 byte 0x00 : null byte for end first part ? */
- /* 1 byte 0x03 : length for rest ? */
- /* 1 byte */
- /* 1 byte : number of all SMS */
- /* 1 byte : number of current SMS */
- { GSM_CalendarNoteUDH, 0x0b, "\x05\x04\x00\xe4\x00\x00\x00\x03\xc7\x00\x00" }, //from 3310 ?
- { GSM_CalendarNoteUDH2, 0x0b, "\x05\x04\x23\xf5\x00\x00\x00\x03\x01\x00\x00" }, //from 6210 or 9210 Note: last 0x01 changes according to note type
- { GSM_ProfileUDH, 0x0b, "\x05\x04\x15\x8a\x00\x00\x00\x03\xce\x00\x00" },
- { GSM_WAPBookmarkUDH, 0x0b, "\x05\x04\xc3\x4f\x00\x00\x00\x03\x01\x00\x00" },//note last 0x01 can change
- { GSM_WAPSettingsUDH, 0x0b, "\x05\x04\xc3\x4f\x00\x00\x00\x03\x7f\x00\x00" },
- { GSM_PhonebookUDH, 0x0b, "\x05\x04\x23\xf4\x00\x00\x00\x03\x01\x00\x00" },
-
- { GSM_NoUDH, 0x00, "" }
-};
+ Copyright (C) 2001 Pawe³ Kot <pkot@linuxnews.pl>
-#define ByteMask ((1 << Bits) - 1)
+ Released under the terms of the GNU GPL, see file COPYING for more details.
-int GSM_PackSevenBitsToEight(int offset, unsigned char *input, unsigned char *output)
-{
- unsigned char *OUT = output; /* Current pointer to the output buffer */
- unsigned char *IN = input; /* Current pointer to the input buffer */
- int Bits; /* Number of bits directly copied to
- the output buffer */
- Bits = (7 + offset) % 8;
-
- /* If we don't begin with 0th bit, we will write only a part of the
- first octet */
- if (offset) {
- *OUT = 0x00;
- OUT++;
- }
+ Library for parsing and creating Short Messages (SMS).
- while ((IN - input) < strlen(input)) {
- unsigned char Byte = EncodeWithDefaultAlphabet(*IN);
+ $Log$
+ Revision 1.1.1.8 2002/04/03 00:08:04 short
+ Found in "gnokii-working" directory, some November-patches version
- *OUT = Byte >> (7 - Bits);
- /* If we don't write at 0th bit of the octet, we should write
- a second part of the previous octet */
- if (Bits != 7)
- *(OUT-1) |= (Byte & ((1 << (7-Bits)) - 1)) << (Bits+1);
+ Revision 1.1 2001/11/08 16:23:21 pkot
+ New version of libsms. Not functional yet, but it reasonably stable API.
- Bits--;
+ Revision 1.1 2001/07/09 23:06:26 pkot
+ Moved sms.* files from my hard disk to CVS
- if (Bits == -1) Bits = 7;
- else OUT++;
+*/
- IN++;
- }
- return (OUT - output);
-}
+#include <stdlib.h>
-int GSM_UnpackEightBitsToSeven(int offset, int in_length, int out_length,
- unsigned char *input, unsigned char *output)
-{
- unsigned char *OUT = output; /* Current pointer to the output buffer */
- unsigned char *IN = input; /* Current pointer to the input buffer */
- unsigned char Rest = 0x00;
- int Bits;
-
- Bits = offset ? offset : 7;
-
- while ((IN - input) < in_length) {
-
- *OUT = ((*IN & ByteMask) << (7 - Bits)) | Rest;
- Rest = *IN >> Bits;
-
- /* If we don't start from 0th bit, we shouldn't go to the
- next char. Under *OUT we have now 0 and under Rest -
- _first_ part of the char. */
- if ((IN != input) || (Bits == 7)) OUT++;
- IN++;
-
- if ((OUT - output) >= out_length) break;
-
- /* After reading 7 octets we have read 7 full characters but
- we have 7 bits as well. This is the next character */
- if (Bits == 1) {
- *OUT = Rest;
- OUT++;
- Bits = 7;
- Rest = 0x00;
- } else {
- Bits--;
- }
- }
+#include "gsm-common.h"
+#include "gsm-encoding.h"
- return OUT - output;
-}
+struct udh_data {
+ unsigned int length;
+ char *header;
+};
-/* This function implements packing of numbers (SMS Center number and
- destination number) for SMS sending function. */
-/* See GSM 03.40 9.1.1:
- 1 byte - length of number given in semioctets or bytes (when given in bytes,
- includes one byte for byte with number format.
- Returned by function (set semioctet to true, if want result
- in semioctets).
- 1 byte - format of number. See GSM_NumberType; in gsm-common.h. Returned
- in u8 *Output.
- n bytes - 2n or 2n-1 semioctets with number. For some types of numbers
- in the most significant bits of the last byte with 0x0f
- (1111 binary) are filled if the number is represented
- with odd number of digits. Returned in u8 *Output. */
-/* 1 semioctet = 4 bits = half of byte */
-int GSM_PackSemiOctetNumber(u8 *Number, u8 *Output, bool semioctet) {
-
- u8 *IN=Number; /* Pointer to the input number */
- u8 *OUT=Output; /* Pointer to the output */
- int length=0,j;
- unsigned char format=GNT_UNKNOWN; // format of number used by us
-
- /* Checking for format number */
- while (*IN) {
- if (length==0 && *IN=='+')
- format=GNT_INTERNATIONAL; // first byte is '+'. It can be international
- else {
- if (*IN>'9' || *IN<'0') {
- format=GNT_ALPHANUMERIC; //char is not number. It must be alphanumeric
- }
- }
- IN++;length++;
- }
-
- /* Now we return to first byte */
- for (j=0;j<length;j++) IN--;
-
- /* 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 5.3.0, section 9.1.2.5, page 33.*/
- *OUT++=format;
-
- /* The next field is the number. See GSM 03.40 section 9.1.2 */
- switch (format) {
- case GNT_ALPHANUMERIC:
- length=GSM_PackSevenBitsToEight(0, IN, OUT)*2;
- break;
-
- case GNT_INTERNATIONAL:
- length--;
- EncodeBCD (OUT, IN+1, length, true);
- break;
-
- default:
- EncodeBCD (OUT, IN, length, true);
- break;
- }
-
- if (semioctet) {
- return length;
- } else {
- /* Convert number of semioctets to number of chars */
- if (length % 2) length++;
- return length / 2 + 1;
- }
-}
+/* 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 */
+};
-char *GSM_UnpackSemiOctetNumber(u8 *Number, bool semioctet) {
+/* User data headers */
+static struct udh_data headers[] = {
+ { 0x00, "" },
+ { 0x05, "\x00\x03\x01\x00\x00" }, /* Concatenated messages */
+ { 0x06, "\x05\x04\x15\x82\x00\x00" }, /* Operator 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 */
+ { 0x00, "" }
+};
- static char Buffer[20]="";
- int length=Number[0];
- if (semioctet) {
- /* Convert number of semioctets to number of chars */
- if (length % 2) length++;
- length=length / 2 + 1;
- }
-
- length--; //without leading byte with format of number
+/***
+ *** Util functions
+ ***/
- switch (Number[1]) {
- case GNT_ALPHANUMERIC:
- GSM_UnpackEightBitsToSeven(0, length, length, Number+2, Buffer);
- Buffer[length]=0;
- break;
+static char *GetBCDNumber(u8 *Number)
+{
+ static char Buffer[20] = "";
- case GNT_INTERNATIONAL:
- Buffer[0]='+';
- DecodeBCD (Buffer+1, Number+2, length);
- break;
+ /* This is the length of BCD coded number */
+ int length=Number[0];
+ int count;
+ int Digit;
- default:
- DecodeBCD (Buffer, Number+2, length);
- break;
- }
+ switch (Number[1]) {
- return Buffer;
+ case 0xd0:
+ Unpack7BitCharacters(0, length, length, Number+2, Buffer);
+ Buffer[length] = 0;
+ break;
+ 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;
+ }
+ return Buffer;
}
-/* See GSM 03.40 section 9.2.3.11 */
-GSM_Error GSM_EncodeSMSDateTime(GSM_DateTime *DT, unsigned char *req)
+#if 0
+char *GetBCDNumber(u8 *Number, int maxdigits, int maxbytes)
{
-#ifdef DEBUG
- fprintf(stdout,_("Date & time in saved SMS: %02i/%02i/%04i %02i:%02i:%02i\n"),
- DT->Day,DT->Month,DT->Year,DT->Hour,DT->Minute,DT->Second);
-#endif
-
- req[0]=EncodeWithBCDAlphabet(DT->Year);
- req[1]=EncodeWithBCDAlphabet(DT->Month);
- req[2]=EncodeWithBCDAlphabet(DT->Day);
- req[3]=EncodeWithBCDAlphabet(DT->Hour);
- req[4]=EncodeWithBCDAlphabet(DT->Minute);
- req[5]=EncodeWithBCDAlphabet(DT->Second);
-
- /* FIXME: do it */
- req[6]=0; /* TimeZone = +-0 */
-
- return GE_NONE;
+ 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;
}
-
-/* See GSM 03.40 section 9.2.3.11 */
-GSM_Error GSM_DecodeSMSDateTime(GSM_DateTime *DT, unsigned char *req)
-{
- DT->Year = DecodeWithBCDAlphabet(req[0]);
- DT->Month = DecodeWithBCDAlphabet(req[1]);
- DT->Day = DecodeWithBCDAlphabet(req[2]);
- DT->Hour = DecodeWithBCDAlphabet(req[3]);
- DT->Minute = DecodeWithBCDAlphabet(req[4]);
- DT->Second = DecodeWithBCDAlphabet(req[5]);
-
- DT->Timezone=(10*(req[6]&0x07)+(req[6]>>4))/4;
- if (req[6]&0x08) DT->Timezone = -DT->Timezone;
-
-#ifdef DEBUG
- fprintf(stdout, _("%d%d-"), req[0]&0xf, req[0]>>4);
- fprintf(stdout, _("%d%d-"), req[1]&0xf, req[1]>>4);
- fprintf(stdout, _("%d%d "), req[2]&0xf, req[2]>>4);
- fprintf(stdout, _("%d%d:"), req[3]&0xf, req[3]>>4);
- fprintf(stdout, _("%d%d:"), req[4]&0xf, req[4]>>4);
- fprintf(stdout, _("%d%d "), req[5]&0xf, req[5]>>4);
-
- if (req[6]) {
- if (req[6] & 0x08) fprintf(stdout, "-");
- else fprintf(stdout, "+");
-
- fprintf(stdout, _("%02d00"), (10*(req[6]&0x07)+(req[6]>>4))/4);
- }
-
- fprintf(stdout, "\n");
#endif
- return GE_NONE;
+static char *PrintDateTime(u8 *Number)
+{
+ static char Buffer[23] = "";
+
+ memset(Buffer, 0, 23);
+ 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;
}
-int GSM_EncodeETSISMSSubmitData(GSM_SMSMessage *SMS, GSM_ETSISMSMessage *ETSI)
+static SMS_DateTime *UnpackDateTime(u8 *Number, SMS_DateTime *dt)
{
- int off,size=0,size2=0,w,i;
-
- /* off - length of the user data header */
- off = 0;
-
- if (SMS->UDHType) {
- /* GSM 03.40 section 9.2.3.23 (TP-User-Data-Header-Indicator) */
- ETSI->firstbyte |= 0x40;
-
- /* off - length of the user data header */
- off = 1 + SMS->UDH[0];
-
- /* we copy the udh */
- memcpy(ETSI->MessageText, SMS->UDH, off);
+ 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;
+}
-// if (SMS->UDHType==GSM_HangSMS) ETSI->TPDCS=0x08; //Such SMS hangs phone (5110, 5.07),
- //when saved to Outbox atry try to read it
- /*from phone's menu*/
- }
+/***
+ *** ENCODING SMS
+ ***/
- switch (SMS->Coding) {
- /* When save SMS to SIM and it's 8 bit SMS,
- "Edit" is not displayed in phone menu and
- "Message cannot be displayed here" instead of message text */
- case GSM_Coding_8bit:
+/* 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
+*/
+static GSM_Error EncodeUDH(SMS_UDHInfo UDHi, char *UDH)
+{
+ unsigned char pos;
- /* the mask for the 8-bit data */
- /* GSM 03.40 section 9.2.3.10 (TP-Data-Coding-Scheme) and GSM 03.38 section 4 */
- ETSI->TPDCS |= 0xf4;
-
- memcpy(ETSI->MessageText + off, SMS->MessageText, SMS->Length);
+ pos = UDH[0];
+ switch (UDHi.Type) {
+ case SMS_NoUDH:
+ break;
+ case SMS_VoiceMessage:
+ case SMS_FaxMessage:
+ case SMS_EmailMessage:
+ UDH[pos+4] = UDHi.u.SpecialSMSMessageIndication.MessageCount;
+ if (UDHi.u.SpecialSMSMessageIndication.Store) UDH[pos+3] |= 0x80;
+ case SMS_ConcatenatedMessages:
+ case SMS_OpLogo:
+ case SMS_CallerIDLogo:
+ case SMS_Ringtone:
+ UDH[0] += headers[UDHi.Type].length;
+ memcpy(UDH+pos+1, headers[UDHi.Type].header, headers[UDHi.Type].length);
+ break;
+ default:
+ fprintf(stderr, _("Not supported User Data Header type\n"));
+ break;
+ }
+ return GE_NONE;
+}
- size2 = size = SMS->Length+off;
+static GSM_Error EncodeSMSSubmitHeader(GSM_SMSMessage *SMS, char *frame)
+{
+ GSM_Error error = GE_NONE;
+ int i;
- break;
+ /* SMS Center */
- case GSM_Coding_Default:
+ /* Reply Path */
+ if (SMS->ReplyViaSameSMSC) frame[13] |= 0x80;
- w=(7-off)%7;
- if (w<0) w=(14-off)%14;
+ /* 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;
+ }
- size = GSM_PackSevenBitsToEight(w, SMS->MessageText, ETSI->MessageText + off);
- size += off;
- size2 = (off*8 + w) / 7 + strlen(SMS->MessageText);
+ /* Status (Delivery) Report Request */
+ if (SMS->Report) frame[13] |= 0x20;
- break;
+ /* Validity Period Format: mask - 0x00, 0x10, 0x08, 0x18 */
+ frame[13] |= ((SMS->Validity.VPF & 0x03) << 3);
- case GSM_Coding_Unicode:
+ /* Reject Duplicates */
+ if (SMS->RejectDuplicates) frame[13] |= 0x04;
- /* GSM 03.40 section 9.2.3.10 (TP-Data-Coding-Scheme) and GSM 03.38 section 4 */
- ETSI->TPDCS |= 0x08;
+ /* Message Type is already set */
-#ifdef DEBUG
- fprintf(stdout,_("SMS Length is %i\n"),strlen(SMS->MessageText));
-#endif
+ /* Message Reference */
+ /* Can we set this? */
- EncodeUnicode (ETSI->MessageText+off,SMS->MessageText,strlen(SMS->MessageText));
- /* here we code "special" chars */
- for (i=0;i<strlen(SMS->MessageText);i++) {
- if (SMS->MessageText[i]=='~') ETSI->MessageText[off+1+i*2]=1; //enables/disables blinking
- if (SMS->MessageText[i]=='`') ETSI->MessageText[off+1+i*2]=0; //hides rest ot contents
- }
+ /* Protocol Identifier */
+ /* FIXME: allow to change this in better way.
+ currently only 0x5f == `Return Call Message' is used */
+ frame[16] = SMS->PID;
- size=size2=strlen(SMS->MessageText)*2+off;
+ /* Data Coding Scheme */
+ 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;
+ }
- break;
- }
+ /* User Data Length */
+ /* Will be filled later. */
- /* FIXME: support for compression */
- /* GSM 03.40 section 9.2.3.10 (TP-Data-Coding-Scheme) and GSM 03.38 section 4 */
- /* See also GSM 03.42 */
- /* if (SMS->Compression) ETSI->TPDCS |= 0x20; */
+ /* Destination Address */
- /* SMS->Length is:
- - integer representation of the number od octets within the user data when UD is coded using 8bit data
- - the sum of the number of septets in UDH including any padding and number of septets in UD in other case */
- /* GSM 03.40 section 9.2.3.16 (TP-User-Data-Length) */
- ETSI->TPUDL = size2;
+ /* Validity Period */
+ switch (SMS->Validity.VPF) {
+ case SMS_EnhancedFormat:
+ break;
+ case SMS_RelativeFormat:
+ break;
+ case SMS_AbsoluteFormat:
+ break;
+ default:
+ break;
+ }
- return size;
+ return GE_NONE;
}
-GSM_Error GSM_DecodeETSISMSSubmitData(GSM_SMSMessage *SMS, GSM_ETSISMSMessage *ETSI)
+static GSM_Error EncodeSMSDeliverHeader()
{
- int off,w,i,tmp=0;
- unsigned char output[161];
- bool UDHOK;
+ return GE_NONE;
+}
- /* off - length of the user data header */
- off = 0;
-
- SMS->UDHType = GSM_NoUDH;
+static GSM_Error EncodeSMSHeader(GSM_SMSMessage *SMS, char *frame)
+/* We can create either SMS DELIVER (for saving in Inbox) or SMS SUBMIT
+ (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 EncodeSMSSubmitHeader(SMS, frame);
+ default: /* we don't create other formats of SMS */
+ return GE_SMSWRONGFORMAT;
+ }
+}
- if (ETSI->firstbyte & 64) { /* UDH header available */
+/* This function encodes SMS as described in:
+ - GSM 03.40 version 6.1.0 Release 1997, section 9
+*/
+GSM_Error EncodePDUSMS(GSM_SMSMessage *SMS, char *frame)
+{
+ GSM_Error error = GE_NONE;
+ int i;
- off = (ETSI->MessageText[0] + 1); /* Length of UDH header */
-
- /* Copy UDH header into SMS->UDH */
- for (i = 0; i < off; i++) SMS->UDH[i] = ETSI->MessageText[i];
+ /* Short Message Data info element id */
-#ifdef DEBUG
- fprintf(stdout, " UDH header available (length %i",off);
-#endif
-
- SMS->UDHType = GSM_UnknownUDH;
-
- i=-1;
- while (true) {
- i++;
- if (UDHHeaders[i].UDHType==GSM_NoUDH) break;
- tmp=UDHHeaders[i].Length;
- if (tmp==SMS->UDH[0]) { //if length is the same
-
- if (tmp==0x05) tmp=tmp-2;/*two last bytes can be different for such UDH*/
- if (tmp==0x0b) tmp=tmp-3;/*three last bytes can be different for such UDH*/
-
- UDHOK=true;
- for (w=0;w<tmp;w++) {
- if (UDHHeaders[i].Text[w]!=SMS->UDH[w+1]) {
- UDHOK=false;
- break;
- }
- }
- if (UDHOK) {
- SMS->UDHType=UDHHeaders[i].UDHType;
- break;
- }
- }
- }
-
-#ifdef DEBUG
- switch (SMS->UDHType) {
- case GSM_ConcatenatedMessages:
- fprintf(stdout,_(", concatenated (linked) message %d/%d"),SMS->UDH[5],SMS->UDH[4]);break;
- case GSM_DisableVoice:
- fprintf(stdout,_(", disables voice indicator"));break;
- case GSM_EnableVoice:
- fprintf(stdout,_(", enables voice indicator"));break;
- case GSM_DisableFax:
- fprintf(stdout,_(", disables fax indicator"));break;
- case GSM_EnableFax:
- fprintf(stdout,_(", enables fax indicator"));break;
- case GSM_DisableEmail:
- fprintf(stdout,_(", disables email indicator"));break;
- case GSM_EnableEmail:
- fprintf(stdout,_(", enables email indicator"));break;
- case GSM_VoidSMS:
- fprintf(stdout,_(", void SMS"));break;
- case GSM_WAPBookmarkUDH:
- fprintf(stdout,_(", WAP Bookmark"));break;
- case GSM_WAPBookmarkUDHLong:
- fprintf(stdout,_(", WAP Bookmark, part %i/%i"),SMS->UDH[11],SMS->UDH[10]);break;
- case GSM_WAPSettingsUDH:
- fprintf(stdout,_(", WAP Settings, part %i/%i"),SMS->UDH[11],SMS->UDH[10]);break;
- case GSM_RingtoneUDH:
- fprintf(stdout,_(", ringtone"));break;
- case GSM_OpLogo:
- fprintf(stdout,_(", GSM Operator Logo"));break;
- case GSM_CallerIDLogo:
- fprintf(stdout,_(", Caller Logo"));break;
- case GSM_ProfileUDH:
- fprintf(stdout,_(", Profile SMS, part %i/%i"),SMS->UDH[11],SMS->UDH[10]);break;
- case GSM_CalendarNoteUDH:
- fprintf(stdout,_(", Calendar note SMS, part %i/%i"),SMS->UDH[11],SMS->UDH[10]);break;
- case GSM_CalendarNoteUDH2:
- fprintf(stdout,_(", Calendar note SMS, part %i/%i"),SMS->UDH[11],SMS->UDH[10]);break;
- case GSM_PhonebookUDH:
- fprintf(stdout,_(", Phonebook Entry, part %i/%i"),SMS->UDH[11],SMS->UDH[10]);break;
- default:
- fprintf(stdout,_(", UNKNOWN"));break;
- }
-
- fprintf(stdout, ")\n");
-
- hexdump(off,SMS->UDH);
-#endif
- }
+ /* Length of Short Message Data */
- SMS->Coding = GSM_Coding_Default;
+ /* Short Message Reference value */
+ if (SMS->Number) frame[3] = SMS->Number;
- /* GSM 03.40 section 9.2.3.10 (TP-Data-Coding-Scheme) and GSM 03.38 section 4 */
- if ((ETSI->TPDCS & 0xf4) == 0xf4) SMS->Coding=GSM_Coding_8bit;
- if ((ETSI->TPDCS & 0x08) == 0x08) SMS->Coding=GSM_Coding_Unicode;
+ /* Short Message status */
+ if (SMS->Status) frame[1] = SMS->Status;
- switch (SMS->Coding) {
- case GSM_Coding_Default:
- w=(7-off)%7;
- if (w<0) w=(14-off)%14;
-
- SMS->Length=ETSI->TPUDL - (off*8 + w) / 7;
+ /* Message Type */
- tmp=GSM_UnpackEightBitsToSeven(w,ETSI->TPUDL-off, SMS->Length, ETSI->MessageText+off, output);
+ /* SMSC number */
+ 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);
-#ifdef DEBUG
- fprintf(stdout, " 7 bit SMS, body is (length %i): ",SMS->Length);
-#endif /* DEBUG */
+ /* Header coding */
+// EncodeUDH(SMS, frame);
+// if (error != GE_NONE) return error;
- DecodeDefault (SMS->MessageText, output, SMS->Length);
+ /* User Data Header - if present */
+ for (i = 0; SMS->UDH[i].Type != SMS_NoUDH; i++) {
+ error = EncodeUDH(SMS->UDH[i], frame);
+ if (error != GE_NONE) return error;
+ }
-#ifdef DEBUG
- fprintf(stdout, "%s\n",SMS->MessageText);
-#endif
+ /* User Data */
+ // EncodeData(&(SMS->MessageText), &(SMS->DCS), frame);
- break;
- case GSM_Coding_8bit:
- SMS->Length=ETSI->TPUDL - off;
-
- memcpy(SMS->MessageText,ETSI->MessageText+off,SMS->Length);
-
-#ifdef DEBUG
- fprintf(stdout, " 8 bit SMS, body is (length %i)\n",SMS->Length);
- hexdump(SMS->Length,SMS->MessageText);
-#endif /* DEBUG */
-
- break;
- case GSM_Coding_Unicode:
- SMS->Length=(ETSI->TPUDL - off) / 2;
-
-#ifdef DEBUG
- fprintf(stdout, " 7 bit SMS, body is (length %i), Unicode coding: ",SMS->Length);
- for (i=0; i<SMS->Length;i++) {
- fprintf(stdout, "[%02x %02x]", ETSI->MessageText[off+i*2] , ETSI->MessageText[off+i*2+1]);
- }
- fprintf(stdout, "\n");
-#endif /* DEBUG */
-
- /* here we decode "special" chars */
- for (i=0; i<SMS->Length;i++) {
- if (ETSI->MessageText[off+i*2] ==0x00 &&
- ETSI->MessageText[off+i*2+1]==0x01)
- ETSI->MessageText[off+i*2+1]='~'; //enables/disables blinking
- if (ETSI->MessageText[off+i*2] ==0x00 &&
- ETSI->MessageText[off+i*2+1]==0x00)
- ETSI->MessageText[off+i*2+1]='`'; //hides rest ot contents
- }
-
- DecodeUnicode (SMS->MessageText, ETSI->MessageText+off, SMS->Length);
-
- break;
- }
-
- return GE_NONE;
+ return error;
}
-GSM_Error GSM_DecodeETSISMSStatusReportData(GSM_SMSMessage *SMS, GSM_ETSISMSMessage *ETSI)
+/* This function does simple SMS encoding - no PDU coding */
+GSM_Error EncodeTextSMS()
{
- /* See GSM 03.40 section 9.2.3.11 (TP-Service-Centre-Time-Stamp) */
-#ifdef DEBUG
- fprintf(stdout, _(" SMSC response date: "));
-#endif
- GSM_DecodeSMSDateTime(&SMS->SMSCTime, ETSI->SMSCDateTime);
-
- if (ETSI->TPStatus < 0x03) {
- strcpy(SMS->MessageText,_("Delivered"));
-
-#ifdef DEBUG
- /* more detailed reason only for debug */
- /* See GSM 03.40 section 9.2.3.15 (TP-Status) */
- switch (ETSI->TPStatus) {
- case 0x00: fprintf(stdout, _(" SM received by the SME"));break;
- case 0x01: fprintf(stdout, _(" SM forwarded by the SC to the SME but the SC is unable to confirm delivery"));break;
- case 0x02: fprintf(stdout, _(" SM replaced by the SC"));break;
- }
-#endif /* DEBUG */
-
- SMS->Length = 10;
-
- } else if (ETSI->TPStatus & 0x40) {
-
- strcpy(SMS->MessageText,_("Failed"));
-
-#ifdef DEBUG
- /* more detailed reason only for debug */
- if (ETSI->TPStatus & 0x20) {
-
- /* See GSM 03.40 section 9.2.3.15 (TP-Status) */
- fprintf(stdout, _(" Temporary error, SC is not making any more transfer attempts\n"));
- switch (ETSI->TPStatus) {
- case 0x60: fprintf(stdout, _(" Congestion"));break;
- case 0x61: fprintf(stdout, _(" SME busy"));break;
- case 0x62: fprintf(stdout, _(" No response from SME"));break;
- case 0x63: fprintf(stdout, _(" Service rejected"));break;
- case 0x64: fprintf(stdout, _(" Quality of service not available"));break;
- case 0x65: fprintf(stdout, _(" Error in SME"));break;
- default : fprintf(stdout, _(" Reserved/Specific to SC: %x"),ETSI->TPStatus);break;
- }
-
- } else {
-
- /* See GSM 03.40 section 9.2.3.15 (TP-Status) */
- fprintf(stdout, _(" Permanent error, SC is not making any more transfer attempts\n"));
- switch (ETSI->TPStatus) {
- case 0x40: fprintf(stdout, _(" Remote procedure error"));break;
- case 0x41: fprintf(stdout, _(" Incompatibile destination"));break;
- case 0x42: fprintf(stdout, _(" Connection rejected by SME"));break;
- case 0x43: fprintf(stdout, _(" Not obtainable"));break;
- case 0x44: fprintf(stdout, _(" Quality of service not available"));break;
- case 0x45: fprintf(stdout, _(" No internetworking available"));break;
- case 0x46: fprintf(stdout, _(" SM Validity Period Expired"));break;
- case 0x47: fprintf(stdout, _(" SM deleted by originating SME"));break;
- case 0x48: fprintf(stdout, _(" SM Deleted by SC Administration"));break;
- case 0x49: fprintf(stdout, _(" SM does not exist"));break;
- default : fprintf(stdout, _(" Reserved/Specific to SC: %x"),ETSI->TPStatus);break;
- }
- }
-#endif /* DEBUG */
-
- SMS->Length = 6;
- } else if (ETSI->TPStatus & 0x20) {
- strcpy(SMS->MessageText,_("Pending"));
-
-#ifdef DEBUG
- /* more detailed reason only for debug */
- /* See GSM 03.40 section 9.2.3.15 (TP-Status) */
- fprintf(stdout, _(" Temporary error, SC still trying to transfer SM\n"));
- switch (ETSI->TPStatus) {
- case 0x20: fprintf(stdout, _(" Congestion"));break;
- case 0x21: fprintf(stdout, _(" SME busy"));break;
- case 0x22: fprintf(stdout, _(" No response from SME"));break;
- case 0x23: fprintf(stdout, _(" Service rejected"));break;
- case 0x24: fprintf(stdout, _(" Quality of service not aviable"));break;
- case 0x25: fprintf(stdout, _(" Error in SME"));break;
- default : fprintf(stdout, _(" Reserved/Specific to SC: %x"),ETSI->TPStatus);break;
- }
-#endif /* DEBUG */
- SMS->Length = 7;
- } else {
- strcpy(SMS->MessageText,_("Unknown"));
-
-#ifdef DEBUG
- /* more detailed reason only for debug */
- fprintf(stdout, _(" Reserved/Specific to SC: %x"),ETSI->TPStatus);
-#endif /* DEBUG */
- SMS->Length = 8;
- }
-
-#ifdef DEBUG
- fprintf(stdout, _("\n"));
-#endif /* DEBUG */
-
- return GE_NONE;
+ return GE_NONE;
}
-GSM_Error GSM_EncodeETSISMSSubmitHeader(GSM_SMSMessage *SMS,GSM_ETSISMSMessage *ETSI)
-{
- GSM_Error error;
-
- /* First of all we should get SMSC number */
- if (SMS->MessageCenter.No) {
- error = GSM->GetSMSCenter(&SMS->MessageCenter);
- if (error != GE_NONE) return error;
- SMS->MessageCenter.No = 0;
- }
-
-#ifdef DEBUG
- fprintf(stdout, _("Packing SMS to \"%s\" via message center \"%s\"\n"), SMS->Destination, SMS->MessageCenter.Number);
-#endif /* DEBUG */
-
- ETSI->SMSCNumber[0]=GSM_PackSemiOctetNumber(SMS->MessageCenter.Number, ETSI->SMSCNumber+1, false);
-
- /* GSM 03.40 section 9.2.3.17 (TP-Reply-Path) */
- if (SMS->ReplyViaSameSMSC) ETSI->firstbyte |= 128;
-
- /* When save to Outbox with SMS Class, "Edit" is not displayed in phone menu
- and can forward it to another phone with set class (for example, 0=Flash) */
- /* Message Class*/
- /* GSM 03.40 section 9.2.3.10 (TP-Data-Coding-Scheme) and GSM 03.38 section 4 */
- if (SMS->Class>=0 && SMS->Class<5) ETSI->TPDCS |= (240+SMS->Class);
-
- /* When is not set for SMS saved for Inbox, phone displays "Message" instead
- of number and doesn't display "Details" info */
- ETSI->Number[0] = GSM_PackSemiOctetNumber(SMS->Destination, ETSI->Number+1, true);
-
- return GE_NONE;
-}
+/***
+ *** DECODING SMS
+ ***/
-GSM_Error GSM_DecodeETSISMSHeader(GSM_SMSMessage *SMS, GSM_ETSISMSMessage *ETSI)
+static GSM_Error SMSStatus(unsigned char status, GSM_SMSMessage *sms)
{
-#ifdef DEBUG
- fprintf(stdout, _(" SMS center number: %s"), GSM_UnpackSemiOctetNumber(ETSI->SMSCNumber,false));
- if (SMS->folder==0 && (ETSI->firstbyte & 128)!=0) //GST_INBOX
- fprintf(stdout, _(" (centre set for reply)"));
-#endif
-
- strcpy(SMS->MessageCenter.Number, GSM_UnpackSemiOctetNumber(ETSI->SMSCNumber,false));
-
- SMS->ReplyViaSameSMSC=false;
- if ((ETSI->firstbyte & 128)!=0) SMS->ReplyViaSameSMSC=true;
-
-#ifdef DEBUG
- fprintf(stdout, _("\n Remote number (recipient or sender): %s\n"), GSM_UnpackSemiOctetNumber(ETSI->Number,true));
-#endif
-
- strcpy(SMS->Sender, GSM_UnpackSemiOctetNumber(ETSI->Number,true));
-
- return GE_NONE;
+ if (status < 0x03) {
+ strcpy(sms->MessageText, _("Delivered"));
+ switch (status) {
+ case 0x00:
+ 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"));
+ break;
+ case 0x02:
+ dprintf(_("SM replaced by the SC"));
+ break;
+ }
+ sms->Length = 10;
+ } else if (status & 0x40) {
+
+ 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"));
+
+ switch (status) {
+ case 0x60:
+ dprintf(_("Congestion"));
+ break;
+ case 0x61:
+ dprintf(_("SME busy"));
+ break;
+ case 0x62:
+ dprintf(_("No response from SME"));
+ break;
+ case 0x63:
+ dprintf(_("Service rejected"));
+ break;
+ case 0x64:
+ dprintf(_("Quality of service not aviable"));
+ break;
+ case 0x65:
+ dprintf(_("Error in SME"));
+ break;
+ default:
+ dprintf(_("Reserved/Specific to SC: %x"), status);
+ break;
+ }
+ } else {
+ dprintf(_("Permanent error, SC is not making any more transfer attempts\n"));
+ switch (status) {
+ case 0x40:
+ dprintf(_("Remote procedure error"));
+ break;
+ case 0x41:
+ dprintf(_("Incompatibile destination"));
+ break;
+ case 0x42:
+ dprintf(_("Connection rejected by SME"));
+ break;
+ case 0x43:
+ dprintf(_("Not obtainable"));
+ break;
+ case 0x44:
+ dprintf(_("Quality of service not aviable"));
+ break;
+ case 0x45:
+ dprintf(_("No internetworking available"));
+ break;
+ case 0x46:
+ dprintf(_("SM Validity Period Expired"));
+ break;
+ case 0x47:
+ dprintf(_("SM deleted by originating SME"));
+ break;
+ case 0x48:
+ dprintf(_("SM Deleted by SC Administration"));
+ break;
+ case 0x49:
+ dprintf(_("SM does not exist"));
+ break;
+ default:
+ dprintf(_("Reserved/Specific to SC: %x"), status);
+ break;
+ }
+ }
+ sms->Length = 6;
+ } else if (status & 0x20) {
+ strcpy(sms->MessageText, _("Pending"));
+
+ /* more detailed reason only for debug */
+ dprintf(_("Temporary error, SC still trying to transfer SM\n"));
+ switch (status) {
+ case 0x20:
+ dprintf(_("Congestion"));
+ break;
+ case 0x21:
+ dprintf(_("SME busy"));
+ break;
+ case 0x22:
+ dprintf(_("No response from SME"));
+ break;
+ case 0x23:
+ dprintf(_("Service rejected"));
+ break;
+ case 0x24:
+ dprintf(_("Quality of service not aviable"));
+ break;
+ case 0x25:
+ dprintf(_("Error in SME"));
+ break;
+ default:
+ dprintf(_("Reserved/Specific to SC: %x"), status);
+ break;
+ }
+ sms->Length = 7;
+ } else {
+ strcpy(sms->MessageText, _("Unknown"));
+
+ /* more detailed reason only for debug */
+ dprintf(_("Reserved/Specific to SC: %x"), status);
+ sms->Length = 8;
+ }
+ return GE_NONE;
}
-/* FIXME: we should allow for all validity formats */
-GSM_Error GSM_EncodeETSISMSSubmitValidity(GSM_SMSMessage *SMS,GSM_ETSISMSMessage *ETSI)
+static GSM_Error DecodeData(char *message, char *output, int length, SMS_DataCodingScheme dcs, int udhlen, int size)
{
- /* GSM 03.40 section 9.2.3.3 (TP-Validity-Period-Format) */
- /* Bits 4 and 3: 10. TP-VP field present and integer represent (relative) */
- ETSI->firstbyte |= 0x10;
-
- /* GSM 03.40 section 9.2.3.12 (TP-Validity Period) */
- /* FIXME: error-checking for correct Validity - it should not be bigger then
- 63 weeks and smaller then 5minutes. We should also test intervals because
- the SMS->Validity to TP-VP is not continuos. I think that the simplest
- solution will be an array of correct values. We should parse it and if we
- find the closest TP-VP value we should use it. Or is it good to take
- closest smaller TP-VP as we do now? I think it is :-) */
-
- /* 5 minutes intervals up to 12 hours = 720 minutes */
- if (SMS->Validity <= 720)
- ETSI->TPVP = (unsigned char) (SMS->Validity/5)-1;
-
- /* 30 minutes intervals up to 1 day */
- else if ((SMS->Validity > 720) && (SMS->Validity <= 1440))
- ETSI->TPVP = (unsigned char) ((SMS->Validity-720)/30)+143;
-
- /* 1 day intervals up to 30 days */
- else if ((SMS->Validity > 1440) && (SMS->Validity <= 43200))
- ETSI->TPVP = (unsigned char) (SMS->Validity/1440)+166;
-
- /* 1 week intervals up to 63 weeks */
- else if ((SMS->Validity > 43200) && (SMS->Validity <= 635040))
- ETSI->TPVP = (unsigned char) (SMS->Validity/10080)+192;
-
- return GE_NONE;
+ /* Unicode */
+ if ((dcs.Type & 0x08) == 0x08) {
+ length = (length - udhlen)/2;
+ DecodeUnicode(output, message, length);
+ /* 8bit SMS */
+ } else {
+ if ((dcs.Type & 0xf4) == 0xf4) {
+ memcpy(output, message, length);
+ /* 7bit SMS */
+ } else {
+ length = length - (udhlen * 8 + ((7-udhlen)%7)) / 7;
+ Unpack7BitCharacters((7-udhlen)%7, size, length, message, output);
+ }
+ DecodeAscii(output, output, length);
+ }
+ dprintf("%s\n", output);
+ return GE_NONE;
}
-/* FIXME: do we need more than SMS_Submit and SMS_Deliver ? */
-GSM_Error GSM_EncodeETSISMS(GSM_SMSMessage *SMS, GSM_ETSISMSMessage *ETSI, SMS_MessageType PDU, int *length)
+/* This function decodes UDH 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
+*/
+static GSM_Error DecodeUDH(char *SMSMessage, SMS_UDHInfo **UDHi, GSM_SMSMessage *sms)
{
- int size=0;
- GSM_Error error;
-
- ETSI->firstbyte=0;
- ETSI->TPPID=0;
- ETSI->TPDCS=0;
- ETSI->TPUDL=0;
- ETSI->TPStatus=0;
- ETSI->TPVP=0;
-
- switch (PDU) {
- case SMS_Submit:
-
- /* GSM 03.40 section 9.2.3.1 (TP-Message-Type-Indicator) */
- /* Bits 1 and 0: 01. SMS-Submit */
- ETSI->firstbyte |= 0x01;
-
- /* GSM 03.40 section 9.2.3.5 (TP-Status-Raport-Request) */
- /* Mask for request for delivery report from SMSC */
- if (SMS->Type == GST_DR) ETSI->firstbyte |= 32;
-
- error=GSM_EncodeETSISMSSubmitHeader(SMS, ETSI);
- if (error!=GE_NONE) return error;
- error=GSM_EncodeETSISMSSubmitValidity(SMS, ETSI);
- if (error!=GE_NONE) return error;
- size=GSM_EncodeETSISMSSubmitData(SMS, ETSI);
-
- break;
- case SMS_Deliver:
-
- /* GSM 03.40 section 9.2.3.1 (TP-Message-Type-Indicator) */
- /* Bits 1 and 0: 00. SMS-Deliver */
- ETSI->firstbyte |= 0x00;
-
- error=GSM_EncodeETSISMSSubmitHeader(SMS, ETSI);
- if (error!=GE_NONE) return error;
- GSM_EncodeSMSDateTime(&SMS->Time, ETSI->DeliveryDateTime);
- size=GSM_EncodeETSISMSSubmitData(SMS, ETSI);
-
- break;
- default:
- break;
- }
-
- /* size is the length of the data in octets including udh */
- *length=size;
-
- return GE_NONE;
+ unsigned char length, pos, nr;
+
+ length = SMSMessage[0];
+ pos = 1;
+ nr = 0;
+ while (length > 0) {
+ unsigned char udh_length;
+
+ udh_length = SMSMessage[pos+1];
+ switch (SMSMessage[pos]) {
+ case 0x00: // Concatenated short messages
+ 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 (SMSMessage[pos + 3] & 0x03) {
+ case 0x00:
+ UDHi[nr]->Type = SMS_VoiceMessage;
+ break;
+ case 0x01:
+ UDHi[nr]->Type = SMS_FaxMessage;
+ break;
+ case 0x02:
+ UDHi[nr]->Type = SMS_EmailMessage;
+ break;
+ default:
+ UDHi[nr]->Type = SMS_UnknownUDH;
+ break;
+ }
+ 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
+ break;
+ case 0x06: // SMSC Control Parameters
+ break;
+ case 0x07: // UDH Source Indicator
+ break;
+ default:
+ break;
+ }
+ length -= (udh_length + 2);
+ pos += (udh_length + 2);
+ nr++;
+ }
+ sms->UDH_No = nr;
+
+ return GE_NONE;
}
-/* This function decodes parts of SMS coded according to GSM 03.40
- (given in GSM_ETSISMSMessage) to GSM_SMSMessage */
-GSM_Error GSM_DecodeETSISMS(GSM_SMSMessage *SMS, GSM_ETSISMSMessage *ETSI)
+static GSM_Error DecodeSMSSubmit()
{
- SMS_MessageType PDU=SMS_Deliver;
-
- /* See GSM 03.40 section 9.2.3.1 */
- if ((ETSI->firstbyte & 0x03) == 0x01) PDU=SMS_Submit;
- if ((ETSI->firstbyte & 0x03) == 0x02) PDU=SMS_Status_Report;
-
- GSM_DecodeETSISMSHeader(SMS, ETSI);
-
- switch (PDU) {
- case SMS_Submit:
-#ifdef DEBUG
- fprintf(stdout, _(" SMS submit "));
-#endif
- SMS->SMSData=false;
- GSM_DecodeETSISMSSubmitData(SMS,ETSI);
- break;
- case SMS_Deliver:
-#ifdef DEBUG
- fprintf(stdout, _(" SMS deliver "));
- fprintf(stdout, _(" Date: "));
-#endif
- SMS->SMSData=true;
- GSM_DecodeSMSDateTime(&SMS->Time, ETSI->DeliveryDateTime);
- GSM_DecodeETSISMSSubmitData(SMS,ETSI);
- break;
- case SMS_Status_Report:
-#ifdef DEBUG
- fprintf(stdout, _(" SMS status report "));
- fprintf(stdout, _(" Date: "));
-#endif
- SMS->SMSData=true;
- GSM_DecodeSMSDateTime(&SMS->Time, ETSI->DeliveryDateTime);
- GSM_DecodeETSISMSStatusReportData(SMS,ETSI);
- break;
- default:
- break;
- }
-
- SMS->MessageText[SMS->Length]=0;
-
- return GE_NONE;
+ return GE_NONE;
}
-void GSM_SetDefaultSMSData (GSM_SMSMessage *SMS)
+static GSM_Error DecodeSMSDeliver()
{
- struct tm *now;
- time_t nowh;
- GSM_DateTime Date;
-
- /* Default settings for SMS message:
- - no delivery report
- - Class Message 1
- - no compression
- - SMSC no. 1
- - validity 3 days */
-
- SMS->folder = GST_OUTBOX;
- SMS->Type = GST_SMS;
- SMS->Class = -1;
- SMS->Compression = false;
- SMS->MessageCenter.No = 1;
- SMS->Validity = 4320; /* 4320 minutes == 72 hours */
- SMS->ReplyViaSameSMSC = false;
- SMS->UDHType = GSM_NoUDH;
- SMS->Coding=GSM_Coding_Default;
- strcpy(SMS->Destination,"");
-
- /* This part is required to save SMS */
-
- SMS->Status = GSS_NOTSENTREAD;
- SMS->Location = 0;
-
- nowh=time(NULL);
- now=localtime(&nowh);
-
- Date.Year = now->tm_year;
- Date.Month = now->tm_mon+1;
- Date.Day = now->tm_mday;
- Date.Hour = now->tm_hour;
- Date.Minute = now->tm_min;
- Date.Second = now->tm_sec;
-
- /* I have 100 (for 2000) Year now :-) */
- if (Date.Year>99 && Date.Year<1900) {
- Date.Year=Date.Year+1900;
- }
-
- /* We need to have only two last digits of year */
- if (Date.Year>1900)
- {
- if (Date.Year<2000) Date.Year = Date.Year-1900;
- else Date.Year = Date.Year-2000;
- }
-
- SMS->Time.Year=Date.Year;
- SMS->Time.Month=Date.Month;
- SMS->Time.Day=Date.Day;
- SMS->Time.Hour=Date.Hour;
- SMS->Time.Minute=Date.Minute;
- SMS->Time.Second=Date.Second;
-
- SMS->Name[0]=0;
+ 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
-*/
-GSM_Error EncodeUDHHeader(char *text, GSM_UDH UDHType)
+static GSM_Error DecodeSMSHeader(unsigned char *message, GSM_SMSMessage *sms)
{
- int i=0;
-
- if (UDHType!=GSM_NoUDH) {
- while (true) {
- if (UDHHeaders[i].UDHType==GSM_NoUDH) {
-#ifdef DEBUG
- fprintf(stderr,_("Not supported User Data Header type\n"));
-#endif
+ /* Short Message Type */
+ switch (sms->Type = message[7]) {
+ case SMS_Deliver:
+ dprintf("Mobile Terminated message:\n");
break;
- }
- if (UDHHeaders[i].UDHType==UDHType) {
- text[0] = UDHHeaders[i].Length; // UDH Length
- memcpy(text+1, UDHHeaders[i].Text, UDHHeaders[i].Length);
+ case SMS_Delivery_Report:
+ dprintf("Delivery Report:\n");
+ UnpackDateTime(message + 39 + DataOffset[sms->Type], &(sms->Time));
+ dprintf("\tDelivery date: %s\n", PrintDateTime(message + 39 + DataOffset[sms->Type]));
break;
- }
- i++;
- }
- }
+ case SMS_Submit:
+ dprintf("Mobile Originated message:\n");
+ break;
+ default:
+ dprintf("Not supported message:\n");
+ break;
+ }
+ /* 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 */
+ sms->Number = message[6];
+ dprintf("\tLocation: %d\n", sms->Number);
+
+ /* Short Message Center */
+ 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 */
+ 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]));
+
+ UnpackDateTime(message + 24 + DataOffset[sms->Type], &(sms->Time));
+ dprintf("\tDate: %s\n", PrintDateTime(message + 24 + DataOffset[sms->Type]));
+
+ /* Data Coding Scheme */
+ if (sms->Type != SMS_Delivery_Report)
+ sms->DCS.Type = message[18 + DataOffset[sms->Type]];
+ else
+ sms->DCS.Type = 0;
+
+ /* User Data Header */
+ 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;
}
-int GSM_MakeSinglePartSMS2(GSM_SMSMessage *SMS,
- unsigned char *MessageBuffer,int cur, GSM_UDH UDHType, GSM_Coding_Type Coding){
-
- int j;
- int current,smsudhlength;
-
- GSM_SetDefaultSMSData(SMS);
-
- EncodeUDHHeader(SMS->UDH, UDHType);
- SMS->UDHType=UDHType;
-
- switch (UDHType) {
- case GSM_EnableVoice:
- case GSM_DisableVoice:
- case GSM_EnableEmail:
- case GSM_DisableEmail:
- case GSM_EnableFax:
- case GSM_DisableFax:
- SMS->Class=1;
- SMS->Coding=Coding;
- break;
- case GSM_NoUDH:
- case GSM_ConcatenatedMessages:
- case GSM_VoidSMS:
- case GSM_HangSMS:
- case GSM_BugSMS:
- case GSM_PhonebookUDH:
- case GSM_CalendarNoteUDH: //class=1?
- SMS->Class=-1;
- SMS->Coding=Coding;
- break;
- case GSM_OpLogo:
- case GSM_CallerIDLogo:
- case GSM_RingtoneUDH:
- case GSM_WAPBookmarkUDH:
- case GSM_WAPBookmarkUDHLong:
- case GSM_WAPSettingsUDH:
- case GSM_ProfileUDH:
- SMS->Class=1;
- SMS->Coding=GSM_Coding_8bit;
- break;
- default:
- fprintf(stderr,_("Error in makesinglepartsms !\n\n\n"));
- }
-
- current=cur;
-
- smsudhlength=0;
- if (UDHType!=GSM_NoUDH)
- smsudhlength=SMS->UDH[0]+1;
-
- j=0;
- switch (SMS->Coding) {
- case GSM_Coding_8bit:
- j=(GSM_MAX_SMS_8_BIT_LENGTH-smsudhlength); //max=140
- break;
- case GSM_Coding_Default:
- j=(GSM_MAX_SMS_8_BIT_LENGTH-smsudhlength)*8/7; //max=160
- break;
- case GSM_Coding_Unicode:
- j=(GSM_MAX_SMS_8_BIT_LENGTH-smsudhlength)/2; //max=70
- break;
- }
- if (current>j) current=j;
-
- memcpy(SMS->MessageText,MessageBuffer,current);
- SMS->MessageText[current]=0;
- SMS->Length=current;
-
- return current;
+/* This function decodes SMS as described in:
+ - GSM 03.40 version 6.1.0 Release 1997, section 9
+*/
+GSM_Error DecodePDUSMS(unsigned char *message, GSM_SMSMessage *SMS, int MessageLength)
+{
+ int i, udhlen = 0;
+
+ 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, SMS->DCS,
+ udhlen, size);
+ }
+
+ return GE_NONE;
}
-void GSM_MakeMultiPartSMS2(GSM_MultiSMSMessage *SMS,
- unsigned char *MessageBuffer,int MessageLength, GSM_UDH UDHType, GSM_Coding_Type Coding){
-
- int i=0,j,pos=0,current=0;
-
- for (i=0;i<4;i++) {
- if (pos==MessageLength) break;
-
- current=MessageLength-pos;
-
- pos=pos+GSM_MakeSinglePartSMS2(&SMS->SMS[i],MessageBuffer+pos,current,UDHType,Coding);
- }
-
- for (j=0;j<i;j++)
- {
- switch (UDHType) {
- case GSM_ProfileUDH:
- case GSM_WAPBookmarkUDHLong:
- case GSM_WAPSettingsUDH:
- case GSM_CalendarNoteUDH:
- case GSM_CalendarNoteUDH2:
- case GSM_PhonebookUDH:
- SMS->SMS[j].UDH[10]=i;
- SMS->SMS[j].UDH[11]=j+1;
- break;
- case GSM_ConcatenatedMessages:
- SMS->SMS[j].UDH[4]=i;
- SMS->SMS[j].UDH[5]=j+1;
- break;
- default:
- break;
- }
- }
-
- SMS->number=i;
+/* This function does simple SMS decoding - no PDU coding */
+GSM_Error DecodeTextSMS(unsigned char *message, GSM_SMSMessage *sms)
+{
+#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;
}