summaryrefslogtreecommitdiffabout
path: root/gammu/emb/common/service/sms
Side-by-side diff
Diffstat (limited to 'gammu/emb/common/service/sms') (more/less context) (ignore whitespace changes)
-rw-r--r--gammu/emb/common/service/sms/gsmems.c765
-rw-r--r--gammu/emb/common/service/sms/gsmems.h20
-rw-r--r--gammu/emb/common/service/sms/gsmmulti.c1148
-rw-r--r--gammu/emb/common/service/sms/gsmmulti.h271
-rw-r--r--gammu/emb/common/service/sms/gsmsms.c663
-rw-r--r--gammu/emb/common/service/sms/gsmsms.h492
6 files changed, 3359 insertions, 0 deletions
diff --git a/gammu/emb/common/service/sms/gsmems.c b/gammu/emb/common/service/sms/gsmems.c
new file mode 100644
index 0000000..a7e20f4
--- a/dev/null
+++ b/gammu/emb/common/service/sms/gsmems.c
@@ -0,0 +1,765 @@
+/* (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"
+
+/* EMS Developers' Guidelines from www.sonyericsson.com
+ * docs from Alcatel
+ */
+GSM_Error GSM_EncodeEMSMultiPartSMS(GSM_MultiPartSMSInfo *Info,
+ GSM_MultiSMSMessage *SMS,
+ GSM_UDH UDHType)
+{
+ unsigned char Buffer[GSM_MAX_SMS_LENGTH*2*MAX_MULTI_SMS];
+ int i,UsedText,j,Length,Width,Height,z,x,y;
+ unsigned int Len;
+ int Used,FreeText,FreeBytes,Width2,CopiedText,CopiedSMSText;
+ unsigned char UDHID;
+ GSM_Bitmap Bitmap,Bitmap2;
+ GSM_Ringtone Ring;
+ GSM_Coding_Type Coding = SMS_Coding_Default;
+ GSM_Phone_Bitmap_Types BitmapType;
+ MultiPartSMSEntry *Entry;
+ bool start;
+ GSM_DateTime Date;
+
+#ifdef DEBUG
+ if (UDHType != UDH_NoUDH) dbgprintf("linked EMS\n");
+#endif
+
+ if (Info->UnicodeCoding) Coding = SMS_Coding_Unicode;
+
+ /* Cleaning on the start */
+ for (i=0;i<MAX_MULTI_SMS;i++) {
+ GSM_SetDefaultSMSData(&SMS->SMS[i]);
+ SMS->SMS[i].UDH.Type = UDHType;
+ GSM_EncodeUDHHeader(&SMS->SMS[i].UDH);
+ SMS->SMS[i].Coding = Coding;
+ }
+
+ /* Packing */
+ for (i=0;i<Info->EntriesNum;i++) {
+ Entry = &Info->Entries[i];
+
+ switch (Entry->ID) {
+ case SMS_ConcatenatedTextLong:
+ case SMS_ConcatenatedTextLong16bit:
+ Len = 0;
+ while(1) {
+ if (Entry->Left || Entry->Right ||
+ Entry->Center || Entry->Large ||
+ Entry->Small || Entry->Bold ||
+ Entry->Italic || Entry->Underlined ||
+ Entry->Strikethrough) {
+ Buffer[0] = 0x0A; /* ID for text format */
+ Buffer[1] = 0x03; /* length of rest */
+ Buffer[2] = 0x00; /* Position in EMS msg */
+ Buffer[3] = 0x00; /* how many chars */
+ Buffer[4] = 0x00; /* formatting bits */
+ if (Entry->Left) {
+ } else if (Entry->Right) { Buffer[4] |= 1;
+ } else if (Entry->Center) { Buffer[4] |= 2;
+ } else Buffer[4] |= 3;
+ if (Entry->Large) { Buffer[4] |= 4;
+ } else if (Entry->Small) { Buffer[4] |= 8;}
+ if (Entry->Bold) Buffer[4] |= 16;
+ if (Entry->Italic) Buffer[4] |= 32;
+ if (Entry->Underlined) Buffer[4] |= 64;
+ if (Entry->Strikethrough) Buffer[4] |= 128;
+ GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,5,true,&UsedText,&CopiedText,&CopiedSMSText);
+ GSM_Find_Free_Used_SMS2(Coding,SMS->SMS[SMS->Number], &UsedText, &FreeText, &FreeBytes);
+ if (FreeText == 0) continue;
+ }
+ GSM_AddSMS_Text_UDH(SMS,Coding,Entry->Buffer+Len*2,UnicodeLength(Entry->Buffer) - Len,false,&UsedText,&CopiedText,&CopiedSMSText);
+ if (Entry->Left || Entry->Right ||
+ Entry->Center || Entry->Large ||
+ Entry->Small || Entry->Bold ||
+ Entry->Italic || Entry->Underlined ||
+ Entry->Strikethrough) {
+ SMS->SMS[SMS->Number].UDH.Text[SMS->SMS[SMS->Number].UDH.Length-3] = UsedText;
+ SMS->SMS[SMS->Number].UDH.Text[SMS->SMS[SMS->Number].UDH.Length-2] = CopiedSMSText;
+ }
+ Len += CopiedText;
+ if (Len == UnicodeLength(Entry->Buffer)) break;
+ dbgprintf("%i %i\n",Len,UnicodeLength(Entry->Buffer));
+ }
+ break;
+ case SMS_EMSPredefinedSound:
+ case SMS_EMSPredefinedAnimation:
+ if (Entry->ID == SMS_EMSPredefinedSound) {
+ Buffer[0] = 0x0B; /* ID for def.sound */
+ } else {
+ Buffer[0] = 0x0D; /* ID for def.animation */
+ }
+ Buffer[1] = 0x02; /* Length of rest */
+ Buffer[2] = 0x00; /* Position in EMS msg */
+ Buffer[3] = Entry->Number; /* Number of anim. */
+ GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,4,true,&UsedText,&CopiedText,&CopiedSMSText);
+ SMS->SMS[SMS->Number].UDH.Text[SMS->SMS[SMS->Number].UDH.Length-2] = UsedText;
+ break;
+ case SMS_EMSSonyEricssonSound:
+ case SMS_EMSSound10:
+ case SMS_EMSSound12:
+ if (Entry->Protected) {
+ Buffer[0] = 0x17; /* ID for ODI */
+ Buffer[1] = 2; /* Length of rest */
+ Buffer[2] = 1; /* Number of protected objects */
+ Buffer[3] = 1; /* 1=Protected,0=Not protected */
+ GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,4,true,&UsedText,&CopiedText,&CopiedSMSText);
+ }
+
+ Length = 128; /* 128 bytes is maximal length from specs */
+ switch (Entry->ID) {
+ case SMS_EMSSound10:
+ Entry->RingtoneNotes = GSM_EncodeEMSSound(*Entry->Ringtone, Buffer+3, &Length, 1.0, true);
+ break;
+ case SMS_EMSSound12:
+ Entry->RingtoneNotes = GSM_EncodeEMSSound(*Entry->Ringtone, Buffer+3, &Length, 1.2, true);
+ break;
+ case SMS_EMSSonyEricssonSound:
+ Entry->RingtoneNotes = GSM_EncodeEMSSound(*Entry->Ringtone, Buffer+3, &Length, 0, true);
+ break;
+ default:
+ break;
+ }
+
+ Buffer[0] = 0x0C; /* ID for EMS sound */
+ Buffer[1] = Length+1; /* Length of rest */
+ Buffer[2] = 0x00; /* Position in EMS msg */
+ GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,Length+3,true,&UsedText,&CopiedText,&CopiedSMSText);
+ SMS->SMS[SMS->Number].UDH.Text[SMS->SMS[SMS->Number].UDH.Length-Length-1] = UsedText;
+ break;
+ case SMS_EMSSonyEricssonSoundLong:
+ case SMS_EMSSound10Long:
+ case SMS_EMSSound12Long:
+ Ring = *Entry->Ringtone;
+
+ /* First check if we can use classic format */
+ Length = 128; /* 128 bytes is maximal length from specs */
+ switch (Entry->ID) {
+ case SMS_EMSSound10Long:
+ Entry->RingtoneNotes = GSM_EncodeEMSSound(Ring, Buffer+3, &Length, 1.0, true);
+ break;
+ case SMS_EMSSound12Long:
+ Entry->RingtoneNotes = GSM_EncodeEMSSound(Ring, Buffer+3, &Length, 1.2, true);
+ break;
+ case SMS_EMSSonyEricssonSoundLong:
+ Entry->RingtoneNotes = GSM_EncodeEMSSound(Ring, Buffer+3, &Length, 0, true);
+ break;
+ default:
+ break;
+ }
+ if (Entry->RingtoneNotes == Ring.NoteTone.NrCommands) {
+ if (Entry->Protected) {
+ Buffer[0] = 0x17; /* ID for ODI */
+ Buffer[1] = 2; /* Length of rest */
+ Buffer[2] = 1; /* Number of protected objects */
+ Buffer[3] = 1; /* 1=Protected,0=Not protected */
+ GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,4,true,&UsedText,&CopiedText,&CopiedSMSText);
+ }
+
+ Buffer[0] = 0x0C; /* ID for EMS sound */
+ Buffer[1] = Length+1; /* Length of rest */
+ Buffer[2] = 0x00; /* Position in EMS msg */
+ GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,Length+3,true,&UsedText,&CopiedText,&CopiedSMSText);
+ SMS->SMS[SMS->Number].UDH.Text[SMS->SMS[SMS->Number].UDH.Length-Length-1] = UsedText;
+ break;
+ }
+
+ /* Find free place in first SMS */
+ GSM_Find_Free_Used_SMS2(Coding,SMS->SMS[SMS->Number], &UsedText, &FreeText, &FreeBytes);
+ Length = FreeBytes - 3;
+ if (Entry->Protected) Length = Length - 4;
+ if (Length < 0) Length = 128;
+ if (Length > 128) Length = 128;
+
+ Ring = *Entry->Ringtone;
+
+ /* Checking number of SMS */
+ Used = 0;
+ FreeBytes = 0;
+ start = true;
+ while (1) {
+ if (FreeBytes != 0) {
+ z = 0;
+ for (j=FreeBytes;j<Ring.NoteTone.NrCommands;j++) {
+ Ring.NoteTone.Commands[z] = Ring.NoteTone.Commands[j];
+ z++;
+ }
+ Ring.NoteTone.NrCommands -= FreeBytes;
+ if (Ring.NoteTone.NrCommands == 0) break;
+ Length = 128; /* 128 bytes is maximal length from specs */
+ }
+ switch (Entry->ID) {
+ case SMS_EMSSound10Long:
+ FreeBytes = GSM_EncodeEMSSound(Ring, Buffer+3, &Length, 1.0, start);
+ break;
+ case SMS_EMSSound12Long:
+ FreeBytes = GSM_EncodeEMSSound(Ring, Buffer+3, &Length, 1.2, start);
+ break;
+ case SMS_EMSSonyEricssonSoundLong:
+ FreeBytes = GSM_EncodeEMSSound(Ring, Buffer+3, &Length, 0, start);
+ break;
+ default:
+ break;
+ }
+ start = false;
+ Used++;
+ }
+ dbgprintf("Used SMS: %i\n",Used);
+
+ if (Entry->Protected) {
+ Buffer[0] = 0x17; /* ID for ODI */
+ Buffer[1] = 2; /* Length of rest */
+ Buffer[2] = Used+1; /* Number of protected objects */
+ Buffer[3] = 1; /* 1=Protected,0=Not protected */
+ GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,4,true,&UsedText,&CopiedText,&CopiedSMSText);
+ }
+
+ /* Save UPI UDH */
+ Buffer[0] = 0x13; /* ID for UPI */
+ Buffer[1] = 1; /* Length of rest */
+ Buffer[2] = Used; /* Number of used parts */
+ GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,3,true,&UsedText,&CopiedText,&CopiedSMSText);
+
+ /* Find free place in first SMS */
+ GSM_Find_Free_Used_SMS2(Coding,SMS->SMS[SMS->Number], &UsedText, &FreeText, &FreeBytes);
+ Length = FreeBytes - 3;
+ if (Length < 0) Length = 128;
+ if (Length > 128) Length = 128;
+
+ Ring = *Entry->Ringtone;
+
+ /* Saving */
+ FreeBytes = 0;
+ start = true;
+ while (1) {
+ if (FreeBytes != 0) {
+ z = 0;
+ for (j=FreeBytes;j<Ring.NoteTone.NrCommands;j++) {
+ Ring.NoteTone.Commands[z] = Ring.NoteTone.Commands[j];
+ z++;
+ }
+ Ring.NoteTone.NrCommands -= FreeBytes;
+ if (Ring.NoteTone.NrCommands == 0) break;
+ Length = 128; /* 128 bytes is maximal length from specs */
+ }
+ switch (Entry->ID) {
+ case SMS_EMSSound10Long:
+ FreeBytes = GSM_EncodeEMSSound(Ring, Buffer+3, &Length, 1.0, start);
+ break;
+ case SMS_EMSSound12Long:
+ FreeBytes = GSM_EncodeEMSSound(Ring, Buffer+3, &Length, 1.2, start);
+ break;
+ case SMS_EMSSonyEricssonSoundLong:
+ FreeBytes = GSM_EncodeEMSSound(Ring, Buffer+3, &Length, 0, start);
+ break;
+ default:
+ break;
+ }
+ Buffer[0] = 0x0C; /* ID for EMS sound */
+ Buffer[1] = Length+1; /* Length of rest */
+ Buffer[2] = 0x00; /* Position in EMS msg */
+ GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,Length+3,true,&UsedText,&CopiedText,&CopiedSMSText);
+ SMS->SMS[SMS->Number].UDH.Text[SMS->SMS[SMS->Number].UDH.Length-Length-1] = UsedText;
+ start = false;
+ }
+
+ Entry->RingtoneNotes = Entry->Ringtone->NoteTone.NrCommands;
+
+ break;
+ case SMS_EMSAnimation:
+ if (Entry->Protected) {
+ Buffer[0] = 0x17; /* ID for ODI */
+ Buffer[1] = 2; /* Length of rest */
+ Buffer[2] = 1; /* Number of protected objects */
+ Buffer[3] = 1; /* 1=Protected,0=Not protected */
+ GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,4,true,&UsedText,&CopiedText,&CopiedSMSText);
+ }
+
+ if (Entry->Bitmap->Bitmap[0].BitmapWidth > 8 || Entry->Bitmap->Bitmap[0].BitmapHeight > 8) {
+ BitmapType = GSM_EMSMediumPicture; /* Bitmap 16x16 */
+ Buffer[0] = 0x0E; /* ID for 16x16 animation */
+ } else {
+ BitmapType = GSM_EMSSmallPicture; /* Bitmap 8x8 */
+ Buffer[0] = 0x0F; /* ID for 8x8 animation */
+ }
+ Length = PHONE_GetBitmapSize(BitmapType,0,0);
+
+ Buffer[1] = Length*Entry->Bitmap->Number + 1; /* Length of rest */
+ Buffer[2] = 0x00; /* Position in EMS msg */
+ for (j=0;j<Entry->Bitmap->Number;j++) {
+ PHONE_EncodeBitmap(BitmapType, Buffer+3+j*Length, &Entry->Bitmap->Bitmap[j]);
+ }
+ GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,3+Length*Entry->Bitmap->Number,true,&UsedText,&CopiedText,&CopiedSMSText);
+ SMS->SMS[SMS->Number].UDH.Text[SMS->SMS[SMS->Number].UDH.Length-1-Length*Entry->Bitmap->Number] = UsedText;
+ break;
+ case SMS_EMSFixedBitmap:
+ if (Entry->Protected) {
+ Buffer[0] = 0x17; /* ID for ODI */
+ Buffer[1] = 2; /* Length of rest */
+ Buffer[2] = 1; /* Number of protected objects */
+ Buffer[3] = 1; /* 1=Protected,0=Not protected */
+ GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,4,true,&UsedText,&CopiedText,&CopiedSMSText);
+ }
+
+ if (Entry->Bitmap->Bitmap[0].BitmapWidth > 16 || Entry->Bitmap->Bitmap[0].BitmapHeight > 16) {
+ BitmapType = GSM_EMSBigPicture; /* Bitmap 32x32 */
+ Buffer[0] = 0x10; /* ID for EMS bitmap */
+ } else {
+ BitmapType = GSM_EMSMediumPicture; /* Bitmap 16x16 */
+ Buffer[0] = 0x11; /* ID for EMS bitmap */
+ }
+ Length = PHONE_GetBitmapSize(BitmapType,0,0);
+ PHONE_GetBitmapWidthHeight(BitmapType, &Width, &Height);
+
+ Buffer[1] = Length + 1; /* Length of rest */
+ Buffer[2] = 0x00; /* Position in EMS msg */
+ PHONE_EncodeBitmap(BitmapType,Buffer+3, &Entry->Bitmap->Bitmap[0]);
+ GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,3+Length,true,&UsedText,&CopiedText,&CopiedSMSText);
+ SMS->SMS[SMS->Number].UDH.Text[SMS->SMS[SMS->Number].UDH.Length-1-Length] = UsedText;
+ break;
+ case SMS_EMSVariableBitmapLong:
+ BitmapType = GSM_EMSVariablePicture;
+ Width = Entry->Bitmap->Bitmap[0].BitmapWidth;
+ Height = Entry->Bitmap->Bitmap[0].BitmapHeight;
+ Bitmap = Entry->Bitmap->Bitmap[0];
+
+ /* First check if we can use classical format */
+ while (1) {
+ /* Width should be multiply of 8 */
+ while (Width % 8 != 0) Width--;
+
+ /* specs */
+ if (Width <= 96 && Height <= 128) break;
+
+ Height--;
+ }
+ Length = PHONE_GetBitmapSize(BitmapType,Width,Height);
+ if (Length <= 128) {
+ if (Entry->Protected) {
+ Buffer[0] = 0x17; /* ID for ODI */
+ Buffer[1] = 2; /* Length of rest */
+ Buffer[2] = 1; /* Number of protected objects */
+ Buffer[3] = 1; /* 1=Protected,0=Not protected */
+ GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,4,true,&UsedText,&CopiedText,&CopiedSMSText);
+ }
+
+ Buffer[0] = 0x12; /* ID for EMS bitmap */
+ Buffer[1] = Length + 3; /* Length of rest */
+ Buffer[2] = 0x00; /* Position in EMS msg */
+ Buffer[3] = Width/8; /* Bitmap width/8 */
+ Buffer[4] = Height; /* Bitmap height */
+
+ GSM_ResizeBitmap(&Bitmap, &Entry->Bitmap->Bitmap[0], Width, Height);
+#ifdef DEBUG
+ if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) GSM_PrintBitmap(di.df,&Bitmap);
+#endif
+ PHONE_EncodeBitmap(BitmapType,Buffer+5, &Bitmap);
+ GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,5+Length,true,&UsedText,&CopiedText,&CopiedSMSText);
+ SMS->SMS[SMS->Number].UDH.Text[SMS->SMS[SMS->Number].UDH.Length-3-Length] = UsedText;
+ break;
+ }
+
+ /* Find free place in first SMS */
+ GSM_Find_Free_Used_SMS2(Coding,SMS->SMS[SMS->Number], &UsedText, &FreeText, &FreeBytes);
+ Used = 0;
+ Length = FreeBytes - 3;
+ if (Entry->Protected) Length = Length - 4;
+ if (Length < 0) Length = 128;
+ if (Length > 128) Length = 128;
+
+ /* Checking number of SMS */
+ FreeBytes = 0;
+ while (FreeBytes != Width) {
+ Width2 = 8;
+ while (FreeBytes + Width2 != Width) {
+ if (PHONE_GetBitmapSize(BitmapType,Width2+8,Height) > Length) break;
+
+ Width2 = Width2 + 8;
+ }
+ FreeBytes = FreeBytes + Width2;
+ Length = 128;
+ Used ++;
+ }
+ dbgprintf("Used SMS: %i\n",Used);
+
+ if (Entry->Protected) {
+ Buffer[0] = 0x17; /* ID for ODI */
+ Buffer[1] = 2; /* Length of rest */
+ Buffer[2] = Used+1; /* Number of protected objects */
+ Buffer[3] = 1; /* 1=Protected,0=Not protected */
+ GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,4,true,&UsedText,&CopiedText,&CopiedSMSText);
+ }
+
+ /* Save UPI UDH */
+ Buffer[0] = 0x13; /* ID for UPI */
+ Buffer[1] = 1; /* Length of rest */
+ Buffer[2] = Used; /* Number of used parts */
+
+ /* Find free place in first SMS */
+ GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,3,true,&UsedText,&CopiedText,&CopiedSMSText);
+ GSM_Find_Free_Used_SMS2(Coding,SMS->SMS[SMS->Number], &UsedText, &FreeText, &FreeBytes);
+ Length = FreeBytes - 3;
+ if (Length < 0) Length = 128;
+ if (Length > 128) Length = 128;
+
+#ifdef DEBUG
+ if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) GSM_PrintBitmap(di.df,&Bitmap);
+#endif
+
+ /* Saving SMS */
+ FreeBytes = 0;
+ while (FreeBytes != Width) {
+ Width2 = 8;
+ while (FreeBytes + Width2 != Width) {
+ if (PHONE_GetBitmapSize(BitmapType,Width2+8,Height) > Length) break;
+
+ Width2 = Width2 + 8;
+ }
+
+ /* Copying part of bitmap to new structure */
+ Bitmap2.BitmapWidth = Width2;
+ Bitmap2.BitmapHeight = Height;
+ GSM_ClearBitmap(&Bitmap2);
+ for (x=0;x<Width2;x++) {
+ for (y=0;y<Height;y++) {
+ if (GSM_IsPointBitmap(&Bitmap,x+FreeBytes,y)) {
+ GSM_SetPointBitmap(&Bitmap2, x, y);
+ }
+ }
+ }
+#ifdef DEBUG
+ if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) GSM_PrintBitmap(di.df,&Bitmap2);
+#endif
+
+ /* Adding new bitmap to SMS */
+ Length = PHONE_GetBitmapSize(BitmapType,Width2,Height);
+ Buffer[0] = 0x12; /* ID for EMS bitmap */
+ Buffer[1] = Length + 3; /* Length of rest */
+ Buffer[2] = 0x00; /* Position in EMS msg */
+ Buffer[3] = Width2/8; /* Bitmap width/8 */
+ Buffer[4] = Height; /* Bitmap height */
+ PHONE_EncodeBitmap(BitmapType,Buffer+5, &Bitmap2);
+ GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,5+Length,true,&UsedText,&CopiedText,&CopiedSMSText);
+ SMS->SMS[SMS->Number].UDH.Text[SMS->SMS[SMS->Number].UDH.Length-3-Length] = UsedText;
+
+ FreeBytes = FreeBytes + Width2;
+ Length = 128;
+ }
+ break;
+ case SMS_EMSVariableBitmap:
+ if (Entry->Protected) {
+ Buffer[0] = 0x17; /* ID for ODI */
+ Buffer[1] = 2; /* Length of rest */
+ Buffer[2] = 1; /* Number of protected objects */
+ Buffer[3] = 1; /* 1=Protected,0=Not protected */
+ GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,4,true,&UsedText,&CopiedText,&CopiedSMSText);
+ }
+
+ BitmapType = GSM_EMSVariablePicture;
+ Width = Entry->Bitmap->Bitmap[0].BitmapWidth;
+ Height = Entry->Bitmap->Bitmap[0].BitmapHeight;
+
+ while (1) {
+ /* Width should be multiply of 8 */
+ while (Width % 8 != 0) Width--;
+
+ /* specs */
+ if (PHONE_GetBitmapSize(BitmapType,Width,Height) <= 128) break;
+
+ Height--;
+ }
+
+ Length = PHONE_GetBitmapSize(BitmapType,Width,Height);
+
+ Buffer[0] = 0x12; /* ID for EMS bitmap */
+ Buffer[1] = Length + 3; /* Length of rest */
+ Buffer[2] = 0x00; /* Position in EMS msg */
+ Buffer[3] = Width/8; /* Bitmap width/8 */
+ Buffer[4] = Height; /* Bitmap height */
+
+ GSM_ResizeBitmap(&Bitmap, &Entry->Bitmap->Bitmap[0], Width, Height);
+#ifdef DEBUG
+ if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) GSM_PrintBitmap(di.df,&Bitmap);
+#endif
+ PHONE_EncodeBitmap(BitmapType,Buffer+5, &Bitmap);
+ GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,5+Length,true,&UsedText,&CopiedText,&CopiedSMSText);
+ SMS->SMS[SMS->Number].UDH.Text[SMS->SMS[SMS->Number].UDH.Length-3-Length] = UsedText;
+ break;
+ default:
+ break;
+ }
+ }
+
+ SMS->Number++;
+
+ if (UDHType == UDH_ConcatenatedMessages) {
+ UDHID = GSM_MakeSMSIDFromTime();
+ for (i=0;i<SMS->Number;i++) {
+ SMS->SMS[i].UDH.Text[2+1] = UDHID;
+ SMS->SMS[i].UDH.Text[3+1] = SMS->Number;
+ SMS->SMS[i].UDH.Text[4+1] = i+1;
+ }
+ }
+ if (UDHType == UDH_ConcatenatedMessages16bit) {
+ UDHID = GSM_MakeSMSIDFromTime();
+ GSM_GetCurrentDateTime (&Date);
+ for (i=0;i<SMS->Number;i++) {
+ SMS->SMS[i].UDH.Text[2+1] = Date.Hour;
+ SMS->SMS[i].UDH.Text[3+1] = UDHID;
+ SMS->SMS[i].UDH.Text[4+1] = SMS->Number;
+ SMS->SMS[i].UDH.Text[5+1] = i+1;
+ }
+ }
+
+#ifdef DEBUG
+ dbgprintf("SMS number is %i\n",SMS->Number);
+ for (i=0;i<SMS->Number;i++) {
+ dbgprintf("UDH length %i\n",SMS->SMS[i].UDH.Length);
+ DumpMessage(di.df, di.dl, SMS->SMS[i].UDH.Text, SMS->SMS[i].UDH.Length);
+ dbgprintf("SMS length %i\n",UnicodeLength(SMS->SMS[i].Text)*2);
+ DumpMessage(di.df, di.dl, SMS->SMS[i].Text, UnicodeLength(SMS->SMS[i].Text)*2);
+ }
+#endif
+ return ERR_NONE;
+}
+
+static bool AddEMSText(GSM_SMSMessage *SMS, GSM_MultiPartSMSInfo *Info, int *Pos, int Len)
+{
+ int BufferLen;
+
+ if (Len==0) return true;
+
+ if (Info->Entries[Info->EntriesNum].ID!=SMS_ConcatenatedTextLong &&
+ Info->Entries[Info->EntriesNum].ID!=0) {
+ (Info->EntriesNum)++;
+ }
+ BufferLen = UnicodeLength(Info->Entries[Info->EntriesNum].Buffer)*2;
+ switch (SMS->Coding) {
+ case SMS_Coding_8bit:
+// memcpy(Info->Entries[Info->EntriesNum].Buffer+BufferLen,SMS->Text+(*Pos),Len);
+// BufferLen+=Len;
+// (*Pos)+=Len;
+ break;
+ case SMS_Coding_Unicode:
+ case SMS_Coding_Default:
+ Info->Entries[Info->EntriesNum].Buffer = realloc(Info->Entries[Info->EntriesNum].Buffer, BufferLen + (Len * 2) + 2);
+ if (Info->Entries[Info->EntriesNum].Buffer == NULL) return false;
+ memcpy(Info->Entries[Info->EntriesNum].Buffer + BufferLen, SMS->Text + (*Pos) *2, Len * 2);
+ BufferLen += Len * 2;
+ break;
+ }
+ (*Pos)+=Len;
+ Info->Entries[Info->EntriesNum].Buffer[BufferLen] = 0;
+ Info->Entries[Info->EntriesNum].Buffer[BufferLen+1] = 0;
+ Info->Entries[Info->EntriesNum].ID = SMS_ConcatenatedTextLong;
+ return true;
+}
+
+bool GSM_DecodeEMSMultiPartSMS(GSM_MultiPartSMSInfo *Info,
+ GSM_MultiSMSMessage *SMS)
+{
+ int i, w, Pos, z, UPI = 1, width, height;
+ bool RetVal = false, NewPicture = true;
+ GSM_Phone_Bitmap_Types BitmapType;
+ GSM_Bitmap Bitmap,Bitmap2;
+
+ for (i=0;i<MAX_MULTI_SMS;i++) {
+ Info->Entries[i].ID = 0;
+ }
+
+ for (i=0;i<SMS->Number;i++) {
+ Pos = 0;
+ w = 1;
+ while (w < SMS->SMS[i].UDH.Length) {
+ if (Info->EntriesNum + 1 == MAX_MULTI_SMS) {
+ dbgprintf("Couldn't parse SMS, contains too many EMS parts!\n");
+ return false;
+ }
+ switch(SMS->SMS[i].UDH.Text[w]) {
+ case 0x00:
+ dbgprintf("UDH part - linked SMS with 8 bit ID\n");
+ break;
+ case 0x08:
+ dbgprintf("UDH part - linked SMS with 16 bit ID\n");
+ break;
+// case 0x0A:
+// dbgprintf("UDH part - EMS text formatting\n");
+// break;
+ case 0x0B:
+ dbgprintf("UDH part - default EMS sound\n");
+ if (SMS->SMS[i].UDH.Text[w+2] > Pos) {
+ z = Pos;
+ if (!AddEMSText(&SMS->SMS[i], Info, &Pos, SMS->SMS[i].UDH.Text[w+2]-z)) return false;
+ }
+ if (Info->Entries[Info->EntriesNum].ID != 0) (Info->EntriesNum)++;
+ Info->Entries[Info->EntriesNum].Number = SMS->SMS[i].UDH.Text[w+3];
+ Info->Entries[Info->EntriesNum].ID = SMS_EMSPredefinedSound;
+ RetVal = true;
+ break;
+// case 0x0C:
+// dbgprintf("UDH part - EMS sound\n");
+// break;
+ case 0x0D:
+ dbgprintf("UDH part - default EMS animation\n");
+ if (SMS->SMS[i].UDH.Text[w+2] > Pos) {
+ z = Pos;
+ if (!AddEMSText(&SMS->SMS[i], Info, &Pos, SMS->SMS[i].UDH.Text[w+2]-z)) return false;
+ }
+ if (Info->Entries[Info->EntriesNum].ID != 0) (Info->EntriesNum)++;
+ Info->Entries[Info->EntriesNum].Number = SMS->SMS[i].UDH.Text[w+3];
+ Info->Entries[Info->EntriesNum].ID = SMS_EMSPredefinedAnimation;
+ RetVal = true;
+ break;
+ case 0x0E:
+ case 0x0F:
+ if (SMS->SMS[i].UDH.Text[w] == 0x0E) {
+ dbgprintf("UDH part - EMS 16x16 animation\n");
+ BitmapType = GSM_EMSMediumPicture;
+ } else {
+ dbgprintf("UDH part - EMS 8x8 animation\n");
+ BitmapType = GSM_EMSSmallPicture;
+ }
+ dbgprintf("Position - %i\n",SMS->SMS[i].UDH.Text[w+2]);
+ if (SMS->SMS[i].UDH.Text[w+2] > Pos) {
+ z = Pos;
+ if (!AddEMSText(&SMS->SMS[i], Info, &Pos, SMS->SMS[i].UDH.Text[w+2]-z)) return false;
+ }
+ (Info->EntriesNum)++;
+ Info->Entries[Info->EntriesNum].ID = SMS_EMSAnimation;
+ Info->Entries[Info->EntriesNum].Bitmap = (GSM_MultiBitmap *)malloc(sizeof(GSM_MultiBitmap));
+ if (Info->Entries[Info->EntriesNum].Bitmap == NULL) return false;
+ Info->Entries[Info->EntriesNum].Bitmap->Number = 0;
+ for (z=0;z<((SMS->SMS[i].UDH.Text[w+1]-1)/PHONE_GetBitmapSize(BitmapType,0,0));z++) {
+ Info->Entries[Info->EntriesNum].Bitmap->Bitmap[z].Type = GSM_PictureImage;
+ PHONE_DecodeBitmap(BitmapType,
+ SMS->SMS[i].UDH.Text + w + 3 + PHONE_GetBitmapSize(BitmapType,0,0) * z,
+ &Info->Entries[Info->EntriesNum].Bitmap->Bitmap[z]);
+ Info->Entries[Info->EntriesNum].Bitmap->Number++;
+ }
+ RetVal = true;
+ break;
+ case 0x10:
+ case 0x11:
+ if (SMS->SMS[i].UDH.Text[w] == 0x10) {
+ dbgprintf("UDH part - EMS 32x32 picture\n");
+ BitmapType = GSM_EMSBigPicture;
+ } else {
+ dbgprintf("UDH part - EMS 16x16 picture\n");
+ BitmapType = GSM_EMSMediumPicture;
+ }
+ dbgprintf("Position - %i\n",SMS->SMS[i].UDH.Text[w+2]);
+ if (SMS->SMS[i].UDH.Text[w+2] > Pos) {
+ z = Pos;
+ if (!AddEMSText(&SMS->SMS[i], Info, &Pos, SMS->SMS[i].UDH.Text[w+2]-z)) return false;
+ }
+ if (Info->Entries[Info->EntriesNum].ID != 0) (Info->EntriesNum)++;
+ Info->Entries[Info->EntriesNum].Bitmap = (GSM_MultiBitmap *)malloc(sizeof(GSM_MultiBitmap));
+ if (Info->Entries[Info->EntriesNum].Bitmap == NULL) return false;
+ PHONE_DecodeBitmap(BitmapType,
+ SMS->SMS[i].UDH.Text + w + 3,
+ &Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0]);
+ Info->Entries[Info->EntriesNum].Bitmap->Number = 1;
+ Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0].Text[0] = 0;
+ Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0].Text[1] = 0;
+ Info->Entries[Info->EntriesNum].ID = SMS_EMSFixedBitmap;
+ RetVal = true;
+ break;
+ case 0x12:
+ dbgprintf("UDH part - EMS variable width bitmap\n");
+ if (SMS->SMS[i].UDH.Text[w+2] > Pos) {
+ z = Pos;
+ if (!AddEMSText(&SMS->SMS[i], Info, &Pos, SMS->SMS[i].UDH.Text[w+2]-z)) return false;
+ }
+ if (NewPicture) {
+ (Info->EntriesNum)++;
+ Info->Entries[Info->EntriesNum].Bitmap->Number = 0;
+ Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0].BitmapWidth = 0;
+ Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0].BitmapHeight = 0;
+ }
+ Bitmap.BitmapWidth = SMS->SMS[i].UDH.Text[w+3]*8;
+ Bitmap.BitmapHeight = SMS->SMS[i].UDH.Text[w+4];
+ Info->Entries[Info->EntriesNum].Bitmap = (GSM_MultiBitmap *)malloc(sizeof(GSM_MultiBitmap));
+ if (Info->Entries[Info->EntriesNum].Bitmap == NULL) return false;
+ if (NewPicture) {
+ Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0].BitmapWidth = Bitmap.BitmapWidth;
+ Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0].BitmapHeight = Bitmap.BitmapHeight;
+ PHONE_DecodeBitmap(GSM_EMSVariablePicture,
+ SMS->SMS[i].UDH.Text + w + 5,
+ &Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0]);
+ } else {
+ PHONE_DecodeBitmap(GSM_EMSVariablePicture,
+ SMS->SMS[i].UDH.Text + w + 5,
+ &Bitmap);
+ Bitmap2 = Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0];
+ Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0].BitmapWidth = Bitmap.BitmapWidth+Bitmap2.BitmapWidth;
+ Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0].BitmapHeight = Bitmap2.BitmapHeight;
+ for (width=0;width<Bitmap2.BitmapWidth;width++) {
+ for (height=0;height<Bitmap2.BitmapHeight;height++) {
+ if (GSM_IsPointBitmap(&Bitmap2, width, height)) {
+ GSM_SetPointBitmap(&Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0],width,height);
+ } else {
+ GSM_ClearPointBitmap(&Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0],width,height);
+ }
+ }
+ }
+ for (width=0;width<Bitmap.BitmapWidth;width++) {
+ for (height=0;height<Bitmap2.BitmapHeight;height++) {
+ if (GSM_IsPointBitmap(&Bitmap, width, height)) {
+ GSM_SetPointBitmap(&Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0],width+Bitmap2.BitmapWidth,height);
+ } else {
+ GSM_ClearPointBitmap(&Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0],width+Bitmap2.BitmapWidth,height);
+ }
+ }
+ }
+ }
+ if (UPI == 1) {
+ Info->Entries[Info->EntriesNum].Bitmap->Number = 1;
+ Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0].Text[0] = 0;
+ Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0].Text[1] = 0;
+ Info->Entries[Info->EntriesNum].ID = SMS_EMSVariableBitmap;
+ RetVal = true;
+ NewPicture = true;
+ dbgprintf("New variable picture\n");
+ } else {
+ NewPicture = false;
+ UPI--;
+ }
+ break;
+ case 0x13:
+ dbgprintf("UDH part - UPI\n");
+ dbgprintf("Value %i\n",SMS->SMS[i].UDH.Text[w+2]);
+ UPI = SMS->SMS[i].UDH.Text[w+2];
+ break;
+ case 0x17:
+ dbgprintf("UDH part - Object Distribution Indicator (Media Rights Protecting) ignored now\n");
+ break;
+ default:
+ dbgprintf("UDH part - block %02x\n",SMS->SMS[i].UDH.Text[w]);
+ Info->Unknown = true;
+ } /* switch */
+ w=w+SMS->SMS[i].UDH.Text[w+1]+2;
+ } /* while */
+ if (!AddEMSText(&SMS->SMS[i], Info, &Pos, SMS->SMS[i].Length-Pos)) return false;
+ RetVal = true;
+ }
+ if (RetVal) (Info->EntriesNum)++;
+ return RetVal;
+}
+
+/* How should editor hadle tabs in this file? Add editor commands here.
+ * vim: noexpandtab sw=8 ts=8 sts=8:
+ */
diff --git a/gammu/emb/common/service/sms/gsmems.h b/gammu/emb/common/service/sms/gsmems.h
new file mode 100644
index 0000000..6701d28
--- a/dev/null
+++ b/gammu/emb/common/service/sms/gsmems.h
@@ -0,0 +1,20 @@
+/* (c) 2002-2003 by Marcin Wiacek */
+
+#ifndef __gsm_ems_h
+#define __gsm_ems_h
+
+#include "../../gsmcomon.h"
+#include "gsmmulti.h"
+
+GSM_Error GSM_EncodeEMSMultiPartSMS(GSM_MultiPartSMSInfo *Info,
+ GSM_MultiSMSMessage *SMS,
+ GSM_UDH UDHType);
+
+bool GSM_DecodeEMSMultiPartSMS(GSM_MultiPartSMSInfo *Info,
+ GSM_MultiSMSMessage *SMS);
+
+#endif
+
+/* How should editor hadle tabs in this file? Add editor commands here.
+ * vim: noexpandtab sw=8 ts=8 sts=8:
+ */
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:
+ */
diff --git a/gammu/emb/common/service/sms/gsmmulti.h b/gammu/emb/common/service/sms/gsmmulti.h
new file mode 100644
index 0000000..c672261
--- a/dev/null
+++ b/gammu/emb/common/service/sms/gsmmulti.h
@@ -0,0 +1,271 @@
+/* (c) 2002-2004 by Marcin Wiacek */
+
+#ifndef __gsm_multi_h
+#define __gsm_multi_h
+
+#include "../../gsmcomon.h"
+#include "../gsmlogo.h"
+#include "../gsmcal.h"
+#include "../gsmpbk.h"
+#include "../gsmdata.h"
+#include "../gsmring.h"
+#include "gsmsms.h"
+
+/* ---------------------- multi SMS --------------------------------------- */
+
+/* Identifiers for Smart Messaging 3.0 multipart SMS */
+
+#define SM30_ISOTEXT 0 /* ISO 8859-1 text */
+#define SM30_UNICODETEXT 1
+#define SM30_OTA 2
+#define SM30_RINGTONE 3
+#define SM30_PROFILENAME 4
+/* ... */
+#define SM30_SCREENSAVER 6
+
+/* Identifiers for Alcatel Terminal Data Download */
+#define ALCATELTDD_PICTURE 4
+#define ALCATELTDD_ANIMATION 5
+#define ALCATELTDD_SMSTEMPLATE 6
+
+void GSM_SMSCounter(int MessageLength,
+ unsigned char *MessageBuffer,
+ GSM_UDH UDHType,
+ GSM_Coding_Type Coding,
+ int *SMSNum,
+ int *CharsLeft);
+
+#define MAX_MULTI_SMS 10
+
+/**
+ * Multiple SMS messages, used for Smart Messaging 3.0/EMS.
+ */
+typedef struct {
+ /**
+ * Sender or recipient number.
+ */
+ unsigned char Number;
+ /**
+ * Array of SMSes.
+ */
+ GSM_SMSMessage SMS[MAX_MULTI_SMS];
+} GSM_MultiSMSMessage;
+
+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);
+
+void GSM_MakeMultiPartSMS(GSM_MultiSMSMessage *SMS,
+ unsigned char *MessageBuffer,
+ int MessageLength,
+ GSM_UDH UDHType,
+ GSM_Coding_Type Coding,
+ int Class,
+ unsigned char RejectDuplicates);
+
+void GSM_Find_Free_Used_SMS2(GSM_Coding_Type Coding,GSM_SMSMessage SMS, int *UsedText, int *FreeText, int *FreeBytes);
+
+unsigned char GSM_MakeSMSIDFromTime(void);
+
+/**
+ * ID during packing SMS for Smart Messaging 3.0, EMS and other
+ */
+typedef enum {
+ /**
+ * 1 text SMS.
+ */
+ SMS_Text = 1,
+ /**
+ * Contacenated SMS, when longer than 1 SMS.
+ */
+ SMS_ConcatenatedTextLong,
+ /**
+ * Contacenated SMS, auto Default/Unicode coding.
+ */
+ SMS_ConcatenatedAutoTextLong,
+ SMS_ConcatenatedTextLong16bit,
+ SMS_ConcatenatedAutoTextLong16bit,
+ /**
+ * Nokia profile = Name, Ringtone, ScreenSaver
+ */
+ SMS_NokiaProfileLong,
+ /**
+ * Nokia Picture Image + (text)
+ */
+ SMS_NokiaPictureImageLong,
+ /**
+ * Nokia screen saver + (text)
+ */
+ SMS_NokiaScreenSaverLong,
+ /**
+ * Nokia ringtone - old SM2.0 format, 1 SMS
+ */
+ SMS_NokiaRingtone,
+ /**
+ * Nokia ringtone contacenated, when very long
+ */
+ SMS_NokiaRingtoneLong,
+ /**
+ * Nokia 72x14 operator logo, 1 SMS
+ */
+ SMS_NokiaOperatorLogo,
+ /**
+ * Nokia 72x14 op logo or 78x21 in 2 SMS
+ */
+ SMS_NokiaOperatorLogoLong,
+ /**
+ * Nokia 72x14 caller logo, 1 SMS
+ */
+ SMS_NokiaCallerLogo,
+ /**
+ * Nokia WAP bookmark in 1 or 2 SMS
+ */
+ SMS_NokiaWAPBookmarkLong,
+ /**
+ * Nokia WAP settings in 2 SMS
+ */
+ SMS_NokiaWAPSettingsLong,
+ /**
+ * Nokia MMS settings in 2 SMS
+ */
+ SMS_NokiaMMSSettingsLong,
+ /**
+ * Nokia VCARD 1.0 - only name and default number
+ */
+ SMS_NokiaVCARD10Long,
+ /**
+ * Nokia VCARD 2.1 - all numbers + text
+ */
+ SMS_NokiaVCARD21Long,
+ /**
+ * Nokia VCALENDAR 1.0 - can be in few sms
+ */
+ SMS_NokiaVCALENDAR10Long,
+ SMS_NokiaVTODOLong,
+ SMS_VCARD10Long,
+ SMS_VCARD21Long,
+ SMS_DisableVoice,
+ SMS_DisableFax,
+ SMS_DisableEmail,
+ SMS_EnableVoice,
+ SMS_EnableFax,
+ SMS_EnableEmail,
+ SMS_VoidSMS,
+ /**
+ * IMelody 1.0
+ */
+ SMS_EMSSound10,
+ /**
+ * IMelody 1.2
+ */
+ SMS_EMSSound12,
+ /**
+ * IMelody without header - SonyEricsson extension
+ */
+ SMS_EMSSonyEricssonSound,
+ /**
+ * IMelody 1.0 with UPI.
+ */
+ SMS_EMSSound10Long,
+ /***
+ * IMelody 1.2 with UPI.
+ */
+ SMS_EMSSound12Long,
+ /**
+ * IMelody without header with UPI.
+ */
+ SMS_EMSSonyEricssonSoundLong,
+ SMS_EMSPredefinedSound,
+ SMS_EMSPredefinedAnimation,
+ SMS_EMSAnimation,
+ /**
+ * Fixed bitmap of size 16x16 or 32x32.
+ */
+ SMS_EMSFixedBitmap,
+ SMS_EMSVariableBitmap,
+ SMS_EMSVariableBitmapLong,
+ SMS_MMSIndicatorLong,
+ /**
+ * Variable bitmap with black and white colors
+ */
+ SMS_AlcatelMonoBitmapLong,
+ /**
+ * Variable animation with black and white colors
+ */
+ SMS_AlcatelMonoAnimationLong,
+ SMS_AlcatelSMSTemplateName
+} EncodeMultiPartSMSID;
+
+typedef struct {
+ EncodeMultiPartSMSID ID;
+
+ int Number;
+ GSM_Ringtone *Ringtone;
+ GSM_MultiBitmap *Bitmap;
+ GSM_WAPBookmark *Bookmark;
+ GSM_WAPSettings *Settings;
+ GSM_MMSIndicator *MMSIndicator;
+ GSM_MemoryEntry *Phonebook;
+ GSM_CalendarEntry *Calendar;
+ GSM_ToDoEntry *ToDo;
+ bool Protected;
+
+ unsigned char *Buffer;
+ bool Left;
+ bool Right;
+ bool Center;
+ bool Large;
+ bool Small;
+ bool Bold;
+ bool Italic;
+ bool Underlined;
+ bool Strikethrough;
+
+ /* Return values */
+ int RingtoneNotes;
+} MultiPartSMSEntry;
+
+typedef struct {
+ MultiPartSMSEntry Entries[MAX_MULTI_SMS];
+ int EntriesNum;
+ bool UnicodeCoding;
+ int Class;
+ unsigned char ReplaceMessage;
+ bool Unknown;
+} GSM_MultiPartSMSInfo;
+
+/**
+ * Encodes multi part SMS from "readable" format.
+ */
+GSM_Error GSM_EncodeMultiPartSMS (GSM_MultiPartSMSInfo *Info, GSM_MultiSMSMessage *SMS);
+
+/**
+ * Decodes multi part SMS to "readable" format.
+ */
+bool GSM_DecodeMultiPartSMS (GSM_MultiPartSMSInfo *Info, GSM_MultiSMSMessage *SMS, bool ems);
+
+/**
+ * Clears @ref GSM_MultiPartSMSInfo to default values.
+ */
+void GSM_ClearMultiPartSMSInfo (GSM_MultiPartSMSInfo *Info);
+
+/**
+ * Frees any allocated structures inside @ref GSM_MultiPartSMSInfo.
+ */
+void GSM_FreeMultiPartSMSInfo (GSM_MultiPartSMSInfo *Info);
+
+/**
+ * Links SMS messages according to IDs.
+ */
+GSM_Error GSM_LinkSMS(GSM_MultiSMSMessage **INPUT, GSM_MultiSMSMessage **OUTPUT, bool ems);
+
+#endif
+
+/* How should editor hadle tabs in this file? Add editor commands here.
+ * vim: noexpandtab sw=8 ts=8 sts=8:
+ */
diff --git a/gammu/emb/common/service/sms/gsmsms.c b/gammu/emb/common/service/sms/gsmsms.c
new file mode 100644
index 0000000..9920835
--- a/dev/null
+++ b/gammu/emb/common/service/sms/gsmsms.c
@@ -0,0 +1,663 @@
+/* (c) 2001-2004 by Marcin Wiacek */
+/* based on some work from Pawel Kot, others and Gnokii */
+
+#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"
+
+/* 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;w<tmp;w++) {
+ if (UDHHeaders[i].Text[w]!=UDH->Text[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;i<Layout.Text;i++) buffer[i] = 0;
+ }
+
+ /* GSM 03.40 section 9.2.3.1 (TP-Message-Type-Indicator) */
+ switch (SMS->PDU) {
+ 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:
+ */
diff --git a/gammu/emb/common/service/sms/gsmsms.h b/gammu/emb/common/service/sms/gsmsms.h
new file mode 100644
index 0000000..d87ff60
--- a/dev/null
+++ b/gammu/emb/common/service/sms/gsmsms.h
@@ -0,0 +1,492 @@
+/* (c) 2001-2004 by Marcin Wiacek */
+/* based on some work from Pawel Kot, others and Gnokii */
+
+#ifndef __gsm_sms_h
+#define __gsm_sms_h
+
+#include "../../gsmcomon.h"
+#include "../gsmlogo.h"
+#include "../gsmcal.h"
+#include "../gsmpbk.h"
+#include "../gsmdata.h"
+#include "../gsmring.h"
+
+/* --------------------- Some general definitions ------------------------- */
+
+#define GSM_MAX_UDH_LENGTH 140
+#define GSM_MAX_SMS_LENGTH 160
+#define GSM_MAX_8BIT_SMS_LENGTH 140
+
+/* -------------------- Cell Broadcast ------------------------------------ */
+
+/**
+ * Structure for Cell Broadcast messages.
+ */
+typedef struct {
+ /**
+ * Message text.
+ */
+ char Text[300];
+ /**
+ * Channel number.
+ */
+ int Channel;
+} GSM_CBMessage;
+
+/* ------------------------ SMS status ------------------------------------ */
+
+/**
+ * Status of SMS memory.
+ */
+typedef struct {
+ /**
+ * Number of unread messages on SIM.
+ */
+ int SIMUnRead;
+ /**
+ * Number of all saved messages (including unread) on SIM.
+ */
+ int SIMUsed;
+ /**
+ * Number of all possible messages on SIM.
+ */
+ int SIMSize;
+ /**
+ * Number of used templates (62xx/63xx/7110/etc.).
+ */
+ int TemplatesUsed;
+ /**
+ * Number of unread messages in phone.
+ */
+ int PhoneUnRead;
+ /**
+ * Number of all saved messages in phone.
+ */
+ int PhoneUsed;
+ /**
+ * Number of all possible messages on phone.
+ */
+ int PhoneSize;
+} GSM_SMSMemoryStatus;
+
+/* --------------------- SMS Center --------------------------------------- */
+
+/**
+ * Enum defines format of SMS messages. See GSM 03.40 section 9.2.3.9
+ */
+typedef enum {
+ SMS_FORMAT_Pager = 1,
+ SMS_FORMAT_Fax,
+ SMS_FORMAT_Email,
+ SMS_FORMAT_Text
+ /* Some values not handled here */
+} GSM_SMSFormat;
+
+/**
+ * Enum defines some the most often used validity lengths for SMS messages
+ * for relative validity format. See GSM 03.40 section 9.2.3.12.1 - it gives
+ * more values
+ */
+typedef enum {
+ SMS_VALID_1_Hour = 0x0b,
+ SMS_VALID_6_Hours = 0x47,
+ SMS_VALID_1_Day = 0xa7,
+ SMS_VALID_3_Days = 0xa9,
+ SMS_VALID_1_Week = 0xad,
+ SMS_VALID_Max_Time = 0xff
+} GSM_ValidityPeriod;
+
+/**
+ * Enum defines format of validity period for SMS messages.
+ * See GSM 03.40 section 9.2.3.12
+ */
+typedef enum {
+ SMS_Validity_NotAvailable = 1,
+ SMS_Validity_RelativeFormat
+ /* Specification gives also other possibilities */
+} GSM_ValidityPeriodFormat;
+
+/**
+ * Structure for validity of SMS messages
+ */
+typedef struct {
+ GSM_ValidityPeriodFormat Format;
+ /**
+ * Value defines period for relative format
+ */
+ GSM_ValidityPeriod Relative;
+} GSM_SMSValidity;
+
+#define GSM_MAX_SMSC_NAME_LENGTH 30
+
+/**
+ * Structure for SMSC (SMS Center) information.
+ */
+typedef struct {
+ /**
+ * Number of the SMSC on SIM
+ */
+ int Location;
+ /**
+ * Name of the SMSC
+ */
+ unsigned char Name[(GSM_MAX_SMSC_NAME_LENGTH+1)*2];
+ /**
+ * SMSC phone number.
+ */
+ unsigned char Number[(GSM_MAX_NUMBER_LENGTH+1)*2];
+ /**
+ * Validity of SMS messages.
+ */
+ GSM_SMSValidity Validity;
+ /**
+ * Format of sent SMS messages.
+ */
+ GSM_SMSFormat Format;
+ /**
+ * Default recipient number. In old DCT3 ignored
+ */
+ unsigned char DefaultNumber[(GSM_MAX_NUMBER_LENGTH+1)*2];
+} GSM_SMSC;
+
+/* --------------------- single SMS --------------------------------------- */
+
+/**
+ * Status of SMS message.
+ */
+typedef enum {
+ SMS_Sent = 1,
+ SMS_UnSent,
+ SMS_Read,
+ SMS_UnRead
+} GSM_SMS_State;
+
+/**
+ * Coding type of SMS.
+ */
+typedef enum {
+ /**
+ * Unicode
+ */
+ SMS_Coding_Unicode = 1,
+ /**
+ * Default GSM aplhabet.
+ */
+ SMS_Coding_Default,
+ /**
+ * 8-bit.
+ */
+ SMS_Coding_8bit
+} GSM_Coding_Type;
+
+/**
+ * Types of UDH (User Data Header).
+ */
+typedef enum {
+ UDH_NoUDH = 1,
+ /**
+ * Linked SMS.
+ */
+ UDH_ConcatenatedMessages,
+ /**
+ * Linked SMS with 16 bit reference.
+ */
+ UDH_ConcatenatedMessages16bit,
+ UDH_DisableVoice,
+ UDH_DisableFax,
+ UDH_DisableEmail,
+ UDH_EnableVoice,
+ UDH_EnableFax,
+ UDH_EnableEmail,
+ UDH_VoidSMS,
+ UDH_NokiaRingtone,
+ UDH_NokiaRingtoneLong,
+ UDH_NokiaOperatorLogo,
+ UDH_NokiaOperatorLogoLong,
+ UDH_NokiaCallerLogo,
+ UDH_NokiaWAP,
+ UDH_NokiaWAPLong,
+ UDH_NokiaCalendarLong,
+ UDH_NokiaProfileLong,
+ UDH_NokiaPhonebookLong,
+ UDH_UserUDH,
+ UDH_MMSIndicatorLong
+} GSM_UDH;
+
+/**
+ * Structure for User Data Header.
+ */
+typedef struct {
+ /**
+ * UDH type.
+ */
+ GSM_UDH Type;
+ /**
+ * UDH length.
+ */
+ int Length;
+ /**
+ * UDH text.
+ */
+ unsigned char Text[GSM_MAX_UDH_LENGTH];
+ /**
+ * 8-bit ID, when required (-1 otherwise).
+ */
+ int ID8bit;
+ /**
+ * 16-bit ID, when required (-1 otherwise).
+ */
+ int ID16bit;
+ /**
+ * Number of current part.
+ */
+ int PartNumber;
+ /**
+ * Total number of parts.
+ */
+ int AllParts;
+} GSM_UDHHeader;
+
+/**
+ * TP-Message-Type-Indicator. See GSM 03.40 section 9.2.3.1.
+ */
+typedef enum {
+ /**
+ * SMS in Inbox.
+ */
+ SMS_Deliver = 1,
+ /**
+ * Delivery Report
+ */
+ SMS_Status_Report,
+ /**
+ * SMS for sending or in Outbox
+ */
+ SMS_Submit
+ /* specification gives more */
+} GSM_SMSMessageType;
+
+/**
+ * Maximal length of SMS name.
+ */
+#define GSM_MAX_SMS_NAME_LENGTH 40
+
+/**
+ * SMS message data.
+ */
+typedef struct {
+ /**
+ * Message to be replaced.
+ */
+ unsigned char ReplaceMessage;
+ /**
+ * Whether to reject duplicates.
+ */
+ bool RejectDuplicates;
+ /**
+ * UDH (User Data Header)
+ */
+ GSM_UDHHeader UDH;
+ /**
+ * Sender or recipient number.
+ */
+ unsigned char Number[(GSM_MAX_NUMBER_LENGTH+1)*2];
+ /**
+ * SMSC (SMS Center)
+ */
+ GSM_SMSC SMSC;
+ /**
+ * For saved SMS: where exactly it's saved (SIM/phone)
+ */
+ GSM_MemoryType Memory;
+ /**
+ * For saved SMS: location of SMS in memory.
+ */
+ int Location;
+ /**
+ * For saved SMS: number of folder, where SMS is saved
+ */
+ int Folder;
+ /**
+ * For saved SMS: whether SMS is really in Inbox.
+ */
+ bool InboxFolder;
+ /**
+ * Length of the SMS message.
+ */
+ int Length;
+ /**
+ * Status (read/unread/...) of SMS message.
+ */
+ GSM_SMS_State State;
+ /**
+ * Name in Nokia with SMS memory (6210/7110, etc.) Ignored in other.
+ */
+ unsigned char Name[(GSM_MAX_SMS_NAME_LENGTH+1)*2];
+ /**
+ * Text for SMS.
+ */
+ unsigned char Text[(GSM_MAX_SMS_LENGTH+1)*2];
+ /**
+ * Type of message.
+ */
+ GSM_SMSMessageType PDU;
+ /**
+ * Type of coding.
+ */
+ GSM_Coding_Type Coding;
+ /**
+ * Date and time, when SMS was saved or sent
+ */
+ GSM_DateTime DateTime;
+ /**
+ * Date of SMSC response in DeliveryReport messages.
+ */
+ GSM_DateTime SMSCTime;
+ /**
+ * In delivery reports: status.
+ */
+ unsigned char DeliveryStatus;
+ /**
+ * Indicates whether "Reply via same center" is set.
+ */
+ bool ReplyViaSameSMSC;
+ /**
+ * SMS class.
+ */
+ char Class;
+ /**
+ * Message reference.
+ */
+ unsigned char MessageReference;
+} GSM_SMSMessage;
+
+/* In layouts are saved locations for some SMS part. Below are listed
+ * specs, which describe them
+ */
+typedef struct {
+ /**
+ * TP-User-Data. GSM 03.40 section 9.2.3.24.
+ */
+ unsigned char Text;
+ /**
+ * - In SMS-Deliver: TP-Originating-Address. GSM 03.40 section 9.2.3.7.
+ * - In SMS-Submit: TP-Destination-Address. GSM 03.40 section 9.2.3.8.
+ * - In SMS-Status-Report: TP-Recipient-Address. GSM 03.40 section 9.2.3.14.
+ */
+ unsigned char Number;
+ /**
+ * SMSC number
+ */
+ unsigned char SMSCNumber;
+ /**
+ * TP-Data-Coding-Scheme. GSM 03.40 section 9.2.3.10
+ */
+ unsigned char TPDCS;
+ /**
+ * - For SMS-Submit: TP-Validity-Period. GSM 03.40 section 9.2.3.12.
+ * - For SMS-Status-Report: TP-Discharge Time. GSM 03.40 section 9.2.3.13.
+ */
+ unsigned char DateTime;
+ /**
+ * TP-Service-Centre-Time-Stamp in SMS-Status-Report. GSM 03.40 section 9.2.3.11.
+ */
+ unsigned char SMSCTime;
+ /**
+ * TP-Status in SMS-Status-Report. GSM 03.40 section 9.2.3.15.
+ */
+ unsigned char TPStatus;
+ /**
+ * TP-User-Data-Length. GSM 03.40 section 9.2.3.16.
+ */
+ unsigned char TPUDL;
+ /**
+ * TP-Validity Period in SMS-Submit. GSM 03.40 section 9.2.3.12.
+ */
+ unsigned char TPVP;
+ /**
+ * Byte contains in SMS-Deliver:
+ * - TP-Message-Type-Indicator (2 bits) GSM 03.40 section 9.2.3.1
+ * - TP-More-Messages-To-Send (1 bit). GSM 03.40 section 9.2.3.2
+ * - TP-Reply-Path (1 bit). GSM 03.40 section 9.2.3.17
+ * - TP-User-Data-Header-Indicator (1 bit). GSM 03.40 section 9.2.3.23
+ * - TP-Status-Report-Indicator (1 bit). GSM 03.40 section 9.2.3.4
+ *
+ * Byte contains in SMS-Submit:
+ * - TP-Message-Type-Indicator (2 bits) GSM 03.40 section 9.2.3.1
+ * - TP-Reject-Duplicates (1 bit). GSM 03.40 section
+ * - TP-Validity-Period-Format (2 bits).GSM 03.40 section 9.2.3.3
+ * - TP-Reply-Path (1 bit). GSM 03.40 section 9.2.3.17
+ * - TP-User-Data-Header-Indicator (1 bit). GSM 03.40 section 9.2.3.23
+ * - TP-Status-Report-Request (1 bit). GSM 03.40 section 9.2.3.5
+ */
+ unsigned char firstbyte;
+ /**
+ * TP-Message Reference in SMS-Submit. GSM 03.40 section 9.2.3.6
+ */
+ unsigned char TPMR;
+ /**
+ * TP-Protocol-Identifier. GSM 03.40 section 9.2.3.9
+ */
+ unsigned char TPPID;
+} GSM_SMSMessageLayout;
+
+GSM_Error GSM_DecodeSMSFrame(GSM_SMSMessage *SMS, unsigned char *buffer, GSM_SMSMessageLayout Layout);
+GSM_Error GSM_EncodeSMSFrame(GSM_SMSMessage *SMS, unsigned char *buffer, GSM_SMSMessageLayout Layout, int *length, bool clear);
+
+GSM_Error GSM_DecodeSMSFrameStatusReportData (GSM_SMSMessage *SMS, unsigned char *buffer, GSM_SMSMessageLayout Layout);
+GSM_Error GSM_DecodeSMSFrameText (GSM_SMSMessage *SMS, unsigned char *buffer, GSM_SMSMessageLayout Layout);
+
+void GSM_DecodeUDHHeader(GSM_UDHHeader *UDH);
+void GSM_EncodeUDHHeader(GSM_UDHHeader *UDH);
+
+void GSM_SetDefaultSMSData(GSM_SMSMessage *SMS);
+
+/* ---------------------- SMS folders ------------------------------------- */
+
+/**
+ * Number of possible SMS folders.
+ */
+#define GSM_MAX_SMS_FOLDERS 24
+/**
+ * Maximal length of SMS folder name.
+ */
+#define GSM_MAX_SMS_FOLDER_NAME_LEN 20
+
+/**
+ * Information about SMS folder.
+ */
+typedef struct {
+ /**
+ * Whether it is really inbox.
+ */
+ bool InboxFolder;
+ /**
+ * Where exactly it's saved
+ */
+ GSM_MemoryType Memory;
+ /**
+ * Name for SMS folder.
+ */
+ char Name[(GSM_MAX_SMS_FOLDER_NAME_LEN+1)*2];
+} GSM_OneSMSFolder;
+
+/**
+ * List of SMS folders.
+ */
+typedef struct {
+ /**
+ * Array of structures holding information about each folder.
+ */
+ GSM_OneSMSFolder Folder[GSM_MAX_SMS_FOLDERS];
+ /**
+ * Number of SMS folders.
+ */
+ unsigned char Number;
+} GSM_SMSFolders;
+
+#endif
+
+/* How should editor hadle tabs in this file? Add editor commands here.
+ * vim: noexpandtab sw=8 ts=8 sts=8:
+ */