/* (c) 2001-2006 by Marcin Wiacek */ /* Based on some Pawel Kot and others work from Gnokii (www.gnokii.org) * (C) 1999-2000 Hugh Blemings & Pavel Janik ml. (C) 2001-2004 Pawel Kot * GNU GPL version 2 or later */ /* Due to a problem in the source code management, the names of some of * the authors have unfortunately been lost. We do not mean to belittle * their efforts and hope they will contact us to see their names * properly added to the Copyright notice above. * Having published their contributions under the terms of the GNU * General Public License (GPL) [version 2], the Copyright of these * authors will remain respected by adhering to the license they chose * to publish their code under. */ #include #include #include #include #include #include #include #include "../../misc/coding/coding.h" #include "../../misc/misc.h" /* User data headers */ static GSM_UDHHeader UDHHeaders[] = { /* See GSM 03.40 section 9.2.3.24.1 * 1 byte 0x00 * 1 byte 0x03 * 1 byte 0x01: unique ID for message series * 1 byte 0x00: how many SMS in sequence * 1 byte 0x00: number of current SMS in sequence */ { UDH_ConcatenatedMessages, 0x05, "\x00\x03\x01\x00\x00",2,-1,4,3}, /* See GSM 03.40 section 9.2.3.24.2 for voice, fax and email messages */ { UDH_DisableVoice, 0x04, "\x01\x02\x00\x00",-1,-1,-1,-1}, { UDH_DisableFax, 0x04, "\x01\x02\x01\x00",-1,-1,-1,-1}, { UDH_DisableEmail, 0x04, "\x01\x02\x02\x00",-1,-1,-1,-1}, { UDH_EnableVoice, 0x04, "\x01\x02\x00\x01",-1,-1,-1,-1}, { UDH_EnableFax, 0x04, "\x01\x02\x01\x01",-1,-1,-1,-1}, { UDH_EnableEmail, 0x04, "\x01\x02\x02\x01",-1,-1,-1,-1}, /* When send such SMS to some phones, they don't display anything, * only beep and enable vibra/light */ { UDH_VoidSMS, 0x08, "\x01\x02\x02\x01\x01\x02\x02\x00",-1,-1,-1,-1}, /* Nokia Smart Messaging (short version) 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 */ { UDH_NokiaRingtone, 0x06, "\x05\x04\x15\x81\x00\x00",-1,-1,-1,-1}, { UDH_NokiaOperatorLogo, 0x06, "\x05\x04\x15\x82\x00\x00",-1,-1,-1,-1}, { UDH_NokiaCallerLogo, 0x06, "\x05\x04\x15\x83\x00\x00",-1,-1,-1,-1}, { UDH_NokiaWAP, 0x06, "\x05\x04\xc3\x4f\x00\x00",-1,-1,-1,-1}, /* Nokia Smart Messaging (long version) UDH and other * 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 : SAR * 1 byte 0x03 : SAR length * 1 byte : diagram reference number (unique ID for message series) * 1 byte : number of all SMS * 1 byte : number of current SMS */ { UDH_NokiaCalendarLong, 0x0b, "\x05\x04\x00\xe4\x00\x00\x00\x03\xc7\x00\x00",8,-1,10,9}, { UDH_MMSIndicatorLong, 0x0b, "\x05\x04\x0b\x84\x23\xf0\x00\x03\xe5\x00\x00",8,-1,10,9}, { UDH_NokiaRingtoneLong, 0x0b, "\x05\x04\x15\x81\x00\x00\x00\x03\x01\x00\x00",8,-1,10,9}, { UDH_NokiaOperatorLogoLong, 0x0b, "\x05\x04\x15\x82\x00\x00\x00\x03\x02\x00\x00",8,-1,10,9}, { UDH_NokiaProfileLong, 0x0b, "\x05\x04\x15\x8a\x00\x00\x00\x03\xce\x00\x00",8,-1,10,9}, { UDH_NokiaPhonebookLong, 0x0b, "\x05\x04\x23\xf4\x00\x00\x00\x03\x01\x00\x00",8,-1,10,9}, { UDH_NokiaWAPLong, 0x0b, "\x05\x04\xc3\x4f\x00\x00\x00\x03\x7f\x00\x00",8,-1,10,9}, { UDH_ConcatenatedMessages16bit,0x06, "\x08\x04\x00\x00\x00\x00",-1,2,5,4}, { UDH_NoUDH, 0x00, "",-1,-1,-1,-1} }; /* --------------------------- Unpacking SMS ------------------------------- */ /* See GSM 03.40 section 9.2.3.11 */ static GSM_Error GSM_DecodeSMSDateTime(GSM_DateTime *DT, unsigned char *req) { DT->Year = DecodeWithBCDAlphabet(req[0]); if (DT->Year<90) DT->Year=DT->Year+2000; else DT->Year=DT->Year+1990; 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]); /* Base for timezone is GMT. It's in quarters */ DT->Timezone=(10*(req[6]&0x07)+(req[6]>>4))/4; if (req[6]&0x08) DT->Timezone = -DT->Timezone; dbgprintf("Decoding date & time: "); dbgprintf("%s %4d/%02d/%02d ", DayOfWeek(DT->Year, DT->Month, DT->Day), DT->Year, DT->Month, DT->Day); dbgprintf("%02d:%02d:%02d %02d00\n", DT->Hour, DT->Minute, DT->Second, DT->Timezone); return ERR_NONE; } void GSM_DecodeUDHHeader(GSM_UDHHeader *UDH) { int i, tmp, w; bool UDHOK; UDH->Type = UDH_UserUDH; UDH->ID8bit = -1; UDH->ID16bit = -1; UDH->PartNumber = -1; UDH->AllParts = -1; i=-1; while (UDHHeaders[++i].Type != UDH_NoUDH) { tmp=UDHHeaders[i].Length; /* if length is the same */ if (tmp==UDH->Text[0]) { if (tmp==0x05) tmp=tmp-3;/*three last bytes can be different for such UDH*/ if (tmp==0x0b) tmp=tmp-3;/*three last bytes can be different for such UDH*/ if (tmp==0x06 && UDH->Text[1] == 0x08) tmp=tmp-4; UDHOK=true; for (w=0;wText[w+1]) { UDHOK=false; break; } } if (UDHOK) { UDH->Type=UDHHeaders[i].Type; if (UDHHeaders[i].ID8bit !=-1) UDH->ID8bit = UDH->Text[UDHHeaders[i].ID8bit+1]; if (UDHHeaders[i].ID16bit !=-1) UDH->ID16bit = UDH->Text[UDHHeaders[i].ID16bit+1]*256+UDH->Text[UDHHeaders[i].ID16bit+2]; if (UDHHeaders[i].PartNumber !=-1) UDH->PartNumber = UDH->Text[UDHHeaders[i].PartNumber+1]; if (UDHHeaders[i].AllParts !=-1) UDH->AllParts = UDH->Text[UDHHeaders[i].AllParts+1]; break; } } } #ifdef DEBUG dbgprintf("Type of UDH: "); switch (UDH->Type) { case UDH_ConcatenatedMessages : dbgprintf("Concatenated (linked) message"); break; case UDH_ConcatenatedMessages16bit : dbgprintf("Concatenated (linked) message"); break; case UDH_DisableVoice : dbgprintf("Disables voice indicator"); break; case UDH_EnableVoice : dbgprintf("Enables voice indicator"); break; case UDH_DisableFax : dbgprintf("Disables fax indicator"); break; case UDH_EnableFax : dbgprintf("Enables fax indicator"); break; case UDH_DisableEmail : dbgprintf("Disables email indicator"); break; case UDH_EnableEmail : dbgprintf("Enables email indicator"); break; case UDH_VoidSMS : dbgprintf("Void SMS"); break; case UDH_NokiaWAP : dbgprintf("Nokia WAP Bookmark"); break; case UDH_NokiaOperatorLogoLong : dbgprintf("Nokia operator logo"); break; case UDH_NokiaWAPLong : dbgprintf("Nokia WAP Bookmark or WAP/MMS Settings"); break; case UDH_NokiaRingtone : dbgprintf("Nokia ringtone"); break; case UDH_NokiaRingtoneLong : dbgprintf("Nokia ringtone"); break; case UDH_NokiaOperatorLogo : dbgprintf("Nokia GSM operator logo"); break; case UDH_NokiaCallerLogo : dbgprintf("Nokia caller logo"); break; case UDH_NokiaProfileLong : dbgprintf("Nokia profile"); break; case UDH_NokiaCalendarLong : dbgprintf("Nokia calendar note"); break; case UDH_NokiaPhonebookLong : dbgprintf("Nokia phonebook entry"); break; case UDH_UserUDH : dbgprintf("User UDH"); break; case UDH_MMSIndicatorLong : dbgprintf("MMS indicator"); break; case UDH_NoUDH: break; } if (UDH->ID8bit != -1) dbgprintf(", ID 8 bit %i",UDH->ID8bit); if (UDH->ID16bit != -1) dbgprintf(", ID 16 bit %i",UDH->ID16bit); if (UDH->PartNumber != -1 && UDH->AllParts != -1) { dbgprintf(", part %i of %i",UDH->PartNumber,UDH->AllParts); } dbgprintf("\n"); if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) DumpMessage(&di, UDH->Text, UDH->Length); #endif } GSM_Coding_Type GSM_GetMessageCoding(const char TPDCS) { /* GSM 03.40 section 9.2.3.10 (TP-Data-Coding-Scheme) and GSM 03.38 section 4 */ if ((TPDCS & 0xC0) == 0) { /* bits 7..4 set to 00xx */ if ((TPDCS & 0xC) == 0xC) { dbgprintf("WARNING: reserved alphabet value in TPDCS\n"); } else { if (TPDCS == 0) return SMS_Coding_Default_No_Compression; if ((TPDCS & 0x2C) == 0x00) return SMS_Coding_Default_No_Compression; if ((TPDCS & 0x2C) == 0x20) return SMS_Coding_Default_Compression; if ((TPDCS & 0x2C) == 0x08) return SMS_Coding_Unicode_No_Compression; if ((TPDCS & 0x2C) == 0x28) return SMS_Coding_Unicode_Compression; } } else if ((TPDCS & 0xF0) >= 0x40 && (TPDCS & 0xF0) <= 0xB0) { /* bits 7..4 set to 0100 ... 1011 */ dbgprintf("WARNING: reserved coding group in TPDCS\n"); } else if (((TPDCS & 0xF0) == 0xC0) || ((TPDCS & 0xF0) == 0xD0)) { /* bits 7..4 set to 1100 or 1101 */ if ((TPDCS & 4) == 4) { dbgprintf("WARNING: set reserved bit 2 in TPDCS\n"); } else { return SMS_Coding_Default_No_Compression; } } else if ((TPDCS & 0xF0) == 0xE0) { /* bits 7..4 set to 1110 */ if ((TPDCS & 4) == 4) { dbgprintf("WARNING: set reserved bit 2 in TPDCS\n"); } else { return SMS_Coding_Unicode_No_Compression; } } else if ((TPDCS & 0xF0) == 0xF0) { /* bits 7..4 set to 1111 */ if ((TPDCS & 8) == 8) { dbgprintf("WARNING: set reserved bit 3 in TPDCS\n"); } else { if ((TPDCS & 4) == 0) return SMS_Coding_Default_No_Compression; } } return 0; } GSM_Error GSM_DecodeSMSFrameText(GSM_SMSMessage *SMS, unsigned char *buffer, GSM_SMSMessageLayout Layout) { int off=0; /* length of the User Data Header */ int w,i,tmp=0; unsigned char output[161]; SMS->UDH.Length = 0; /* UDH header available */ if (buffer[Layout.firstbyte] & 64) { /* Length of UDH header */ off = (buffer[Layout.Text] + 1); SMS->UDH.Length = off; dbgprintf("UDH header available (length %i)\n",off); /* Copy UDH header into SMS->UDH */ for (i = 0; i < off; i++) SMS->UDH.Text[i] = buffer[Layout.Text + i]; GSM_DecodeUDHHeader(&SMS->UDH); } switch (SMS->Coding) { case SMS_Coding_Default_No_Compression: i = 0; do { i+=7; w=(i-off)%i; } while (w<0); SMS->Length=buffer[Layout.TPUDL] - (off*8 + w) / 7; tmp=GSM_UnpackEightBitsToSeven(w, buffer[Layout.TPUDL]-off, SMS->Length, buffer+(Layout.Text+off), output); dbgprintf("7 bit SMS, length %i\n",SMS->Length); DecodeDefault (SMS->Text, output, SMS->Length, true, NULL); dbgprintf("%s\n",DecodeUnicodeString(SMS->Text)); break; case SMS_Coding_8bit: SMS->Length=buffer[Layout.TPUDL] - off; memcpy(SMS->Text,buffer+(Layout.Text+off),SMS->Length); #ifdef DEBUG dbgprintf("8 bit SMS, length %i\n",SMS->Length); if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) DumpMessage(&di, SMS->Text, SMS->Length); #endif break; case SMS_Coding_Unicode_No_Compression: SMS->Length=(buffer[Layout.TPUDL] - off) / 2; DecodeUnicodeSpecialNOKIAChars(SMS->Text,buffer+(Layout.Text+off), SMS->Length); #ifdef DEBUG dbgprintf("Unicode SMS, length %i\n",SMS->Length); if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) DumpMessage(&di, buffer+(Layout.Text+off), SMS->Length*2); dbgprintf("%s\n",DecodeUnicodeString(SMS->Text)); #endif break; default: SMS->Length=0; break; } return ERR_NONE; } GSM_Error GSM_DecodeSMSFrameStatusReportData(GSM_SMSMessage *SMS, unsigned char *buffer, GSM_SMSMessageLayout Layout) { SMS->DeliveryStatus = buffer[Layout.TPStatus]; SMS->Coding = SMS_Coding_Unicode_No_Compression; if (buffer[Layout.TPStatus] < 0x03) { EncodeUnicode(SMS->Text,"Delivered",9); SMS->Length = 9; } else if (buffer[Layout.TPStatus] & 0x40) { EncodeUnicode(SMS->Text,"Failed",6); SMS->Length = 6; } else if (buffer[Layout.TPStatus] & 0x20) { EncodeUnicode(SMS->Text,"Pending",7); SMS->Length = 7; } else { EncodeUnicode(SMS->Text,"Unknown",7); SMS->Length = 7; } #ifdef DEBUG /* See GSM 03.40 section 9.2.3.15 (TP-Status) */ if (buffer[Layout.TPStatus] & 0x40) { if (buffer[Layout.TPStatus] & 0x20) { /* 0x60, 0x61, ... */ dbgprintf("Temporary error, SC is not making any more transfer attempts\n"); } else { /* 0x40, 0x41, ... */ dbgprintf("Permanent error, SC is not making any more transfer attempts\n"); } } else if (buffer[Layout.TPStatus] & 0x20) { /* 0x20, 0x21, ... */ dbgprintf("Temporary error, SC still trying to transfer SM\n"); } switch (buffer[Layout.TPStatus]) { case 0x00: dbgprintf("SM received by the SME"); break; case 0x01: dbgprintf("SM forwarded by the SC to the SME but the SC is unable to confirm delivery");break; case 0x02: dbgprintf("SM replaced by the SC"); break; case 0x20: dbgprintf("Congestion"); break; case 0x21: dbgprintf("SME busy"); break; case 0x22: dbgprintf("No response from SME"); break; case 0x23: dbgprintf("Service rejected"); break; case 0x24: dbgprintf("Quality of service not available"); break; case 0x25: dbgprintf("Error in SME"); break; case 0x40: dbgprintf("Remote procedure error"); break; case 0x41: dbgprintf("Incompatibile destination"); break; case 0x42: dbgprintf("Connection rejected by SME"); break; case 0x43: dbgprintf("Not obtainable"); break; case 0x44: dbgprintf("Quality of service not available"); break; case 0x45: dbgprintf("No internetworking available"); break; case 0x46: dbgprintf("SM Validity Period Expired"); break; case 0x47: dbgprintf("SM deleted by originating SME"); break; case 0x48: dbgprintf("SM Deleted by SC Administration"); break; case 0x49: dbgprintf("SM does not exist"); break; case 0x60: dbgprintf("Congestion"); break; case 0x61: dbgprintf("SME busy"); break; case 0x62: dbgprintf("No response from SME"); break; case 0x63: dbgprintf("Service rejected"); break; case 0x64: dbgprintf("Quality of service not available"); break; case 0x65: dbgprintf("Error in SME"); break; default : dbgprintf("Reserved/Specific to SC: %x",buffer[Layout.TPStatus]); break; } dbgprintf("\n"); #endif return ERR_NONE; } GSM_Error GSM_DecodeSMSFrame(GSM_SMSMessage *SMS, unsigned char *buffer, GSM_SMSMessageLayout Layout) { GSM_DateTime zerodt = {0,0,0,0,0,0,0}; #ifdef DEBUG if (Layout.firstbyte == 255) { dbgprintf("ERROR: firstbyte in SMS layout not set\n"); return ERR_UNKNOWN; } if (Layout.TPDCS != 255) dbgprintf("TPDCS : %02x %i\n",buffer[Layout.TPDCS] ,buffer[Layout.TPDCS]); if (Layout.TPMR != 255) dbgprintf("TPMR : %02x %i\n",buffer[Layout.TPMR] ,buffer[Layout.TPMR]); if (Layout.TPPID != 255) dbgprintf("TPPID : %02x %i\n",buffer[Layout.TPPID] ,buffer[Layout.TPPID]); if (Layout.TPUDL != 255) dbgprintf("TPUDL : %02x %i\n",buffer[Layout.TPUDL] ,buffer[Layout.TPUDL]); if (Layout.firstbyte != 255) dbgprintf("FirstByte : %02x %i\n",buffer[Layout.firstbyte],buffer[Layout.firstbyte]); if (Layout.Text != 255 && Layout.TPUDL != 255 && buffer[Layout.TPUDL] > 0) { dbgprintf("Text : %02x %i\n",buffer[Layout.Text] ,buffer[Layout.Text]); } #endif SMS->UDH.Type = UDH_NoUDH; SMS->Coding = SMS_Coding_8bit; SMS->Length = 0; SMS->SMSC.Location = 0; SMS->SMSC.DefaultNumber[0] = 0; SMS->SMSC.DefaultNumber[1] = 0; SMS->SMSC.Number[0] = 0; SMS->SMSC.Number[1] = 0; SMS->SMSC.Name[0] = 0; SMS->SMSC.Name[1] = 0; SMS->SMSC.Validity.Format = SMS_Validity_NotAvailable; SMS->SMSC.Format = SMS_FORMAT_Text; SMS->Number[0] = 0; SMS->Number[1] = 0; SMS->OtherNumbersNum = 0; SMS->Name[0] = 0; SMS->Name[1] = 0; SMS->ReplyViaSameSMSC = false; if (Layout.SMSCNumber!=255) { GSM_UnpackSemiOctetNumber(SMS->SMSC.Number,buffer+Layout.SMSCNumber,false); dbgprintf("SMS center number : \"%s\"\n",DecodeUnicodeString(SMS->SMSC.Number)); } if ((buffer[Layout.firstbyte] & 0x80)!=0) SMS->ReplyViaSameSMSC=true; #ifdef DEBUG if (SMS->ReplyViaSameSMSC) dbgprintf("SMS centre set for reply\n"); #endif if (Layout.Number!=255) { GSM_UnpackSemiOctetNumber(SMS->Number,buffer+Layout.Number,true); dbgprintf("Remote number : \"%s\"\n",DecodeUnicodeString(SMS->Number)); } if (Layout.TPDCS != 255) { /* Get message coding */ SMS->Coding = GSM_GetMessageCoding(buffer[Layout.TPDCS]); } if (Layout.Text != 255 && Layout.TPDCS!=255 && Layout.TPUDL!=255 && buffer[Layout.TPUDL] > 0) { GSM_DecodeSMSFrameText(SMS, buffer, Layout); } if (Layout.DateTime != 255) { GSM_DecodeSMSDateTime(&SMS->DateTime,buffer+(Layout.DateTime)); } else { SMS->DateTime = zerodt; } if (Layout.SMSCTime != 255 && Layout.TPStatus != 255) { /* GSM 03.40 section 9.2.3.11 (TP-Service-Centre-Time-Stamp) */ dbgprintf("SMSC response date: "); GSM_DecodeSMSDateTime(&SMS->SMSCTime, buffer+(Layout.SMSCTime)); GSM_DecodeSMSFrameStatusReportData(SMS,buffer,Layout); } else { SMS->SMSCTime = zerodt; } SMS->Class = -1; if (Layout.TPDCS != 255) { /* GSM 03.40 section 9.2.3.10 (TP-Data-Coding-Scheme) and GSM 03.38 section 4 */ if ((buffer[Layout.TPDCS] & 0xD0) == 0x10) { /* bits 7..4 set to 00x1 */ if ((buffer[Layout.TPDCS] & 0xC) == 0xC) { dbgprintf("WARNING: reserved alphabet value in TPDCS\n"); } else { SMS->Class = (buffer[Layout.TPDCS] & 3); } } else if ((buffer[Layout.TPDCS] & 0xF0) == 0xF0) { /* bits 7..4 set to 1111 */ if ((buffer[Layout.TPDCS] & 8) == 8) { dbgprintf("WARNING: set reserved bit 3 in TPDCS\n"); } else { SMS->Class = (buffer[Layout.TPDCS] & 3); } } } dbgprintf("SMS class: %i\n",SMS->Class); SMS->MessageReference = 0; if (Layout.TPMR != 255) SMS->MessageReference = buffer[Layout.TPMR]; SMS->ReplaceMessage = 0; if (Layout.TPPID != 255) { if (buffer[Layout.TPPID] > 0x40 && buffer[Layout.TPPID] < 0x48) { SMS->ReplaceMessage = buffer[Layout.TPPID] - 0x40; } } SMS->RejectDuplicates = false; if ((buffer[Layout.firstbyte] & 0x04)==0x04) SMS->RejectDuplicates = true; return ERR_NONE; } /* ----------------------------- Packing SMS ------------------------------- */ /* See GSM 03.40 section 9.2.3.11 */ static GSM_Error GSM_EncodeSMSDateTime(GSM_DateTime *DT, unsigned char *req) { int Year; dbgprintf("Encoding SMS datetime: %02i/%02i/%04i %02i:%02i:%02i\n", DT->Day,DT->Month,DT->Year,DT->Hour,DT->Minute,DT->Second); /* We need to have only two last digits of year */ if (DT->Year>1900) { if (DT->Year<2000) Year = DT->Year-1900; else Year = DT->Year-2000; } else Year = DT->Year; req[0]=EncodeWithBCDAlphabet(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 ERR_NONE; } static int GSM_EncodeSMSFrameText(GSM_SMSMessage *SMS, unsigned char *buffer, GSM_SMSMessageLayout Layout) { int off = 0; /* length of the User Data Header */ int size = 0, size2 = 0, w; size_t p; char buff[200]; if (SMS->UDH.Type!=UDH_NoUDH) { buffer[Layout.firstbyte] |= 0x40; /* GSM 03.40 section 9.2.3.23 (TP-User-Data-Header-Indicator) */ off = 1 + SMS->UDH.Text[0]; /* off - length of the User Data Header */ memcpy(buffer+Layout.Text, SMS->UDH.Text, off); /* we copy the udh */ #ifdef DEBUG dbgprintf("UDH, length %i\n",off); if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) DumpMessage(&di, SMS->UDH.Text, off); #endif } switch (SMS->Coding) { case SMS_Coding_8bit: /* 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 */ buffer[Layout.TPDCS] |= 0xf4; memcpy(buffer+(Layout.Text+off), SMS->Text, SMS->Length); size2 = size = SMS->Length+off; #ifdef DEBUG dbgprintf("8 bit SMS, length %i\n",SMS->Length); if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) DumpMessage(&di, SMS->Text, SMS->Length); #endif break; case SMS_Coding_Default_No_Compression: p = 0; do { p+=7; w=(p-off)%p; } while (w<0); p = UnicodeLength(SMS->Text); EncodeDefault(buff, SMS->Text, &p, true, NULL); size = GSM_PackSevenBitsToEight(w, buff, buffer+(Layout.Text+off), p); size += off; size2 = (off*8 + w) / 7 + p; dbgprintf("7 bit SMS, length %i, %i\n",size,size2); dbgprintf("%s\n",DecodeUnicodeString(SMS->Text)); if (size > GSM_MAX_8BIT_SMS_LENGTH) { size = 0; size2 = 0; } break; case SMS_Coding_Unicode_No_Compression: /* GSM 03.40 section 9.2.3.10 (TP-Data-Coding-Scheme) * and GSM 03.38 section 4 */ buffer[Layout.TPDCS] |= 0x08; EncodeUnicodeSpecialNOKIAChars(buffer+(Layout.Text+off), SMS->Text, UnicodeLength(SMS->Text)); size=size2=UnicodeLength(buffer+(Layout.Text+off))*2+off; #ifdef DEBUG dbgprintf("Unicode SMS, length %i\n",(size2-off)/2); if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) DumpMessage(&di, buffer+(Layout.Text+off), size2-off); dbgprintf("%s\n",DecodeUnicodeString(buffer+(Layout.Text+off))); #endif break; default: break; } /* GSM 03.40 section 9.2.3.16 (TP-User-Data-Length) * SMS->Length is: - integer representation of the number od octets within the user data when TP-User-Data is coded using 8 bit data - the sum of the number of septets in UDH including any padding and the number of septets in TP-User-Data in other case */ buffer[Layout.TPUDL] = size2; return size; } GSM_Error GSM_EncodeSMSFrame(GSM_SMSMessage *SMS, unsigned char *buffer, GSM_SMSMessageLayout Layout, int *length, bool clear) { int i; if (clear) { /* Cleaning up to the SMS text */ for (i=0;iPDU) { case SMS_Submit: buffer[Layout.firstbyte] |= 0x01; break; /* SMS_Status_Report when Submit sms should have delivery report */ /* We DON'T CREATE FRAME FOR REAL SMS_STATUS_REPORT */ case SMS_Status_Report: buffer[Layout.firstbyte] |= 0x01; /* GSM 03.40 section 9.2.3.5 (TP-Status-Raport-Request) */ /* Set when want delivery report from SMSC */ buffer[Layout.firstbyte] |= 0x20; break; case SMS_Deliver: buffer[Layout.firstbyte] |= 0x00; } /* GSM 03.40 section 9.2.3.17 (TP-Reply-Path) */ if (SMS->ReplyViaSameSMSC) buffer[Layout.firstbyte] |= 0x80; if (Layout.Number!=255) { buffer[Layout.Number] = GSM_PackSemiOctetNumber(SMS->Number,buffer+(Layout.Number+1),true); dbgprintf("Recipient number \"%s\"\n",DecodeUnicodeString(SMS->Number)); } if (Layout.SMSCNumber!=255) { buffer[Layout.SMSCNumber]=GSM_PackSemiOctetNumber(SMS->SMSC.Number,buffer+(Layout.SMSCNumber+1), false); dbgprintf("SMSC number \"%s\"\n",DecodeUnicodeString(SMS->SMSC.Number)); } /* Message Class*/ /* GSM 03.40 section 9.2.3.10 (TP-Data-Coding-Scheme) and GSM 03.38 section 4 */ if (Layout.TPDCS != 255) { if (SMS->Class>=0 && SMS->Class<5) buffer[Layout.TPDCS] |= (240+SMS->Class); dbgprintf("SMS class %i\n",SMS->Class); } if (Layout.TPVP != 255) { /* 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) */ buffer[Layout.firstbyte] |= 0x10; buffer[Layout.TPVP]=((unsigned char)SMS->SMSC.Validity.Relative); dbgprintf("SMS validity %02x\n",SMS->SMSC.Validity.Relative); } if (Layout.DateTime != 255) { GSM_EncodeSMSDateTime(&SMS->DateTime, buffer+Layout.DateTime); } if (Layout.TPMR != 255) { dbgprintf("TPMR: %02x %i\n",SMS->MessageReference,SMS->MessageReference); buffer[Layout.TPMR] = SMS->MessageReference; } if (SMS->RejectDuplicates) { /* GSM 03.40 section 9.2.3.25 (TP Reject Duplicates) */ buffer[Layout.firstbyte] |= 0x04; } if (Layout.TPPID != 255) { buffer[Layout.TPPID] = 0; if (SMS->ReplaceMessage > 0 && SMS->ReplaceMessage < 8) { buffer[Layout.TPPID] = 0x40 + SMS->ReplaceMessage; } } /* size is the length of the data in octets including UDH */ *length=GSM_EncodeSMSFrameText(SMS,buffer,Layout); /* if (*length == 0) return GE_UNKNOWN; */ *length += Layout.Text; return ERR_NONE; } /* ----------------- Some help functions ----------------------------------- */ void GSM_SetDefaultSMSData(GSM_SMSMessage *SMS) { SMS->Class = -1; SMS->SMSC.Location = 1; SMS->SMSC.Name[0] = 0; SMS->SMSC.Name[1] = 0; SMS->SMSC.Number[0] = 0; SMS->SMSC.Number[1] = 0; SMS->SMSC.DefaultNumber[0] = 0; SMS->SMSC.DefaultNumber[1] = 0; SMS->SMSC.Format = SMS_FORMAT_Text; SMS->SMSC.Validity.Format = SMS_Validity_RelativeFormat; SMS->SMSC.Validity.Relative = SMS_VALID_Max_Time; SMS->ReplyViaSameSMSC = false; SMS->UDH.Type = UDH_NoUDH; SMS->UDH.Length = 0; SMS->UDH.Text[0] = 0; SMS->UDH.ID8bit = 0; SMS->UDH.ID16bit = 0; SMS->UDH.PartNumber = 0; SMS->UDH.AllParts = 0; SMS->Coding = SMS_Coding_8bit; SMS->Text[0] = 0; SMS->Text[1] = 0; SMS->PDU = SMS_Submit; SMS->RejectDuplicates = false; SMS->MessageReference = 0; SMS->ReplaceMessage = 0; SMS->Length = 0; SMS->DeliveryStatus = 0; SMS->ReplyViaSameSMSC = 0; SMS->Class = 0; SMS->MessageReference = 0; SMS->OtherNumbersNum = 0; /* This part is required to save SMS */ SMS->State = SMS_UnSent; SMS->Location = 0; SMS->Memory = 0; SMS->Folder = 0x02; /*Outbox*/ SMS->InboxFolder = false; GSM_GetCurrentDateTime (&SMS->DateTime); GSM_GetCurrentDateTime (&SMS->SMSCTime); SMS->Name[0] = 0; SMS->Name[1] = 0; } /** * GSM 03.40 section 9.2.3.24 */ void GSM_EncodeUDHHeader(GSM_UDHHeader *UDH) { int i=0; if (UDH->Type == UDH_NoUDH) { UDH->Length = 0; return; } if (UDH->Type == UDH_UserUDH) { UDH->Length = UDH->Text[0] + 1; return; } while (true) { if (UDHHeaders[i].Type==UDH_NoUDH) { dbgprintf("Not supported UDH type\n"); break; } if (UDHHeaders[i].Type!=UDH->Type) { i++; continue; } /* UDH Length */ UDH->Text[0] = UDHHeaders[i].Length; memcpy(UDH->Text+1, UDHHeaders[i].Text, UDHHeaders[i].Length); UDH->Length = UDH->Text[0] + 1; if (UDHHeaders[i].ID8bit != -1) { UDH->Text[UDHHeaders[i].ID8bit+1] = UDH->ID8bit % 256; } else { UDH->ID8bit = -1; } if (UDHHeaders[i].ID16bit != -1) { UDH->Text[UDHHeaders[i].ID16bit+1] = UDH->ID16bit / 256; UDH->Text[UDHHeaders[i].ID16bit+2] = UDH->ID16bit % 256; } else { UDH->ID16bit = -1; } if (UDHHeaders[i].PartNumber != -1) { UDH->Text[UDHHeaders[i].PartNumber+1] = UDH->PartNumber; } else { UDH->PartNumber = -1; } if (UDHHeaders[i].AllParts != -1) { UDH->Text[UDHHeaders[i].AllParts+1] = UDH->AllParts; } else { UDH->AllParts = -1; } break; } } bool GSM_DecodeSiemensOTASMS(GSM_SiemensOTASMSInfo *Info, GSM_SMSMessage *SMS) { int current; if (SMS->PDU != SMS_Deliver) return false; if (SMS->Coding != SMS_Coding_8bit) return false; if (SMS->Class != 1) return false; if (SMS->UDH.Type != UDH_NoUDH) return false; if (SMS->Length < 22) return false; if (strncmp(SMS->Text,"//SEO",5)!=0) return false; /* Siemens Exchange Object */ if (SMS->Text[5]!=1) return false; /* version 1 */ Info->DataLen = SMS->Text[6] + SMS->Text[7]*256; Info->SequenceID = SMS->Text[8] + SMS->Text[9]*256 + SMS->Text[10]*256*256 + SMS->Text[11]*256*256*256; Info->PacketNum = SMS->Text[12] + SMS->Text[13]*256; Info->PacketsNum = SMS->Text[14] + SMS->Text[15]*256; dbgprintf("Packet %i/%i\n",Info->PacketNum,Info->PacketsNum); Info->AllDataLen = SMS->Text[16] + SMS->Text[17]*256 + SMS->Text[18]*256*256 + SMS->Text[19]*256*256*256; dbgprintf("DataLen %i/%lu\n",Info->DataLen,Info->AllDataLen); if (SMS->Text[20] > 9) return false; memcpy(Info->DataType,SMS->Text+21,SMS->Text[20]); Info->DataType[SMS->Text[20]] = 0; dbgprintf("DataType '%s'\n",Info->DataType); current = 21+SMS->Text[20]; if (SMS->Text[current] > 39) return false; memcpy(Info->DataName,SMS->Text+current+1,SMS->Text[current]); Info->DataName[SMS->Text[current]] = 0; dbgprintf("DataName '%s'\n",Info->DataName); current += SMS->Text[current]+1; memcpy(Info->Data,SMS->Text+current,Info->DataLen); return true; } /* How should editor hadle tabs in this file? Add editor commands here. * vim: noexpandtab sw=8 ts=8 sts=8: */