/* (c) 2001-2004 by Marcin Wiacek */ /* based on some work from Pawel Kot, others and Gnokii */ #include #include #include #include "../../gsmcomon.h" #include "../../misc/coding/coding.h" #include "../gsmcal.h" #include "../gsmpbk.h" #include "../gsmlogo.h" #include "../gsmring.h" #include "../gsmdata.h" #include "../gsmnet.h" #include "gsmsms.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 (true) { i++; if (UDHHeaders[i].Type==UDH_NoUDH) break; 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.df, di.dl, UDH->Text, UDH->Length); #endif } 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); } /* GSM 03.40 section 9.2.3.10 (TP-Data-Coding-Scheme) and GSM 03.38 section 4 */ if ((buffer[Layout.TPDCS] & 0xf4) == 0xf4) SMS->Coding=SMS_Coding_8bit; if ((buffer[Layout.TPDCS] & 0x08) == 0x08) SMS->Coding=SMS_Coding_Unicode; switch (SMS->Coding) { case SMS_Coding_Default: 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.df, di.dl, SMS->Text, SMS->Length); #endif break; case SMS_Coding_Unicode: 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.df, di.dl, buffer+(Layout.Text+off), SMS->Length*2); dbgprintf("%s\n",DecodeUnicodeString(SMS->Text)); #endif break; } return ERR_NONE; } GSM_Error GSM_DecodeSMSFrameStatusReportData(GSM_SMSMessage *SMS, unsigned char *buffer, GSM_SMSMessageLayout Layout) { SMS->DeliveryStatus = buffer[Layout.TPStatus]; 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) dbgprintf("Text : %02x %i\n",buffer[Layout.Text] ,buffer[Layout.Text]); #endif SMS->UDH.Type = UDH_NoUDH; SMS->Coding = SMS_Coding_Default; 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->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.Text != 255 && Layout.TPDCS!=255 && Layout.TPUDL!=255) { 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) { if ((buffer[Layout.TPDCS] & 0xF3)==0xF0) SMS->Class = 0; if ((buffer[Layout.TPDCS] & 0xF3)==0xF1) SMS->Class = 1; if ((buffer[Layout.TPDCS] & 0xF3)==0xF2) SMS->Class = 2; if ((buffer[Layout.TPDCS] & 0xF3)==0xF3) SMS->Class = 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,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.df, di.dl, 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.df, di.dl, SMS->Text, SMS->Length); #endif break; case SMS_Coding_Default: 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: /* 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.df, di.dl, buffer+(Layout.Text+off), size2-off); dbgprintf("%s\n",DecodeUnicodeString(buffer+(Layout.Text+off))); #endif 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.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_Default; SMS->Text[0] = 0; SMS->Text[1] = 0; SMS->PDU = SMS_Submit; SMS->RejectDuplicates = false; SMS->MessageReference = 0; SMS->ReplaceMessage = 0; SMS->Length = 0; /* This part is required to save SMS */ SMS->State = SMS_UnSent; SMS->Location = 0; SMS->Folder = 0x02; /*Outbox*/ GSM_GetCurrentDateTime (&SMS->DateTime); 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; } } /* How should editor hadle tabs in this file? Add editor commands here. * vim: noexpandtab sw=8 ts=8 sts=8: */