Diffstat (limited to 'gammu/emb/common/service/sms/gsmmulti.c') (more/less context) (ignore whitespace changes)
-rw-r--r-- | gammu/emb/common/service/sms/gsmmulti.c | 1148 |
1 files changed, 1148 insertions, 0 deletions
diff --git a/gammu/emb/common/service/sms/gsmmulti.c b/gammu/emb/common/service/sms/gsmmulti.c new file mode 100644 index 0000000..6c1cdcd --- a/dev/null +++ b/gammu/emb/common/service/sms/gsmmulti.c @@ -0,0 +1,1148 @@ +/* (c) 2002-2004 by Marcin Wiacek */ + +#include <ctype.h> +#include <string.h> +#include <time.h> + +#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" +#include "gsmmulti.h" +#include "gsmems.h" + +/* ----------------- Splitting SMS into parts ------------------------------ */ + +unsigned char GSM_MakeSMSIDFromTime(void) +{ + GSM_DateTime Date; + unsigned char retval; + + GSM_GetCurrentDateTime (&Date); + retval = Date.Second; + switch (Date.Minute/10) { + case 2: case 7: retval = retval + 60; break; + case 4: case 8: retval = retval + 120; break; + case 9: case 5: case 0: retval = retval + 180; break; + } + retval += Date.Minute/10; + return retval; +} + +void GSM_Find_Free_Used_SMS2(GSM_Coding_Type Coding,GSM_SMSMessage SMS, int *UsedText, int *FreeText, int *FreeBytes) +{ + int UsedBytes; + + switch (Coding) { + case SMS_Coding_Default: + FindDefaultAlphabetLen(SMS.Text,&UsedBytes,UsedText,500); + UsedBytes = *UsedText * 7 / 8; + if (UsedBytes * 8 / 7 != *UsedText) UsedBytes++; + *FreeBytes = GSM_MAX_8BIT_SMS_LENGTH - SMS.UDH.Length - UsedBytes; + *FreeText = (GSM_MAX_8BIT_SMS_LENGTH - SMS.UDH.Length) * 8 / 7 - *UsedText; + break; + case SMS_Coding_Unicode: + *UsedText = UnicodeLength(SMS.Text); + UsedBytes = *UsedText * 2; + *FreeBytes = GSM_MAX_8BIT_SMS_LENGTH - SMS.UDH.Length - UsedBytes; + *FreeText = *FreeBytes / 2; + break; + case SMS_Coding_8bit: + *UsedText = UsedBytes = SMS.Length; + *FreeBytes = GSM_MAX_8BIT_SMS_LENGTH - SMS.UDH.Length - UsedBytes; + *FreeText = *FreeBytes; + break; + } + dbgprintf("UDH len %i, UsedBytes %i, FreeText %i, UsedText %i, FreeBytes %i\n",SMS.UDH.Length,UsedBytes,*FreeText,*UsedText,*FreeBytes); +} + +GSM_Error GSM_AddSMS_Text_UDH(GSM_MultiSMSMessage *SMS, + GSM_Coding_Type Coding, + char *Buffer, + int BufferLen, + bool UDH, + int *UsedText, + int *CopiedText, + int *CopiedSMSText) +{ + int FreeText,FreeBytes,Copy,i,j; + + dbgprintf("Checking used\n"); + GSM_Find_Free_Used_SMS2(Coding,SMS->SMS[SMS->Number], UsedText, &FreeText, &FreeBytes); + + if (UDH) { + dbgprintf("Adding UDH\n"); + if (FreeBytes - BufferLen <= 0) { + dbgprintf("Going to the new SMS\n"); + SMS->Number++; + GSM_Find_Free_Used_SMS2(Coding,SMS->SMS[SMS->Number], UsedText, &FreeText, &FreeBytes); + } + if (SMS->SMS[SMS->Number].UDH.Length == 0) { + SMS->SMS[SMS->Number].UDH.Length = 1; + SMS->SMS[SMS->Number].UDH.Text[0] = 0x00; + } + memcpy(SMS->SMS[SMS->Number].UDH.Text+SMS->SMS[SMS->Number].UDH.Length,Buffer,BufferLen); + SMS->SMS[SMS->Number].UDH.Length += BufferLen; + SMS->SMS[SMS->Number].UDH.Text[0] += BufferLen; + SMS->SMS[SMS->Number].UDH.Type = UDH_UserUDH; + dbgprintf("UDH added %i\n",BufferLen); + } else { + dbgprintf("Adding text\n"); + if (FreeText == 0) { + dbgprintf("Going to the new SMS\n"); + SMS->Number++; + GSM_Find_Free_Used_SMS2(Coding,SMS->SMS[SMS->Number], UsedText, &FreeText, &FreeBytes); + } + + Copy = FreeText; + dbgprintf("copy %i\n",Copy); + if (BufferLen < Copy) Copy = BufferLen; + dbgprintf("copy %i\n",Copy); + + switch (Coding) { + case SMS_Coding_Default: + FindDefaultAlphabetLen(Buffer,&i,&j,FreeText); + dbgprintf("def length %i %i\n",i,j); + SMS->SMS[SMS->Number].Text[UnicodeLength(SMS->SMS[SMS->Number].Text)*2+i*2] = 0; + SMS->SMS[SMS->Number].Text[UnicodeLength(SMS->SMS[SMS->Number].Text)*2+i*2+1] = 0; + memcpy(SMS->SMS[SMS->Number].Text+UnicodeLength(SMS->SMS[SMS->Number].Text)*2,Buffer,i*2); + *CopiedText = i; + *CopiedSMSText = j; + SMS->SMS[SMS->Number].Length += i; + break; + case SMS_Coding_Unicode: + SMS->SMS[SMS->Number].Text[UnicodeLength(SMS->SMS[SMS->Number].Text)*2+Copy*2] = 0; + SMS->SMS[SMS->Number].Text[UnicodeLength(SMS->SMS[SMS->Number].Text)*2+Copy*2+1] = 0; + memcpy(SMS->SMS[SMS->Number].Text+UnicodeLength(SMS->SMS[SMS->Number].Text)*2,Buffer,Copy*2); + *CopiedText = *CopiedSMSText = Copy; + SMS->SMS[SMS->Number].Length += Copy; + break; + case SMS_Coding_8bit: + memcpy(SMS->SMS[SMS->Number].Text+SMS->SMS[SMS->Number].Length,Buffer,Copy); + SMS->SMS[SMS->Number].Length += Copy; + *CopiedText = *CopiedSMSText = Copy; + break; + } + dbgprintf("Text added\n"); + } + + dbgprintf("Checking on the end\n"); + GSM_Find_Free_Used_SMS2(Coding,SMS->SMS[SMS->Number], UsedText, &FreeText, &FreeBytes); + + return ERR_NONE; +} + +void GSM_MakeMultiPartSMS(GSM_MultiSMSMessage *SMS, + unsigned char *MessageBuffer, + int MessageLength, + GSM_UDH UDHType, + GSM_Coding_Type Coding, + int Class, + unsigned char ReplaceMessage) +{ + int j,Len,UsedText,CopiedText,CopiedSMSText; + unsigned char UDHID; + GSM_DateTime Date; + + Len = 0; + while(1) { + GSM_SetDefaultSMSData(&SMS->SMS[SMS->Number]); + SMS->SMS[SMS->Number].Class = Class; + SMS->SMS[SMS->Number].Coding = Coding; + + SMS->SMS[SMS->Number].UDH.Type = UDHType; + GSM_EncodeUDHHeader(&SMS->SMS[SMS->Number].UDH); + + if (Coding == SMS_Coding_8bit) { + GSM_AddSMS_Text_UDH(SMS,Coding,MessageBuffer+Len,MessageLength - Len,false,&UsedText,&CopiedText,&CopiedSMSText); + } else { + GSM_AddSMS_Text_UDH(SMS,Coding,MessageBuffer+Len*2,MessageLength - Len,false,&UsedText,&CopiedText,&CopiedSMSText); + } + Len += CopiedText; + dbgprintf("%i %i\n",Len,MessageLength); + if (Len == MessageLength) break; + if (SMS->Number == MAX_MULTI_SMS) break; + SMS->Number++; + } + + SMS->Number++; + + UDHID = GSM_MakeSMSIDFromTime(); + GSM_GetCurrentDateTime (&Date); + for (j=0;j<SMS->Number;j++) { + SMS->SMS[j].UDH.Type = UDHType; + SMS->SMS[j].UDH.ID8bit = UDHID; + SMS->SMS[j].UDH.ID16bit = UDHID + 256 * Date.Hour; + SMS->SMS[j].UDH.PartNumber = j+1; + SMS->SMS[j].UDH.AllParts = SMS->Number; + GSM_EncodeUDHHeader(&SMS->SMS[j].UDH); + } + if (SMS->Number == 1) SMS->SMS[0].ReplaceMessage = ReplaceMessage; +} + +/* Calculates number of SMS and number of left chars in SMS */ +void GSM_SMSCounter(int MessageLength, + unsigned char *MessageBuffer, + GSM_UDH UDHType, + GSM_Coding_Type Coding, + int *SMSNum, + int *CharsLeft) +{ + int UsedText,FreeBytes; + GSM_MultiSMSMessage MultiSMS; + + MultiSMS.Number = 0; + GSM_MakeMultiPartSMS(&MultiSMS,MessageBuffer,MessageLength,UDHType,Coding,-1,false); + GSM_Find_Free_Used_SMS2(Coding,MultiSMS.SMS[MultiSMS.Number-1], &UsedText, CharsLeft, &FreeBytes); + *SMSNum = MultiSMS.Number; +} + +/* Nokia Smart Messaging 3.0 */ +static void GSM_EncodeSMS30MultiPartSMS(GSM_MultiPartSMSInfo *Info, + char *Buffer, int *Length) +{ + int len; + + /*SM version. Here 3.0*/ + Buffer[(*Length)++] = 0x30; + + if (Info->Entries[0].ID == SMS_NokiaProfileLong) { + if (Info->Entries[0].Buffer != NULL) { + if (Info->Entries[0].Buffer[0]!=0x00 || Info->Entries[0].Buffer[1]!=0x00) { + Buffer[(*Length)++] = SM30_PROFILENAME; + Buffer[(*Length)++] = 0x00; + Buffer[(*Length)++] = 2*UnicodeLength(Info->Entries[0].Buffer); + CopyUnicodeString(Buffer+(*Length),Info->Entries[0].Buffer); + *Length = *Length + 2*UnicodeLength(Info->Entries[0].Buffer); + } + } + if (Info->Entries[0].Ringtone != NULL) { + Buffer[(*Length)++] = SM30_RINGTONE; + /* Length for this part later will be changed */ + Buffer[(*Length)++] = 0x01; + Buffer[(*Length)++] = 0x00; + /* Smart Messaging 3.0 says: 16*9=144 bytes, + * but on 3310 4.02 it was possible to save about 196 chars + * (without cutting) */ + len = 196; + Info->Entries[0].RingtoneNotes=GSM_EncodeNokiaRTTLRingtone(*Info->Entries[0].Ringtone,Buffer+(*Length),&len); + Buffer[(*Length)-2] = len / 256; + Buffer[(*Length)-1] = len % 256; + *Length = *Length + len; + } + } + if (Info->Entries[0].Bitmap != NULL) { + if (Info->Entries[0].ID == SMS_NokiaPictureImageLong) { + Buffer[(*Length)++] = SM30_OTA; + } else { + Buffer[(*Length)++] = SM30_SCREENSAVER; + } + Buffer[(*Length)++] = 0x01; + Buffer[(*Length)++] = 0x00; + NOKIA_CopyBitmap(GSM_NokiaPictureImage, &Info->Entries[0].Bitmap->Bitmap[0], Buffer, Length); + if (Info->Entries[0].Bitmap->Bitmap[0].Text[0]!=0 || Info->Entries[0].Bitmap->Bitmap[0].Text[1]!=0) { + if (Info->UnicodeCoding) { + Buffer[(*Length)++] = SM30_UNICODETEXT; + /* Length for text part */ + Buffer[(*Length)++] = 0x00; + Buffer[(*Length)++] = UnicodeLength(Info->Entries[0].Bitmap->Bitmap[0].Text)*2; + memcpy(Buffer+(*Length),Info->Entries[0].Bitmap->Bitmap[0].Text,UnicodeLength(Info->Entries[0].Bitmap->Bitmap[0].Text)*2); + *Length = *Length + UnicodeLength(Info->Entries[0].Bitmap->Bitmap[0].Text)*2; + } else { + /*ID for ISO-8859-1 text*/ + Buffer[(*Length)++] = SM30_ISOTEXT; + Buffer[(*Length)++] = 0x00; + Buffer[(*Length)++] = UnicodeLength(Info->Entries[0].Bitmap->Bitmap[0].Text); + memcpy(Buffer+(*Length),DecodeUnicodeString(Info->Entries[0].Bitmap->Bitmap[0].Text),UnicodeLength(Info->Entries[0].Bitmap->Bitmap[0].Text)); + *Length = *Length +UnicodeLength(Info->Entries[0].Bitmap->Bitmap[0].Text); + } + } + } +} + +/* Alcatel docs from www.alcatel.com/wap/ahead */ +GSM_Error GSM_EncodeAlcatelMultiPartSMS(GSM_MultiSMSMessage *SMS, + unsigned char *Data, + int Len, + unsigned char *Name, + int Type) +{ + unsigned char buff[100],UDHID; + int p,i; + GSM_UDHHeader MyUDH; + + for (i=0;i<MAX_MULTI_SMS;i++) { + GSM_SetDefaultSMSData(&SMS->SMS[i]); + SMS->SMS[i].UDH.Type = UDH_UserUDH; + SMS->SMS[i].UDH.Text[1] = 0x80; /* Alcatel */ + p = UnicodeLength(Name); + EncodeDefault(buff, Name, &p, true, NULL); + SMS->SMS[i].UDH.Text[2] = GSM_PackSevenBitsToEight(0, buff, SMS->SMS[i].UDH.Text+3, p) + 4; + SMS->SMS[i].UDH.Text[3] = GSM_PackSevenBitsToEight(0, buff, SMS->SMS[i].UDH.Text+3, p); + SMS->SMS[i].UDH.Text[4] = Type; + SMS->SMS[i].UDH.Text[5] = Len / 256; + SMS->SMS[i].UDH.Text[6] = Len % 256; + SMS->SMS[i].UDH.Text[0] = 6 + SMS->SMS[i].UDH.Text[3]; + SMS->SMS[i].UDH.Length = SMS->SMS[i].UDH.Text[0] + 1; + + if (Len > 140 - SMS->SMS[i].UDH.Length) { + MyUDH.Type = UDH_ConcatenatedMessages; + GSM_EncodeUDHHeader(&MyUDH); + + memcpy(SMS->SMS[i].UDH.Text+SMS->SMS[i].UDH.Length,MyUDH.Text+1,MyUDH.Length-1); + SMS->SMS[i].UDH.Text[0] += MyUDH.Length-1; + SMS->SMS[i].UDH.Length += MyUDH.Length-1; + } + + SMS->SMS[i].Coding = SMS_Coding_8bit; + SMS->SMS[i].Class = 1; + } + + p = 0; + while (p != Len) { + i = 140-SMS->SMS[SMS->Number].UDH.Length; + if (Len - p < i) i = Len - p; + memcpy(SMS->SMS[SMS->Number].Text,Data+p,i); + p += i; + SMS->SMS[SMS->Number].Length = i; + SMS->Number++; + + } + + /* Linked sms UDH */ + if (SMS->Number != 1) { + UDHID = GSM_MakeSMSIDFromTime(); + for (i=0;i<SMS->Number;i++) { + SMS->SMS[i].UDH.Text[SMS->SMS[i].UDH.Length-3] = UDHID; + SMS->SMS[i].UDH.Text[SMS->SMS[i].UDH.Length-2] = SMS->Number; + SMS->SMS[i].UDH.Text[SMS->SMS[i].UDH.Length-1] = i+1; + } + } + + return ERR_NONE; +} + +/* Alcatel docs from www.alcatel.com/wap/ahead and other */ +GSM_Error GSM_EncodeMultiPartSMS(GSM_MultiPartSMSInfo *Info, + GSM_MultiSMSMessage *SMS) +{ + unsigned char Buffer[GSM_MAX_SMS_LENGTH*2*MAX_MULTI_SMS]; + unsigned char Buffer2[GSM_MAX_SMS_LENGTH*2*MAX_MULTI_SMS]; + int Length = 0,smslen,i, Class = -1, j,p; + GSM_Error error; + GSM_Coding_Type Coding = SMS_Coding_8bit; + GSM_UDH UDH = UDH_NoUDH; + GSM_UDHHeader UDHHeader; + bool EMS = false; + int textnum = 0; + + SMS->Number = 0; + + if (Info->Entries[0].ID == SMS_AlcatelSMSTemplateName) { + Buffer[Length++] = 0x00; //number of elements + for (i=1;i<Info->EntriesNum;i++) { + switch (Info->Entries[i].ID) { + case SMS_EMSSound10: + case SMS_EMSSound12: + case SMS_EMSSonyEricssonSound: + case SMS_EMSSound10Long: + case SMS_EMSSound12Long: + case SMS_EMSSonyEricssonSoundLong: + case SMS_EMSVariableBitmap: + case SMS_EMSAnimation: + case SMS_EMSVariableBitmapLong: + break; + case SMS_EMSPredefinedSound: + Buffer[0]++; + Buffer[Length++] = 0x01; //type of data + Buffer[Length++] = 1 % 256; //len + Buffer[Length++] = 1 / 256; //len + Buffer[Length++] = Info->Entries[i].Number; + break; + case SMS_EMSPredefinedAnimation: + Buffer[0]++; + Buffer[Length++] = 0x02; //type of data + Buffer[Length++] = 1 % 256; //len + Buffer[Length++] = 1 / 256; //len + Buffer[Length++] = Info->Entries[i].Number; + break; + case SMS_ConcatenatedTextLong: + Buffer[0]++; + p = UnicodeLength(Info->Entries[i].Buffer); + EncodeDefault(Buffer2, Info->Entries[i].Buffer, &p, true, NULL); + Buffer[Length++] = 0x00; //type of data + Length = Length + 2; + smslen = GSM_PackSevenBitsToEight(0, Buffer2, Buffer+Length, p); + Buffer[Length-2] = smslen % 256; //len + Buffer[Length-1] = smslen / 256; //len + Length = Length + smslen; + break; + default: + return ERR_UNKNOWN; + } + } + Buffer[0] = Buffer[0] * 2; + return GSM_EncodeAlcatelMultiPartSMS(SMS,Buffer,Length,Info->Entries[0].Buffer,ALCATELTDD_SMSTEMPLATE); + } + + for (i=0;i<Info->EntriesNum;i++) { + switch (Info->Entries[i].ID) { + case SMS_EMSPredefinedAnimation: + case SMS_EMSPredefinedSound: + case SMS_EMSSound10: + case SMS_EMSSound12: + case SMS_EMSSonyEricssonSound: + case SMS_EMSSound10Long: + case SMS_EMSSound12Long: + case SMS_EMSSonyEricssonSoundLong: + case SMS_EMSFixedBitmap: + case SMS_EMSVariableBitmap: + case SMS_EMSAnimation: + case SMS_EMSVariableBitmapLong: + EMS = true; + break; + case SMS_ConcatenatedTextLong: + case SMS_ConcatenatedTextLong16bit: + + /* This covers situation, when somebody will call function + * with two or more SMS_Concatenated.... entries only. + * It will be still only linked sms, but functions below + * will pack only first entry according to own limits. + * We redirect to EMS functions, because they are more generic + * here and will handle it correctly and produce linked sms + * from all entries + */ + textnum ++; + if (textnum > 1) EMS = true; + + if (Info->Entries[i].Left || Info->Entries[i].Right || + Info->Entries[i].Center || Info->Entries[i].Large || + Info->Entries[i].Small || Info->Entries[i].Bold || + Info->Entries[i].Italic || Info->Entries[i].Underlined || + Info->Entries[i].Strikethrough) { + EMS = true; + } + default: + break; + } + if (EMS) break; + } + if (EMS) { + error=GSM_EncodeEMSMultiPartSMS(Info,SMS,UDH_NoUDH); + if (error != ERR_NONE) return error; + if (SMS->Number != 1) { + SMS->Number = 0; + for (i=0;i<Info->EntriesNum;i++) { + if (Info->Entries[i].ID == SMS_ConcatenatedTextLong16bit) { + return GSM_EncodeEMSMultiPartSMS(Info,SMS,UDH_ConcatenatedMessages); + } + } + return GSM_EncodeEMSMultiPartSMS(Info,SMS,UDH_ConcatenatedMessages16bit); + } + return error; + } + + if (Info->EntriesNum != 1) return ERR_UNKNOWN; + + switch (Info->Entries[0].ID) { + case SMS_AlcatelMonoBitmapLong: + Buffer[0] = Info->Entries[0].Bitmap->Bitmap[0].BitmapWidth; + Buffer[1] = Info->Entries[0].Bitmap->Bitmap[0].BitmapHeight; + PHONE_EncodeBitmap(GSM_AlcatelBMMIPicture, Buffer+2, &Info->Entries[0].Bitmap->Bitmap[0]); + Length = PHONE_GetBitmapSize(GSM_AlcatelBMMIPicture,Info->Entries[0].Bitmap->Bitmap[0].BitmapWidth,Info->Entries[0].Bitmap->Bitmap[0].BitmapHeight)+2; + return GSM_EncodeAlcatelMultiPartSMS(SMS,Buffer,Length,Info->Entries[0].Bitmap->Bitmap[0].Text,ALCATELTDD_PICTURE); + case SMS_AlcatelMonoAnimationLong: + /* Number of sequence words */ + Buffer[0] = (Info->Entries[0].Bitmap->Number+1) % 256; + Buffer[1] = (Info->Entries[0].Bitmap->Number+1) / 256; + /* Picture display time 1 second (1 = 100ms) */ + Buffer[2] = 10 % 256; + Buffer[3] = 10 / 256 + 0xF0; + + Length = 4; + j = 0; + + /* Offsets to bitmaps */ + for (i=0;i<Info->Entries[0].Bitmap->Number;i++) { + Buffer[Length++] = (4+j+Info->Entries[0].Bitmap->Number*2) % 256; + Buffer[Length++] = (4+j+Info->Entries[0].Bitmap->Number*2) / 256; + j += PHONE_GetBitmapSize(GSM_AlcatelBMMIPicture,Info->Entries[0].Bitmap->Bitmap[i].BitmapWidth,Info->Entries[0].Bitmap->Bitmap[i].BitmapHeight)+2; + } + + /* Bitmaps */ + for (i=0;i<Info->Entries[0].Bitmap->Number;i++) { + Buffer[Length++] = Info->Entries[0].Bitmap->Bitmap[i].BitmapWidth; + Buffer[Length++] = Info->Entries[0].Bitmap->Bitmap[i].BitmapHeight; + PHONE_EncodeBitmap(GSM_AlcatelBMMIPicture, Buffer+Length, &Info->Entries[0].Bitmap->Bitmap[i]); + Length += PHONE_GetBitmapSize(GSM_AlcatelBMMIPicture,Info->Entries[0].Bitmap->Bitmap[i].BitmapWidth,Info->Entries[0].Bitmap->Bitmap[i].BitmapHeight); + } + return GSM_EncodeAlcatelMultiPartSMS(SMS,Buffer,Length,Info->Entries[0].Bitmap->Bitmap[0].Text,ALCATELTDD_ANIMATION); + case SMS_MMSIndicatorLong: + Class = 1; + UDH = UDH_MMSIndicatorLong; + GSM_EncodeMMSIndicatorSMSText(Buffer,&Length,*Info->Entries[0].MMSIndicator); + break; + case SMS_NokiaRingtoneLong: + case SMS_NokiaRingtone: + UDH = UDH_NokiaRingtone; + Class = 1; + /* 7 = length of UDH_NokiaRingtone UDH header */ + Length = GSM_MAX_8BIT_SMS_LENGTH-7; + Info->Entries[0].RingtoneNotes = GSM_EncodeNokiaRTTLRingtone(*Info->Entries[0].Ringtone,Buffer,&Length); + if (Info->Entries[0].ID == SMS_NokiaRingtone) break; + if (Info->Entries[0].RingtoneNotes != Info->Entries[0].Ringtone->NoteTone.NrCommands) { + UDH = UDH_NokiaRingtoneLong; + Length = (GSM_MAX_8BIT_SMS_LENGTH-12)*3; + Info->Entries[0].RingtoneNotes = GSM_EncodeNokiaRTTLRingtone(*Info->Entries[0].Ringtone,Buffer,&Length); + } + break; + case SMS_NokiaOperatorLogoLong: + if (Info->Entries[0].Bitmap->Bitmap[0].BitmapWidth > 72 || Info->Entries[0].Bitmap->Bitmap[0].BitmapHeight > 14) { + UDH = UDH_NokiaOperatorLogoLong; + Class = 1; + NOKIA_EncodeNetworkCode(Buffer, Info->Entries[0].Bitmap->Bitmap[0].NetworkCode); + Length = Length + 3; + NOKIA_CopyBitmap(GSM_Nokia7110OperatorLogo, &Info->Entries[0].Bitmap->Bitmap[0], Buffer, &Length); + break; + } + case SMS_NokiaOperatorLogo: + UDH = UDH_NokiaOperatorLogo; + Class = 1; + NOKIA_EncodeNetworkCode(Buffer, Info->Entries[0].Bitmap->Bitmap[0].NetworkCode); + Length = Length + 3; + NOKIA_CopyBitmap(GSM_NokiaOperatorLogo, &Info->Entries[0].Bitmap->Bitmap[0], Buffer, &Length); + break; + case SMS_NokiaCallerLogo: + UDH = UDH_NokiaCallerLogo; + Class = 1; + NOKIA_CopyBitmap(GSM_NokiaCallerLogo, &Info->Entries[0].Bitmap->Bitmap[0], Buffer, &Length); + break; + case SMS_NokiaProfileLong: + case SMS_NokiaPictureImageLong: + case SMS_NokiaScreenSaverLong: + Class = 1; + UDH = UDH_NokiaProfileLong; + GSM_EncodeSMS30MultiPartSMS(Info,Buffer,&Length); + break; + case SMS_NokiaWAPBookmarkLong: + Class = 1; + NOKIA_EncodeWAPBookmarkSMSText(Buffer,&Length,Info->Entries[0].Bookmark); + /* 7 = length of UDH_NokiaWAP UDH header */ + if (Length>(GSM_MAX_8BIT_SMS_LENGTH-7)) { + UDH=UDH_NokiaWAPLong; + } else { + UDH=UDH_NokiaWAP; + } + break; + case SMS_NokiaWAPSettingsLong: + Class = 1; + UDH = UDH_NokiaWAPLong; + NOKIA_EncodeWAPMMSSettingsSMSText(Buffer,&Length,Info->Entries[0].Settings,false); + break; + case SMS_NokiaMMSSettingsLong: + Class = 1; + UDH = UDH_NokiaWAPLong; + NOKIA_EncodeWAPMMSSettingsSMSText(Buffer,&Length,Info->Entries[0].Settings,true); + break; + case SMS_NokiaVCARD10Long: + GSM_EncodeVCARD(Buffer,&Length,Info->Entries[0].Phonebook,true,Nokia_VCard10); + /* is 1 SMS ? 8 = length of ..SCKE2 */ + if (Length<=GSM_MAX_SMS_LENGTH-8) { + sprintf(Buffer,"//SCKE2 "); + Length = 8; + GSM_EncodeVCARD(Buffer,&Length,Info->Entries[0].Phonebook,true,Nokia_VCard10); + } else { + /* FIXME: It wasn't checked */ + UDH = UDH_NokiaPhonebookLong; + } + Coding = SMS_Coding_Default; + memcpy(Buffer2,Buffer,Length); + EncodeUnicode(Buffer,Buffer2,Length); + break; + case SMS_NokiaVCARD21Long: + GSM_EncodeVCARD(Buffer,&Length,Info->Entries[0].Phonebook,true,Nokia_VCard21); + /* Is 1 SMS ? 12 = length of ..SCKL23F4 */ + if (Length<=GSM_MAX_SMS_LENGTH-12) { + sprintf(Buffer,"//SCKL23F4%c%c",13,10); + Length = 12; + GSM_EncodeVCARD(Buffer,&Length,Info->Entries[0].Phonebook,true,Nokia_VCard21); + } else { + UDH = UDH_NokiaPhonebookLong; + /* Here can be also 8 bit coding */ + } + Coding = SMS_Coding_Default; + memcpy(Buffer2,Buffer,Length); + EncodeUnicode(Buffer,Buffer2,Length); + break; + case SMS_VCARD10Long: + GSM_EncodeVCARD(Buffer,&Length,Info->Entries[0].Phonebook,true,Nokia_VCard10); + if (Length>GSM_MAX_SMS_LENGTH) UDH = UDH_ConcatenatedMessages; + Coding = SMS_Coding_Default; + memcpy(Buffer2,Buffer,Length); + EncodeUnicode(Buffer,Buffer2,Length); + break; + case SMS_VCARD21Long: + GSM_EncodeVCARD(Buffer,&Length,Info->Entries[0].Phonebook,true,Nokia_VCard21); + if (Length>GSM_MAX_SMS_LENGTH) UDH = UDH_ConcatenatedMessages; + Coding = SMS_Coding_Default; + memcpy(Buffer2,Buffer,Length); + EncodeUnicode(Buffer,Buffer2,Length); + break; + case SMS_NokiaVCALENDAR10Long: + error=GSM_EncodeVCALENDAR(Buffer,&Length,Info->Entries[0].Calendar,true,Nokia_VCalendar); + if (error != ERR_NONE) return error; + /* Is 1 SMS ? 8 = length of ..SCKE4 */ + if (Length<=GSM_MAX_SMS_LENGTH-8) { + sprintf(Buffer,"//SCKE4 "); + Length = 8; + GSM_EncodeVCALENDAR(Buffer,&Length,Info->Entries[0].Calendar,true,Nokia_VCalendar); + } else { + UDH = UDH_NokiaCalendarLong; + /* can be here 8 bit coding ? */ + } + Coding = SMS_Coding_Default; + memcpy(Buffer2,Buffer,Length); + EncodeUnicode(Buffer,Buffer2,Length); + break; + case SMS_NokiaVTODOLong: + error=GSM_EncodeVTODO(Buffer,&Length,Info->Entries[0].ToDo,true,Nokia_VToDo); + if (error != ERR_NONE) return error; + UDH = UDH_NokiaCalendarLong; + Coding = SMS_Coding_Default; + memcpy(Buffer2,Buffer,Length); + EncodeUnicode(Buffer,Buffer2,Length); + break; + case SMS_DisableVoice: + case SMS_DisableFax: + case SMS_DisableEmail: + case SMS_EnableVoice: + case SMS_EnableFax: + case SMS_EnableEmail: + case SMS_VoidSMS: + case SMS_Text: + Class = Info->Class; + switch (Info->Entries[0].ID) { + case SMS_DisableVoice : UDH = UDH_DisableVoice; break; + case SMS_DisableFax : UDH = UDH_DisableFax; break; + case SMS_DisableEmail : UDH = UDH_DisableEmail; break; + case SMS_EnableVoice : UDH = UDH_EnableVoice; break; + case SMS_EnableFax : UDH = UDH_EnableFax; break; + case SMS_EnableEmail : UDH = UDH_EnableEmail; break; + case SMS_VoidSMS : UDH = UDH_VoidSMS; break; + case SMS_Text : UDH = UDH_NoUDH; break; + default : break; + } + UDHHeader.Type = UDH; + GSM_EncodeUDHHeader(&UDHHeader); + memcpy(Buffer,Info->Entries[0].Buffer,UnicodeLength(Info->Entries[0].Buffer)*2+2); + if (Info->UnicodeCoding) { + Coding = SMS_Coding_Unicode; + Length = UnicodeLength(Info->Entries[0].Buffer); + if (Length>(140-UDHHeader.Length)/2) Length = (140-UDHHeader.Length)/2; + } else { + Coding = SMS_Coding_Default; + FindDefaultAlphabetLen(Info->Entries[0].Buffer,&Length,&smslen,(GSM_MAX_8BIT_SMS_LENGTH-UDHHeader.Length)*8/7); + } + break; + case SMS_ConcatenatedAutoTextLong: + case SMS_ConcatenatedAutoTextLong16bit: + smslen = UnicodeLength(Info->Entries[0].Buffer); + memcpy(Buffer,Info->Entries[0].Buffer,smslen*2); + EncodeDefault(Buffer2, Buffer, &smslen, true, NULL); + DecodeDefault(Buffer, Buffer2, smslen, true, NULL); +#ifdef DEBUG + if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) { + dbgprintf("Info->Entries[0].Buffer:\n"); + DumpMessage(di.df, di.dl, Info->Entries[0].Buffer, UnicodeLength(Info->Entries[0].Buffer)*2); + dbgprintf("Buffer:\n"); + DumpMessage(di.df, di.dl, Buffer, UnicodeLength(Buffer)*2); + } +#endif + Info->UnicodeCoding = false; + for (smslen=0;smslen<(int)(UnicodeLength(Info->Entries[0].Buffer)*2);smslen++) { + if (Info->Entries[0].Buffer[smslen] != Buffer[smslen]) { + Info->UnicodeCoding = true; + dbgprintf("Setting to Unicode %i\n",smslen); + break; + } + } + /* No break here - we go to the SMS_ConcatenatedTextLong */ + case SMS_ConcatenatedTextLong: + case SMS_ConcatenatedTextLong16bit: + Class = Info->Class; + memcpy(Buffer,Info->Entries[0].Buffer,UnicodeLength(Info->Entries[0].Buffer)*2+2); + UDH = UDH_NoUDH; + if (Info->UnicodeCoding) { + Coding = SMS_Coding_Unicode; + Length = UnicodeLength(Info->Entries[0].Buffer); + if (Info->Entries[0].ID == SMS_ConcatenatedTextLong16bit || + Info->Entries[0].ID == SMS_ConcatenatedAutoTextLong16bit) { + if (Length>70) UDH=UDH_ConcatenatedMessages16bit; + } else { + if (Length>70) UDH=UDH_ConcatenatedMessages; + } + } else { + Coding = SMS_Coding_Default; + FindDefaultAlphabetLen(Info->Entries[0].Buffer,&Length,&smslen,5000); + if (Info->Entries[0].ID == SMS_ConcatenatedTextLong16bit || + Info->Entries[0].ID == SMS_ConcatenatedAutoTextLong16bit) { + if (smslen>GSM_MAX_SMS_LENGTH) UDH=UDH_ConcatenatedMessages16bit; + } else { + if (smslen>GSM_MAX_SMS_LENGTH) UDH=UDH_ConcatenatedMessages; + } + } + default: + break; + } + GSM_MakeMultiPartSMS(SMS,Buffer,Length,UDH,Coding,Class,Info->ReplaceMessage); + return ERR_NONE; +} + +void GSM_ClearMultiPartSMSInfo(GSM_MultiPartSMSInfo *Info) +{ + int i; + + for (i=0;i<MAX_MULTI_SMS;i++) { + Info->Entries[i].Number = 0; + Info->Entries[i].Ringtone = NULL; + Info->Entries[i].Bitmap = NULL; + Info->Entries[i].Bookmark = NULL; + Info->Entries[i].Settings = NULL; + Info->Entries[i].MMSIndicator = NULL; + Info->Entries[i].Phonebook = NULL; + Info->Entries[i].Calendar = NULL; + Info->Entries[i].ToDo = NULL; + Info->Entries[i].Protected = false; + + Info->Entries[i].Buffer = NULL; + Info->Entries[i].Left = false; + Info->Entries[i].Right = false; + Info->Entries[i].Center = false; + Info->Entries[i].Large = false; + Info->Entries[i].Small = false; + Info->Entries[i].Bold = false; + Info->Entries[i].Italic = false; + Info->Entries[i].Underlined = false; + Info->Entries[i].Strikethrough = false; + + Info->Entries[i].RingtoneNotes = 0; + } + Info->Unknown = false; + Info->EntriesNum = 0; + Info->Class = -1; + Info->ReplaceMessage = 0; + Info->UnicodeCoding = false; +} + +void GSM_FreeMultiPartSMSInfo(GSM_MultiPartSMSInfo *Info) +{ + int i; + + for (i=0;i<MAX_MULTI_SMS;i++) { + free(Info->Entries[i].Ringtone); + Info->Entries[i].Ringtone = NULL; + free(Info->Entries[i].Bitmap); + Info->Entries[i].Bitmap = NULL; + free(Info->Entries[i].Bookmark); + Info->Entries[i].Bookmark = NULL; + free(Info->Entries[i].Settings); + Info->Entries[i].Settings = NULL; + free(Info->Entries[i].MMSIndicator); + Info->Entries[i].MMSIndicator = NULL; + free(Info->Entries[i].Phonebook); + Info->Entries[i].Phonebook = NULL; + free(Info->Entries[i].Calendar); + Info->Entries[i].Calendar = NULL; + free(Info->Entries[i].ToDo); + Info->Entries[i].ToDo = NULL; + free(Info->Entries[i].Buffer); + Info->Entries[i].Buffer = NULL; + } +} + +/* ----------------- Joining SMS from parts -------------------------------- */ + +bool GSM_DecodeMultiPartSMS(GSM_MultiPartSMSInfo *Info, + GSM_MultiSMSMessage *SMS, + bool ems) +{ + int i, Length = 0; + char Buffer[GSM_MAX_SMS_LENGTH*2*MAX_MULTI_SMS]; + bool emsexist = false; + + GSM_ClearMultiPartSMSInfo(Info); + if (ems) { + emsexist = true; + for (i=0;i<SMS->Number;i++) { + if (SMS->SMS[i].UDH.Type != UDH_ConcatenatedMessages && + SMS->SMS[i].UDH.Type != UDH_ConcatenatedMessages16bit && + SMS->SMS[i].UDH.Type != UDH_UserUDH) { + emsexist = false; + break; + } + } + } + + /* EMS decoding */ + if (emsexist) return GSM_DecodeEMSMultiPartSMS(Info,SMS); + + /* Smart Messaging decoding */ + if (SMS->SMS[0].UDH.Type == UDH_NokiaRingtone && SMS->Number == 1) { + Info->Entries[0].Ringtone = (GSM_Ringtone *)malloc(sizeof(GSM_Ringtone)); + if (Info->Entries[0].Ringtone == NULL) return false; + if (GSM_DecodeNokiaRTTLRingtone(Info->Entries[0].Ringtone, SMS->SMS[0].Text, SMS->SMS[0].Length)==ERR_NONE) { + Info->Entries[0].ID = SMS_NokiaRingtone; + Info->EntriesNum = 1; + return true; + } + } + if (SMS->SMS[0].UDH.Type == UDH_NokiaCallerLogo && SMS->Number == 1) { + Info->Entries[0].Bitmap = (GSM_MultiBitmap *)malloc(sizeof(GSM_MultiBitmap)); + if (Info->Entries[0].Bitmap == NULL) return false; + Info->Entries[0].Bitmap->Number = 1; + PHONE_DecodeBitmap(GSM_NokiaCallerLogo, SMS->SMS[0].Text+4, &Info->Entries[0].Bitmap->Bitmap[0]); +#ifdef DEBUG + if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) GSM_PrintBitmap(di.df,&Info->Entries[0].Bitmap->Bitmap[0]); +#endif + Info->Entries[0].ID = SMS_NokiaCallerLogo; + Info->EntriesNum = 1; + return true; + } + if (SMS->SMS[0].UDH.Type == UDH_NokiaOperatorLogo && SMS->Number == 1) { + Info->Entries[0].Bitmap = (GSM_MultiBitmap *)malloc(sizeof(GSM_MultiBitmap)); + if (Info->Entries[0].Bitmap == NULL) return false; + Info->Entries[0].Bitmap->Number = 1; + PHONE_DecodeBitmap(GSM_NokiaOperatorLogo, SMS->SMS[0].Text+7, &Info->Entries[0].Bitmap->Bitmap[0]); + NOKIA_DecodeNetworkCode(SMS->SMS[0].Text, Info->Entries[0].Bitmap->Bitmap[0].NetworkCode); +#ifdef DEBUG + if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) GSM_PrintBitmap(di.df,&Info->Entries[0].Bitmap->Bitmap[0]); +#endif + Info->Entries[0].ID = SMS_NokiaOperatorLogo; + Info->EntriesNum = 1; + return true; + } + if (SMS->SMS[0].UDH.Type == UDH_NokiaProfileLong) { + for (i=0;i<SMS->Number;i++) { + if (SMS->SMS[i].UDH.Type != UDH_NokiaProfileLong || + SMS->SMS[i].UDH.Text[11] != i+1 || + SMS->SMS[i].UDH.Text[10] != SMS->Number) { + return false; + } + memcpy(Buffer+Length,SMS->SMS[i].Text,SMS->SMS[i].Length); + Length = Length + SMS->SMS[i].Length; + } + Info->EntriesNum = 1; + Info->Entries[0].ID = SMS_NokiaPictureImageLong; + Info->Entries[0].Bitmap = (GSM_MultiBitmap *)malloc(sizeof(GSM_MultiBitmap)); + if (Info->Entries[0].Bitmap == NULL) return false; + Info->Entries[0].Bitmap->Number = 1; + Info->Entries[0].Bitmap->Bitmap[0].Text[0] = 0; + Info->Entries[0].Bitmap->Bitmap[0].Text[1] = 0; + i=1; + while (i!=Length) { + switch (Buffer[i]) { + case SM30_ISOTEXT: + dbgprintf("ISO 8859-2 text\n"); + Info->Unknown = true; + break; + case SM30_UNICODETEXT: + dbgprintf("Unicode text\n"); + memcpy(Info->Entries[0].Bitmap->Bitmap[0].Text,Buffer+i+3,Buffer[i+1]*256+Buffer[i+2]); + Info->Entries[0].Bitmap->Bitmap[0].Text[Buffer[i+1]*256 + Buffer[i+2]] = 0; + Info->Entries[0].Bitmap->Bitmap[0].Text[Buffer[i+1]*256 + Buffer[i+2]+ 1] = 0; + dbgprintf("Unicode Text \"%s\"\n",DecodeUnicodeString(Info->Entries[0].Bitmap->Bitmap[0].Text)); + break; + case SM30_OTA: + dbgprintf("OTA bitmap as Picture Image\n"); + PHONE_DecodeBitmap(GSM_NokiaPictureImage, Buffer + i + 7, &Info->Entries[0].Bitmap->Bitmap[0]); +#ifdef DEBUG + if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) GSM_PrintBitmap(di.df,&Info->Entries[0].Bitmap->Bitmap[0]); +#endif + break; + case SM30_RINGTONE: + dbgprintf("RTTL ringtone\n"); + Info->Unknown = true; + break; + case SM30_PROFILENAME: + dbgprintf("Profile Name\n"); + Info->Entries[0].ID = SMS_NokiaProfileLong; + Info->Unknown = true; + break; + case SM30_SCREENSAVER: + dbgprintf("OTA bitmap as Screen Saver\n"); + PHONE_DecodeBitmap(GSM_NokiaPictureImage, Buffer + i + 7, &Info->Entries[0].Bitmap->Bitmap[0]); +#ifdef DEBUG + if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) GSM_PrintBitmap(di.df,&Info->Entries[0].Bitmap->Bitmap[0]); +#endif + Info->Entries[0].ID = SMS_NokiaScreenSaverLong; + break; + } + i = i + Buffer[i+1]*256 + Buffer[i+2] + 3; + dbgprintf("%i %i\n",i,Length); + } + return true; + } + + /* Linked sms */ + if (SMS->SMS[0].UDH.Type == UDH_ConcatenatedMessages || + SMS->SMS[0].UDH.Type == UDH_ConcatenatedMessages16bit) { + Info->EntriesNum = 1; + Info->Entries[0].ID = SMS_ConcatenatedTextLong; + if (SMS->SMS[0].UDH.Type == UDH_ConcatenatedMessages16bit) { + Info->Entries[0].ID = SMS_ConcatenatedTextLong16bit; + } + + for (i=0;i<SMS->Number;i++) { + switch (SMS->SMS[i].Coding) { + case SMS_Coding_8bit: + Info->Entries[0].Buffer = realloc(Info->Entries[0].Buffer, Length + SMS->SMS[i].Length + 2); + if (Info->Entries[0].Buffer == NULL) return false; + + memcpy(Info->Entries[0].Buffer + Length, SMS->SMS[i].Text, SMS->SMS[i].Length); + Length=Length+SMS->SMS[i].Length; + break; + case SMS_Coding_Unicode: + if (Info->Entries[0].ID == SMS_ConcatenatedTextLong) { + Info->Entries[0].ID = SMS_ConcatenatedAutoTextLong; + } + if (Info->Entries[0].ID == SMS_ConcatenatedTextLong16bit) { + Info->Entries[0].ID = SMS_ConcatenatedAutoTextLong16bit; + } + case SMS_Coding_Default: + Info->Entries[0].Buffer = realloc(Info->Entries[0].Buffer, Length + UnicodeLength(SMS->SMS[i].Text)*2 + 2); + if (Info->Entries[0].Buffer == NULL) return false; + + memcpy(Info->Entries[0].Buffer+Length,SMS->SMS[i].Text,UnicodeLength(SMS->SMS[i].Text)*2); + Length=Length+UnicodeLength(SMS->SMS[i].Text)*2; + break; + } + } + Info->Entries[0].Buffer[Length] = 0; + Info->Entries[0].Buffer[Length+1] = 0; + return true; + } + + return false; +} + +GSM_Error GSM_LinkSMS(GSM_MultiSMSMessage **INPUT, GSM_MultiSMSMessage **OUTPUT, bool ems) +{ + bool *INPUTSorted, copyit; + int i,OUTPUTNum,j,z,w; + + i = 0; + while (INPUT[i] != NULL) i++; + + INPUTSorted = calloc(i, sizeof(bool)); + if (INPUTSorted == NULL) return ERR_MOREMEMORY; + + OUTPUTNum = 0; + OUTPUT[0] = NULL; + + if (ems) { + i=0; + while (INPUT[i] != NULL) { + if (INPUT[i]->SMS[0].UDH.Type == UDH_UserUDH) { + w=1; + while (w < INPUT[i]->SMS[0].UDH.Length) { + switch(INPUT[i]->SMS[0].UDH.Text[w]) { + case 0x00: + dbgprintf("Adding ID to user UDH - linked SMS with 8 bit ID\n"); + INPUT[i]->SMS[0].UDH.ID8bit = INPUT[i]->SMS[0].UDH.Text[w+2]; + INPUT[i]->SMS[0].UDH.AllParts = INPUT[i]->SMS[0].UDH.Text[w+3]; + INPUT[i]->SMS[0].UDH.PartNumber = INPUT[i]->SMS[0].UDH.Text[w+4]; + break; + case 0x08: + dbgprintf("Adding ID to user UDH - linked SMS with 16 bit ID\n"); + INPUT[i]->SMS[0].UDH.ID16bit = INPUT[i]->SMS[0].UDH.Text[w+2]*256+INPUT[i]->SMS[0].UDH.Text[w+3]; + INPUT[i]->SMS[0].UDH.AllParts = INPUT[i]->SMS[0].UDH.Text[w+4]; + INPUT[i]->SMS[0].UDH.PartNumber = INPUT[i]->SMS[0].UDH.Text[w+5]; + break; + default: + dbgprintf("Block %02x\n",INPUT[i]->SMS[0].UDH.Text[w]); + } + dbgprintf("%i %i %i %i\n", + INPUT[i]->SMS[0].UDH.ID8bit, + INPUT[i]->SMS[0].UDH.ID16bit, + INPUT[i]->SMS[0].UDH.PartNumber, + INPUT[i]->SMS[0].UDH.AllParts); + w=w+INPUT[i]->SMS[0].UDH.Text[w+1]+2; + } + } + i++; + } + } + + i=0; + while (INPUT[i]!=NULL) { + /* If this one SMS was sorted earlier, do not touch */ + if (INPUTSorted[i]) { + i++; + continue; + } + copyit = false; + /* If we have: + * - linked sms returned by phone driver + * - sms without linking + * we copy it to OUTPUT + */ + if (INPUT[i]->Number != 1 || + INPUT[i]->SMS[0].UDH.Type == UDH_NoUDH || + INPUT[i]->SMS[0].UDH.PartNumber == -1) { + copyit = true; + } + /* If we have unknown UDH, we copy it to OUTPUT */ + if (INPUT[i]->SMS[0].UDH.Type == UDH_UserUDH) { + if (!ems) copyit = true; + if (ems && INPUT[i]->SMS[0].UDH.PartNumber == -1) copyit = true; + } + if (copyit) { + OUTPUT[OUTPUTNum] = malloc(sizeof(GSM_MultiSMSMessage)); + if (OUTPUT[OUTPUTNum] == NULL) { + free(INPUTSorted); + return ERR_MOREMEMORY; + } + OUTPUT[OUTPUTNum+1] = NULL; + + memcpy(OUTPUT[OUTPUTNum],INPUT[i],sizeof(GSM_MultiSMSMessage)); + INPUTSorted[i]=true; + OUTPUTNum++; + i = 0; + continue; + } + /* We have 1'st part of linked sms. It's single. + * We will try to find other parts + */ + if (INPUT[i]->SMS[0].UDH.PartNumber == 1) { + OUTPUT[OUTPUTNum] = malloc(sizeof(GSM_MultiSMSMessage)); + if (OUTPUT[OUTPUTNum] == NULL) { + free(INPUTSorted); + return ERR_MOREMEMORY; + } + OUTPUT[OUTPUTNum+1] = NULL; + + memcpy(&OUTPUT[OUTPUTNum]->SMS[0],&INPUT[i]->SMS[0],sizeof(GSM_SMSMessage)); + OUTPUT[OUTPUTNum]->Number = 1; + INPUTSorted[i] = true; + j = 1; + /* We're searching for other parts in sequence */ + while (j!=INPUT[i]->SMS[0].UDH.AllParts) { + z=0; + while(INPUT[z]!=NULL) { + /* This was sorted earlier or is not single */ + if (INPUTSorted[z] || INPUT[z]->Number != 1) { + z++; + continue; + } + if (ems && INPUT[i]->SMS[0].UDH.Type != UDH_ConcatenatedMessages && + INPUT[i]->SMS[0].UDH.Type != UDH_ConcatenatedMessages16bit && + INPUT[i]->SMS[0].UDH.Type != UDH_UserUDH && + INPUT[z]->SMS[0].UDH.Type != UDH_ConcatenatedMessages && + INPUT[z]->SMS[0].UDH.Type != UDH_ConcatenatedMessages16bit && + INPUT[z]->SMS[0].UDH.Type != UDH_UserUDH) { + if (INPUT[z]->SMS[0].UDH.Type != INPUT[i]->SMS[0].UDH.Type) { + z++; + continue; + } + } + if (!ems && INPUT[z]->SMS[0].UDH.Type != INPUT[i]->SMS[0].UDH.Type) { + z++; + continue; + } + dbgprintf("compare %i %i %i %i %i", + j+1, + INPUT[i]->SMS[0].UDH.ID8bit, + INPUT[i]->SMS[0].UDH.ID16bit, + INPUT[i]->SMS[0].UDH.PartNumber, + INPUT[i]->SMS[0].UDH.AllParts); + dbgprintf(" %i %i %i %i\n", + INPUT[z]->SMS[0].UDH.ID8bit, + INPUT[z]->SMS[0].UDH.ID16bit, + INPUT[z]->SMS[0].UDH.PartNumber, + INPUT[z]->SMS[0].UDH.AllParts); + if (INPUT[z]->SMS[0].UDH.ID8bit != INPUT[i]->SMS[0].UDH.ID8bit || + INPUT[z]->SMS[0].UDH.ID16bit != INPUT[i]->SMS[0].UDH.ID16bit || + INPUT[z]->SMS[0].UDH.AllParts != INPUT[i]->SMS[0].UDH.AllParts || + INPUT[z]->SMS[0].UDH.PartNumber != j+1) { + z++; + continue; + } + /* For SMS_Deliver compare also SMSC and Sender number */ + if (INPUT[z]->SMS[0].PDU == SMS_Deliver && + (strcmp(DecodeUnicodeString(INPUT[z]->SMS[0].SMSC.Number),DecodeUnicodeString(INPUT[i]->SMS[0].SMSC.Number)) || + strcmp(DecodeUnicodeString(INPUT[z]->SMS[0].Number),DecodeUnicodeString(INPUT[i]->SMS[0].Number)))) { + z++; + continue; + } + /* DCT4 Outbox: SMS Deliver. Empty number and SMSC. We compare dates */ + if (INPUT[z]->SMS[0].PDU == SMS_Deliver && + UnicodeLength(INPUT[z]->SMS[0].SMSC.Number)==0 && + UnicodeLength(INPUT[z]->SMS[0].Number)==0 && + (INPUT[z]->SMS[0].DateTime.Day != INPUT[i]->SMS[0].DateTime.Day || + INPUT[z]->SMS[0].DateTime.Month != INPUT[i]->SMS[0].DateTime.Month || + INPUT[z]->SMS[0].DateTime.Year != INPUT[i]->SMS[0].DateTime.Year || + INPUT[z]->SMS[0].DateTime.Hour != INPUT[i]->SMS[0].DateTime.Hour || + INPUT[z]->SMS[0].DateTime.Minute != INPUT[i]->SMS[0].DateTime.Minute || + INPUT[z]->SMS[0].DateTime.Second != INPUT[i]->SMS[0].DateTime.Second)) { + z++; + continue; + } + /* We found correct sms. Copy it */ + memcpy(&OUTPUT[OUTPUTNum]->SMS[j],&INPUT[z]->SMS[0],sizeof(GSM_SMSMessage)); + OUTPUT[OUTPUTNum]->Number++; + INPUTSorted[z]=true; + break; + } + /* Incomplete sequence */ + if (OUTPUT[OUTPUTNum]->Number==j) { + dbgprintf("Incomplete sequence\n"); + break; + } + j++; + } + OUTPUTNum++; + i = 0; + continue; + } + /* We have some next linked sms from sequence */ + if (INPUT[i]->SMS[0].UDH.PartNumber > 1) { + j = 0; + while (INPUT[j]!=NULL) { + if (INPUTSorted[j]) { + j++; + continue; + } + /* We have some not unassigned first sms from sequence. + * We can't touch other sms from sequences + */ + if (INPUT[j]->SMS[0].UDH.PartNumber == 1) break; + j++; + } + if (INPUT[j]==NULL) { + OUTPUT[OUTPUTNum] = malloc(sizeof(GSM_MultiSMSMessage)); + if (OUTPUT[OUTPUTNum] == NULL) { + free(INPUTSorted); + return ERR_MOREMEMORY; + } + OUTPUT[OUTPUTNum+1] = NULL; + + memcpy(OUTPUT[OUTPUTNum],INPUT[i],sizeof(GSM_MultiSMSMessage)); + INPUTSorted[i]=true; + OUTPUTNum++; + i = 0; + continue; + } else i++; + } + } + free(INPUTSorted); + return ERR_NONE; +} + +/* How should editor hadle tabs in this file? Add editor commands here. + * vim: noexpandtab sw=8 ts=8 sts=8: + */ |