X-Git-Url: https://git.jankratochvil.net/?p=gnokii.git;a=blobdiff_plain;f=common%2Fgsm-sms.c;h=9fbb1148f1366c541e1a52f92aeb65ad3f8df345;hp=58b21bce19a5e681ece539d2ef7a245d3f5f8788;hb=2a2206f128cdd3ef136166e586026c774da5c490;hpb=4ee1266711b695852ec88f06784fd84400cd70bb diff --git a/common/gsm-sms.c b/common/gsm-sms.c index 58b21bc..9fbb114 100644 --- a/common/gsm-sms.c +++ b/common/gsm-sms.c @@ -1,782 +1,1024 @@ /* - $Id$ - G N O K I I A Linux/Unix toolset and driver for Nokia mobile phones. - Copyright (C) 2001 Pawe³ Kot - Released under the terms of the GNU GPL, see file COPYING for more details. + +*/ - Library for parsing and creating Short Messages (SMS). - - $Log$ - Revision 1.1.1.1 2001/11/25 21:59:06 short - :pserver:cvs@pserver.samba.org:/cvsroot - gnokii - Sun Nov 25 22:56 CET 2001 - - Revision 1.13 2001/11/23 22:07:44 machek - Fix SMS receiving to work, again. Unfortunately, it is not possible to - reuse much of gsm-sms.c... - - Revision 1.12 2001/11/22 17:56:53 pkot - smslib update. sms sending - - Revision 1.11 2001/11/20 16:22:22 pkot - First attempt to read Picture Messages. They should appear when you enable DEBUG. Nokia seems to break own standards. :/ (Markus Plail) - - Revision 1.10 2001/11/19 13:09:40 pkot - Begin work on sms sending +#include +#include +#include +#include +#include - Revision 1.9 2001/11/18 00:54:32 pkot - Bugfixes. I18n of the user responses. UDH support in libsms. Business Card UDH Type +#include "gsm-api.h" +#include "gsm-coding.h" - Revision 1.8 2001/11/17 20:19:29 pkot - smslib cleanups, fixes and debugging +/* 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, "" } +}; - Revision 1.7 2001/11/15 12:15:04 pkot - smslib updates. begin work on sms in 6100 series +#define ByteMask ((1 << Bits) - 1) - Revision 1.6 2001/11/14 18:21:19 pkot - Fixing some problems with UDH and Unicode, but still doesn't work yet :-( +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++; + } - Revision 1.5 2001/11/14 14:26:18 pkot - Changed offset of DCS field to the right value in 6210/7110 + while ((IN - input) < strlen(input)) { + unsigned char Byte = EncodeWithDefaultAlphabet(*IN); - Revision 1.4 2001/11/14 11:26:18 pkot - Getting SMS in 6210/7110 does finally work in some cases :) + *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.3 2001/11/13 16:12:20 pkot - Preparing libsms to get to work. 6210/7110 SMS and SMS Folder updates + Bits--; - Revision 1.2 2001/11/09 14:25:04 pkot - DEBUG cleanups + if (Bits == -1) Bits = 7; + else OUT++; - Revision 1.1 2001/11/08 16:23:21 pkot - New version of libsms. Not functional yet, but it reasonably stable API. + IN++; + } + return (OUT - output); +} - Revision 1.1 2001/07/09 23:06:26 pkot - Moved sms.* files from my hard disk to CVS +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--; + } + } -*/ + return OUT - output; +} -#include -#include +/* 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> 4; - if (Digit < 10) sprintf(Buffer, "%s%d", Buffer, Digit); - } - break; - } - return Buffer; +#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 *PrintDateTime(u8 *Number) +/* See GSM 03.40 section 9.2.3.11 */ +GSM_Error GSM_DecodeSMSDateTime(GSM_DateTime *DT, unsigned char *req) { - 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); - 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; + 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; } -SMS_DateTime *UnpackDateTime(u8 *Number, SMS_DateTime *dt) +int GSM_EncodeETSISMSSubmitData(GSM_SMSMessage *SMS, GSM_ETSISMSMessage *ETSI) { - 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; - - return dt; -} + int off,size=0,size2=0,w,i; -/*** - *** ENCODING SMS - ***/ + /* off - length of the user data header */ + off = 0; -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->UDHType) { + /* GSM 03.40 section 9.2.3.23 (TP-User-Data-Header-Indicator) */ + ETSI->firstbyte |= 0x40; - if (SMS->DCS.u.MessageWaiting.Active) dcs[0] |= 0x08; - dcs[0] |= (SMS->DCS.u.MessageWaiting.Type & 0x03); + /* off - length of the user data header */ + off = 1 + SMS->UDH[0]; - 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; -} + /* we copy the udh */ + memcpy(ETSI->MessageText, SMS->UDH, off); -/* 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; +// 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*/ + } - 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: - dprintf("Not supported User Data Header type\n"); - break; - } - return GE_NONE; -} + 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: -static GSM_Error EncodeSMSSubmitHeader(GSM_SMSMessage *SMS, char *frame) -{ - GSM_Error error = GE_NONE; + /* 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); - /* Standard Header: */ - memcpy(frame, "\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); + size2 = size = SMS->Length+off; - /* Reply Path */ - if (SMS->ReplyViaSameSMSC) frame[0] |= 0x80; + break; - /* User Data Header Indicator */ - if (SMS->UDH_No) frame[0] |= 0x40; + case GSM_Coding_Default: - /* Status (Delivery) Report Request */ - if (SMS->ReportStatus) frame[0] |= 0x20; + w=(7-off)%7; + if (w<0) w=(14-off)%14; - /* Validity Period Format: mask - 0x00, 0x10, 0x08, 0x18 */ - frame[0] |= ((SMS->Validity.VPF & 0x03) << 3); + size = GSM_PackSevenBitsToEight(w, SMS->MessageText, ETSI->MessageText + off); + size += off; + size2 = (off*8 + w) / 7 + strlen(SMS->MessageText); - /* Reject Duplicates */ - if (SMS->RejectDuplicates) frame[0] |= 0x04; + break; - /* Message Type is already set */ + case GSM_Coding_Unicode: - /* Message Reference */ - /* Can we set this? */ + /* GSM 03.40 section 9.2.3.10 (TP-Data-Coding-Scheme) and GSM 03.38 section 4 */ + ETSI->TPDCS |= 0x08; - /* Protocol Identifier */ - /* FIXME: allow to change this in better way. - currently only 0x5f == `Return Call Message' is used */ - if (SMS->PID) frame[3] = SMS->PID; +#ifdef DEBUG + fprintf(stdout,_("SMS Length is %i\n"),strlen(SMS->MessageText)); +#endif - /* Data Coding Scheme */ - switch (SMS->DCS.Type) { - case SMS_GeneralDataCoding: - if (SMS->DCS.u.General.Compressed) frame[4] |= 0x20; - if (SMS->DCS.u.General.Class) frame[4] |= (0x10 | (SMS->DCS.u.General.Class - 1)); - frame[4] |= ((SMS->DCS.u.General.Alphabet & 0x03) << 2); - break; - case SMS_MessageWaiting: - if (SMS->DCS.u.MessageWaiting.Discard) frame[4] |= 0xc0; - else if (SMS->DCS.u.MessageWaiting.Alphabet == SMS_UCS2) frame[4] |= 0xe0; - else frame[4] |= 0xd0; - if (SMS->DCS.u.MessageWaiting.Active) frame[4] |= 0x80; - frame[4] |= (SMS->DCS.u.MessageWaiting.Type & 0x03); - break; - default: - dprintf("Wrong Data Coding Scheme (DCS) format\n"); - return GE_SMSWRONGFORMAT; - } + EncodeUnicode (ETSI->MessageText+off,SMS->MessageText,strlen(SMS->MessageText)); + /* here we code "special" chars */ + for (i=0;iMessageText);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 + } - /* Destination Address */ - frame[5] = SemiOctetPack(SMS->RemoteNumber.number, frame + 6, SMS->RemoteNumber.type); + size=size2=strlen(SMS->MessageText)*2+off; - /* Validity Period */ - switch (SMS->Validity.VPF) { - case SMS_EnhancedFormat: - break; - case SMS_RelativeFormat: - break; - case SMS_AbsoluteFormat: - break; - default: - break; - } + break; + } - return error; + /* 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; */ + + /* 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; + + return size; } -static GSM_Error EncodeSMSDeliverHeader() +GSM_Error GSM_DecodeETSISMSSubmitData(GSM_SMSMessage *SMS, GSM_ETSISMSMessage *ETSI) { - return GE_NONE; + int off,w,i,tmp=0; + unsigned char output[161]; + bool UDHOK; + + /* off - length of the user data header */ + off = 0; + + SMS->UDHType = GSM_NoUDH; + + if (ETSI->firstbyte & 64) { /* UDH header available */ + + 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]; + +#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;wUDH[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 + } + + SMS->Coding = GSM_Coding_Default; + + /* 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; + + 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; + + tmp=GSM_UnpackEightBitsToSeven(w,ETSI->TPUDL-off, SMS->Length, ETSI->MessageText+off, output); + +#ifdef DEBUG + fprintf(stdout, " 7 bit SMS, body is (length %i): ",SMS->Length); +#endif /* DEBUG */ + + DecodeDefault (SMS->MessageText, output, SMS->Length); + +#ifdef DEBUG + fprintf(stdout, "%s\n",SMS->MessageText); +#endif + + 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; iLength;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; iLength;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; } -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 */ +GSM_Error GSM_DecodeETSISMSStatusReportData(GSM_SMSMessage *SMS, GSM_ETSISMSMessage *ETSI) { - /* 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); - default: /* we don't create other formats of SMS */ - return GE_SMSWRONGFORMAT; - } + /* 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; } -/* 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 GSM_EncodeETSISMSSubmitHeader(GSM_SMSMessage *SMS,GSM_ETSISMSMessage *ETSI) { - GSM_Error error = GE_NONE; - int i; - - dprintf("Sending SMS to %s via message center %s\n", SMS->RemoteNumber.number, SMS->MessageCenter.Number); - - /* SMSC number */ - dprintf("%d %s\n", SMS->MessageCenter.Type, SMS->MessageCenter.Number); - message[0] = SemiOctetPack(SMS->MessageCenter.Number, message + 1, SMS->MessageCenter.Type); - if (message[0] % 2) message[0]++; - message[0] = message[0] / 2 + 1; - - /* Common Header */ - error = EncodeSMSHeader(SMS, message + 12); - 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; - - /* User Data */ - EncodeData(SMS, message + 14, message + 36 + SMS->UDH_Length); - message[16] = SMS->Length; - return SMS->Length + 35; + 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; } -/* This function does simple SMS encoding - no PDU coding */ -GSM_Error EncodeTextSMS() +GSM_Error GSM_DecodeETSISMSHeader(GSM_SMSMessage *SMS, GSM_ETSISMSMessage *ETSI) { - return GE_NONE; -} +#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 -/*** - *** DECODING SMS - ***/ + strcpy(SMS->MessageCenter.Number, GSM_UnpackSemiOctetNumber(ETSI->SMSCNumber,false)); -static GSM_Error SMSStatus(unsigned char status, GSM_SMSMessage *SMS) -{ - 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 = strlen(_("Delivered")); - } 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 = strlen(_("Failed")); - } 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 = strlen(_("Pending")); - } else { - strcpy(SMS->MessageText, _("Unknown")); - - /* more detailed reason only for debug */ - dprintf("Reserved/Specific to SC: %x", status); - SMS->Length = strlen(_("Unknown")); - } - dprintf("\n"); - return GE_NONE; + 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; } -static GSM_Error DecodeData(char *message, char *output, int length, int size, int udhlen, SMS_DataCodingScheme dcs) +/* FIXME: we should allow for all validity formats */ +GSM_Error GSM_EncodeETSISMSSubmitValidity(GSM_SMSMessage *SMS,GSM_ETSISMSMessage *ETSI) { - /* Unicode */ - if ((dcs.Type & 0x08) == 0x08) { - dprintf("Unicode message\n"); - length = (length - udhlen)/2; - DecodeUnicode(output, message, length); - } else { - /* 8bit SMS */ - if ((dcs.Type & 0xf4) == 0xf4) { - dprintf("8bit message\n"); - memcpy(output, message, length); - /* 7bit SMS */ - } else { - dprintf("Default Alphabet\n"); - length = length - (udhlen * 8 + ((7-(udhlen%7))%7)) / 7; - Unpack7BitCharacters((7-udhlen)%7, size, length, message, output); - DecodeAscii(output, output, length); - } - } - dprintf("%s\n", output); - return GE_NONE; + /* 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; } -/* 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 *message, GSM_SMSMessage *SMS) +/* 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) { - unsigned char length, pos, nr; - - SMS->UDH_Length = length = message[0] + 1; - pos = 1; - nr = 0; - while (length > 1) { - unsigned char udh_length; - - udh_length = message[pos+1]; - switch (message[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]; - break; - case 0x01: // Special SMS Message Indication - switch (message[pos + 2] & 0x03) { - case 0x00: - dprintf("Voice Message\n"); - SMS->UDH[nr].Type = SMS_VoiceMessage; - break; - case 0x01: - dprintf("Fax Message\n"); - SMS->UDH[nr].Type = SMS_FaxMessage; - break; - case 0x02: - dprintf("Email Message\n"); - SMS->UDH[nr].Type = SMS_EmailMessage; - break; - default: - dprintf("Unknown\n"); - SMS->UDH[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]; - 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: - break; - } - length -= (udh_length + 2); - pos += (udh_length + 2); - nr++; - } - SMS->UDH_No = nr; - - return GE_NONE; + 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; } -static GSM_Error DecodeSMSHeader(unsigned char *message, GSM_SMSMessage *SMS) +/* 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) { - /* Short Message Type */ - switch (SMS->Type = message[2]) { - case SMS_Deliver: - dprintf("Mobile Terminated message:\n"); - break; - case SMS_Delivery_Report: - dprintf("Delivery Report:\n"); - UnpackDateTime(message + 34 + DataOffset[SMS->Type], &(SMS->SMSCTime)); - dprintf("\tDelivery date: %s\n", PrintDateTime(message + 34 + DataOffset[SMS->Type])); - break; - case SMS_Submit: - dprintf("Mobile Originated message:\n"); - break; - default: - dprintf("Not supported message type:\n"); - break; - } - - /* Short Message location in memory */ - SMS->Number = message[1]; - dprintf("\tLocation: %d\n", SMS->Number); - - /* Short Message Center */ - strcpy(SMS->MessageCenter.Number, GetBCDNumber(message + 3)); - dprintf("\tSMS center number: %s\n", SMS->MessageCenter.Number); - SMS->ReplyViaSameSMSC = false; - if (SMS->RemoteNumber.number[0] == 0 && (message[6] & 0x80)) { - SMS->ReplyViaSameSMSC = true; - } - - /* Remote number */ - message[15+DataOffset[SMS->Type]] = ((message[15+DataOffset[SMS->Type]])+1)/2+1; - dprintf("\tRemote number (recipient or sender): %s\n", GetBCDNumber(message + 15 + DataOffset[SMS->Type])); - strcpy(SMS->RemoteNumber.number, GetBCDNumber(message + 15 + DataOffset[SMS->Type])); - - UnpackDateTime(message + 27 + DataOffset[SMS->Type], &(SMS->Time)); - dprintf("\tDate: %s\n", PrintDateTime(message + 27 + DataOffset[SMS->Type])); - - /* Message length */ - SMS->Length = message[14+DataOffset[SMS->Type]]; - - /* Data Coding Scheme */ - if (SMS->Type != SMS_Delivery_Report && SMS->Type != SMS_Picture) - SMS->DCS.Type = message[13 + DataOffset[SMS->Type]]; - else - SMS->DCS.Type = 0; - - /* User Data Header */ - if (message[15] & 0x40) { /* UDH header available */ - dprintf("UDH found\n"); - DecodeUDH(message + 34 + DataOffset[SMS->Type], SMS); - } else { /* No UDH */ - dprintf("No UDH\n"); - SMS->UDH_No = 0; - } + 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) +{ + 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; } -/* This function decodes SMS as described in: - - GSM 03.40 version 6.1.0 Release 1997, section 9 +/* 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 DecodePDUSMS(unsigned char *message, GSM_SMSMessage *SMS, int MessageLength) +GSM_Error EncodeUDHHeader(char *text, GSM_UDH UDHType) { - int size; - GSM_Bitmap bitmap; - - DecodeSMSHeader(message, SMS); - switch (SMS->Type) { - case SMS_Delivery_Report: - SMSStatus(message[17], 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 break; - case SMS_Picture: - dprintf("Picture!!!\n"); - GSM_ReadSMSBitmap(SMS_Picture, message + 41, NULL, &bitmap); - GSM_PrintBitmap(&bitmap); - size = MessageLength - 45 - bitmap.size; - SMS->Length = message[45 + bitmap.size]; - printf("%d %d %d\n", SMS->Length, bitmap.size, size); - DecodeData(message + 46 + bitmap.size, - (unsigned char *)&(SMS->MessageText), - SMS->Length, size, 0, SMS->DCS); - SMS->MessageText[SMS->Length] = 0; + } + if (UDHHeaders[i].UDHType==UDHType) { + text[0] = UDHHeaders[i].Length; // UDH Length + memcpy(text+1, UDHHeaders[i].Text, UDHHeaders[i].Length); break; - default: - size = MessageLength - - 34 - /* Header Length */ - DataOffset[SMS->Type] - /* offset */ - SMS->UDH_Length - /* UDH Length */ - 5; /* checksum */ - DecodeData(message + 34 + DataOffset[SMS->Type] + SMS->UDH_Length, - (unsigned char *)&(SMS->MessageText), - SMS->Length, size, SMS->UDH_Length, SMS->DCS); - /* Just in case */ - SMS->MessageText[SMS->Length] = 0; - break; - } - + } + i++; + } + } return GE_NONE; } -/* This function does simple SMS decoding - no PDU coding */ -GSM_Error DecodeTextSMS(unsigned char *message, GSM_SMSMessage *SMS) -{ - 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; +} + +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;jSMS[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; }