author | zautrix <zautrix> | 2004-08-07 17:24:40 (UTC) |
---|---|---|
committer | zautrix <zautrix> | 2004-08-07 17:24:40 (UTC) |
commit | 88b0d33b8b0b1f6ae320cfc863ca6a47fa8fec22 (patch) (unidiff) | |
tree | 6331418973714243beb674abc87692277b83869d /gammu/emb/common/service/sms | |
parent | ef8a09ce74ad3f0a51484d03fdf009bd5b3677bf (diff) | |
download | kdepimpi-88b0d33b8b0b1f6ae320cfc863ca6a47fa8fec22.zip kdepimpi-88b0d33b8b0b1f6ae320cfc863ca6a47fa8fec22.tar.gz kdepimpi-88b0d33b8b0b1f6ae320cfc863ca6a47fa8fec22.tar.bz2 |
Initial revision
Diffstat (limited to 'gammu/emb/common/service/sms') (more/less context) (ignore whitespace changes)
-rw-r--r-- | gammu/emb/common/service/sms/gsmems.c | 765 | ||||
-rw-r--r-- | gammu/emb/common/service/sms/gsmems.h | 20 | ||||
-rw-r--r-- | gammu/emb/common/service/sms/gsmmulti.c | 1148 | ||||
-rw-r--r-- | gammu/emb/common/service/sms/gsmmulti.h | 271 | ||||
-rw-r--r-- | gammu/emb/common/service/sms/gsmsms.c | 663 | ||||
-rw-r--r-- | gammu/emb/common/service/sms/gsmsms.h | 492 |
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 @@ | |||
1 | /* (c) 2002-2004 by Marcin Wiacek */ | ||
2 | |||
3 | #include <ctype.h> | ||
4 | #include <string.h> | ||
5 | #include <time.h> | ||
6 | |||
7 | #include "../../gsmcomon.h" | ||
8 | #include "../../misc/coding/coding.h" | ||
9 | #include "../gsmcal.h" | ||
10 | #include "../gsmpbk.h" | ||
11 | #include "../gsmlogo.h" | ||
12 | #include "../gsmring.h" | ||
13 | #include "../gsmdata.h" | ||
14 | #include "../gsmnet.h" | ||
15 | #include "gsmsms.h" | ||
16 | #include "gsmmulti.h" | ||
17 | |||
18 | /* EMS Developers' Guidelines from www.sonyericsson.com | ||
19 | * docs from Alcatel | ||
20 | */ | ||
21 | GSM_Error GSM_EncodeEMSMultiPartSMS(GSM_MultiPartSMSInfo *Info, | ||
22 | GSM_MultiSMSMessage *SMS, | ||
23 | GSM_UDH UDHType) | ||
24 | { | ||
25 | unsigned char Buffer[GSM_MAX_SMS_LENGTH*2*MAX_MULTI_SMS]; | ||
26 | int i,UsedText,j,Length,Width,Height,z,x,y; | ||
27 | unsigned int Len; | ||
28 | int Used,FreeText,FreeBytes,Width2,CopiedText,CopiedSMSText; | ||
29 | unsigned char UDHID; | ||
30 | GSM_Bitmap Bitmap,Bitmap2; | ||
31 | GSM_Ringtone Ring; | ||
32 | GSM_Coding_Type Coding = SMS_Coding_Default; | ||
33 | GSM_Phone_Bitmap_TypesBitmapType; | ||
34 | MultiPartSMSEntry *Entry; | ||
35 | bool start; | ||
36 | GSM_DateTime Date; | ||
37 | |||
38 | #ifdef DEBUG | ||
39 | if (UDHType != UDH_NoUDH) dbgprintf("linked EMS\n"); | ||
40 | #endif | ||
41 | |||
42 | if (Info->UnicodeCoding) Coding = SMS_Coding_Unicode; | ||
43 | |||
44 | /* Cleaning on the start */ | ||
45 | for (i=0;i<MAX_MULTI_SMS;i++) { | ||
46 | GSM_SetDefaultSMSData(&SMS->SMS[i]); | ||
47 | SMS->SMS[i].UDH.Type = UDHType; | ||
48 | GSM_EncodeUDHHeader(&SMS->SMS[i].UDH); | ||
49 | SMS->SMS[i].Coding = Coding; | ||
50 | } | ||
51 | |||
52 | /* Packing */ | ||
53 | for (i=0;i<Info->EntriesNum;i++) { | ||
54 | Entry = &Info->Entries[i]; | ||
55 | |||
56 | switch (Entry->ID) { | ||
57 | case SMS_ConcatenatedTextLong: | ||
58 | case SMS_ConcatenatedTextLong16bit: | ||
59 | Len = 0; | ||
60 | while(1) { | ||
61 | if (Entry->Left || Entry->Right || | ||
62 | Entry->Center || Entry->Large || | ||
63 | Entry->Small || Entry->Bold || | ||
64 | Entry->Italic || Entry->Underlined || | ||
65 | Entry->Strikethrough) { | ||
66 | Buffer[0] = 0x0A;/* ID for text format */ | ||
67 | Buffer[1] = 0x03; /* length of rest*/ | ||
68 | Buffer[2] = 0x00; /* Position in EMS msg*/ | ||
69 | Buffer[3] = 0x00; /* how many chars */ | ||
70 | Buffer[4] = 0x00; /* formatting bits*/ | ||
71 | if (Entry->Left) { | ||
72 | } else if (Entry->Right) {Buffer[4] |= 1; | ||
73 | } else if (Entry->Center) {Buffer[4] |= 2; | ||
74 | } else Buffer[4] |= 3; | ||
75 | if (Entry->Large) { Buffer[4] |= 4; | ||
76 | } else if (Entry->Small) {Buffer[4] |= 8;} | ||
77 | if (Entry->Bold) Buffer[4] |= 16; | ||
78 | if (Entry->Italic) Buffer[4] |= 32; | ||
79 | if (Entry->Underlined) Buffer[4] |= 64; | ||
80 | if (Entry->Strikethrough) Buffer[4] |= 128; | ||
81 | GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,5,true,&UsedText,&CopiedText,&CopiedSMSText); | ||
82 | GSM_Find_Free_Used_SMS2(Coding,SMS->SMS[SMS->Number], &UsedText, &FreeText, &FreeBytes); | ||
83 | if (FreeText == 0) continue; | ||
84 | } | ||
85 | GSM_AddSMS_Text_UDH(SMS,Coding,Entry->Buffer+Len*2,UnicodeLength(Entry->Buffer) - Len,false,&UsedText,&CopiedText,&CopiedSMSText); | ||
86 | if (Entry->Left || Entry->Right || | ||
87 | Entry->Center || Entry->Large || | ||
88 | Entry->Small || Entry->Bold || | ||
89 | Entry->Italic || Entry->Underlined || | ||
90 | Entry->Strikethrough) { | ||
91 | SMS->SMS[SMS->Number].UDH.Text[SMS->SMS[SMS->Number].UDH.Length-3] = UsedText; | ||
92 | SMS->SMS[SMS->Number].UDH.Text[SMS->SMS[SMS->Number].UDH.Length-2] = CopiedSMSText; | ||
93 | } | ||
94 | Len += CopiedText; | ||
95 | if (Len == UnicodeLength(Entry->Buffer)) break; | ||
96 | dbgprintf("%i %i\n",Len,UnicodeLength(Entry->Buffer)); | ||
97 | } | ||
98 | break; | ||
99 | case SMS_EMSPredefinedSound: | ||
100 | case SMS_EMSPredefinedAnimation: | ||
101 | if (Entry->ID == SMS_EMSPredefinedSound) { | ||
102 | Buffer[0] = 0x0B; /* ID for def.sound*/ | ||
103 | } else { | ||
104 | Buffer[0] = 0x0D; /* ID for def.animation*/ | ||
105 | } | ||
106 | Buffer[1] = 0x02; /* Length of rest */ | ||
107 | Buffer[2] = 0x00; /* Position in EMS msg*/ | ||
108 | Buffer[3] = Entry->Number; /* Number of anim.*/ | ||
109 | GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,4,true,&UsedText,&CopiedText,&CopiedSMSText); | ||
110 | SMS->SMS[SMS->Number].UDH.Text[SMS->SMS[SMS->Number].UDH.Length-2] = UsedText; | ||
111 | break; | ||
112 | case SMS_EMSSonyEricssonSound: | ||
113 | case SMS_EMSSound10: | ||
114 | case SMS_EMSSound12: | ||
115 | if (Entry->Protected) { | ||
116 | Buffer[0] = 0x17; /* ID for ODI */ | ||
117 | Buffer[1] = 2; /* Length of rest */ | ||
118 | Buffer[2] = 1; /* Number of protected objects */ | ||
119 | Buffer[3] = 1; /* 1=Protected,0=Not protected */ | ||
120 | GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,4,true,&UsedText,&CopiedText,&CopiedSMSText); | ||
121 | } | ||
122 | |||
123 | Length = 128; /* 128 bytes is maximal length from specs */ | ||
124 | switch (Entry->ID) { | ||
125 | case SMS_EMSSound10: | ||
126 | Entry->RingtoneNotes = GSM_EncodeEMSSound(*Entry->Ringtone, Buffer+3, &Length, 1.0, true); | ||
127 | break; | ||
128 | case SMS_EMSSound12: | ||
129 | Entry->RingtoneNotes = GSM_EncodeEMSSound(*Entry->Ringtone, Buffer+3, &Length, 1.2, true); | ||
130 | break; | ||
131 | case SMS_EMSSonyEricssonSound: | ||
132 | Entry->RingtoneNotes = GSM_EncodeEMSSound(*Entry->Ringtone, Buffer+3, &Length, 0, true); | ||
133 | break; | ||
134 | default: | ||
135 | break; | ||
136 | } | ||
137 | |||
138 | Buffer[0] = 0x0C; /* ID for EMS sound */ | ||
139 | Buffer[1] = Length+1; /* Length of rest */ | ||
140 | Buffer[2] = 0x00; /* Position in EMS msg */ | ||
141 | GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,Length+3,true,&UsedText,&CopiedText,&CopiedSMSText); | ||
142 | SMS->SMS[SMS->Number].UDH.Text[SMS->SMS[SMS->Number].UDH.Length-Length-1] = UsedText; | ||
143 | break; | ||
144 | case SMS_EMSSonyEricssonSoundLong: | ||
145 | case SMS_EMSSound10Long: | ||
146 | case SMS_EMSSound12Long: | ||
147 | Ring = *Entry->Ringtone; | ||
148 | |||
149 | /* First check if we can use classic format */ | ||
150 | Length = 128; /* 128 bytes is maximal length from specs */ | ||
151 | switch (Entry->ID) { | ||
152 | case SMS_EMSSound10Long: | ||
153 | Entry->RingtoneNotes = GSM_EncodeEMSSound(Ring, Buffer+3, &Length, 1.0, true); | ||
154 | break; | ||
155 | case SMS_EMSSound12Long: | ||
156 | Entry->RingtoneNotes = GSM_EncodeEMSSound(Ring, Buffer+3, &Length, 1.2, true); | ||
157 | break; | ||
158 | case SMS_EMSSonyEricssonSoundLong: | ||
159 | Entry->RingtoneNotes = GSM_EncodeEMSSound(Ring, Buffer+3, &Length, 0, true); | ||
160 | break; | ||
161 | default: | ||
162 | break; | ||
163 | } | ||
164 | if (Entry->RingtoneNotes == Ring.NoteTone.NrCommands) { | ||
165 | if (Entry->Protected) { | ||
166 | Buffer[0] = 0x17; /* ID for ODI */ | ||
167 | Buffer[1] = 2; /* Length of rest */ | ||
168 | Buffer[2] = 1; /* Number of protected objects */ | ||
169 | Buffer[3] = 1; /* 1=Protected,0=Not protected */ | ||
170 | GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,4,true,&UsedText,&CopiedText,&CopiedSMSText); | ||
171 | } | ||
172 | |||
173 | Buffer[0] = 0x0C; /* ID for EMS sound */ | ||
174 | Buffer[1] = Length+1; /* Length of rest */ | ||
175 | Buffer[2] = 0x00; /* Position in EMS msg */ | ||
176 | GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,Length+3,true,&UsedText,&CopiedText,&CopiedSMSText); | ||
177 | SMS->SMS[SMS->Number].UDH.Text[SMS->SMS[SMS->Number].UDH.Length-Length-1] = UsedText; | ||
178 | break; | ||
179 | } | ||
180 | |||
181 | /* Find free place in first SMS */ | ||
182 | GSM_Find_Free_Used_SMS2(Coding,SMS->SMS[SMS->Number], &UsedText, &FreeText, &FreeBytes); | ||
183 | Length = FreeBytes - 3; | ||
184 | if (Entry->Protected) Length = Length - 4; | ||
185 | if (Length < 0) Length = 128; | ||
186 | if (Length > 128) Length = 128; | ||
187 | |||
188 | Ring = *Entry->Ringtone; | ||
189 | |||
190 | /* Checking number of SMS */ | ||
191 | Used = 0; | ||
192 | FreeBytes = 0; | ||
193 | start = true; | ||
194 | while (1) { | ||
195 | if (FreeBytes != 0) { | ||
196 | z = 0; | ||
197 | for (j=FreeBytes;j<Ring.NoteTone.NrCommands;j++) { | ||
198 | Ring.NoteTone.Commands[z] = Ring.NoteTone.Commands[j]; | ||
199 | z++; | ||
200 | } | ||
201 | Ring.NoteTone.NrCommands -= FreeBytes; | ||
202 | if (Ring.NoteTone.NrCommands == 0) break; | ||
203 | Length = 128; /* 128 bytes is maximal length from specs */ | ||
204 | } | ||
205 | switch (Entry->ID) { | ||
206 | case SMS_EMSSound10Long: | ||
207 | FreeBytes = GSM_EncodeEMSSound(Ring, Buffer+3, &Length, 1.0, start); | ||
208 | break; | ||
209 | case SMS_EMSSound12Long: | ||
210 | FreeBytes = GSM_EncodeEMSSound(Ring, Buffer+3, &Length, 1.2, start); | ||
211 | break; | ||
212 | case SMS_EMSSonyEricssonSoundLong: | ||
213 | FreeBytes = GSM_EncodeEMSSound(Ring, Buffer+3, &Length, 0, start); | ||
214 | break; | ||
215 | default: | ||
216 | break; | ||
217 | } | ||
218 | start = false; | ||
219 | Used++; | ||
220 | } | ||
221 | dbgprintf("Used SMS: %i\n",Used); | ||
222 | |||
223 | if (Entry->Protected) { | ||
224 | Buffer[0] = 0x17; /* ID for ODI */ | ||
225 | Buffer[1] = 2; /* Length of rest */ | ||
226 | Buffer[2] = Used+1; /* Number of protected objects */ | ||
227 | Buffer[3] = 1; /* 1=Protected,0=Not protected */ | ||
228 | GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,4,true,&UsedText,&CopiedText,&CopiedSMSText); | ||
229 | } | ||
230 | |||
231 | /* Save UPI UDH */ | ||
232 | Buffer[0] = 0x13; /* ID for UPI */ | ||
233 | Buffer[1] = 1; /* Length of rest */ | ||
234 | Buffer[2] = Used; /* Number of used parts*/ | ||
235 | GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,3,true,&UsedText,&CopiedText,&CopiedSMSText); | ||
236 | |||
237 | /* Find free place in first SMS */ | ||
238 | GSM_Find_Free_Used_SMS2(Coding,SMS->SMS[SMS->Number], &UsedText, &FreeText, &FreeBytes); | ||
239 | Length = FreeBytes - 3; | ||
240 | if (Length < 0) Length = 128; | ||
241 | if (Length > 128) Length = 128; | ||
242 | |||
243 | Ring = *Entry->Ringtone; | ||
244 | |||
245 | /* Saving */ | ||
246 | FreeBytes = 0; | ||
247 | start = true; | ||
248 | while (1) { | ||
249 | if (FreeBytes != 0) { | ||
250 | z = 0; | ||
251 | for (j=FreeBytes;j<Ring.NoteTone.NrCommands;j++) { | ||
252 | Ring.NoteTone.Commands[z] = Ring.NoteTone.Commands[j]; | ||
253 | z++; | ||
254 | } | ||
255 | Ring.NoteTone.NrCommands -= FreeBytes; | ||
256 | if (Ring.NoteTone.NrCommands == 0) break; | ||
257 | Length = 128; /* 128 bytes is maximal length from specs */ | ||
258 | } | ||
259 | switch (Entry->ID) { | ||
260 | case SMS_EMSSound10Long: | ||
261 | FreeBytes = GSM_EncodeEMSSound(Ring, Buffer+3, &Length, 1.0, start); | ||
262 | break; | ||
263 | case SMS_EMSSound12Long: | ||
264 | FreeBytes = GSM_EncodeEMSSound(Ring, Buffer+3, &Length, 1.2, start); | ||
265 | break; | ||
266 | case SMS_EMSSonyEricssonSoundLong: | ||
267 | FreeBytes = GSM_EncodeEMSSound(Ring, Buffer+3, &Length, 0, start); | ||
268 | break; | ||
269 | default: | ||
270 | break; | ||
271 | } | ||
272 | Buffer[0] = 0x0C; /* ID for EMS sound */ | ||
273 | Buffer[1] = Length+1; /* Length of rest */ | ||
274 | Buffer[2] = 0x00; /* Position in EMS msg */ | ||
275 | GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,Length+3,true,&UsedText,&CopiedText,&CopiedSMSText); | ||
276 | SMS->SMS[SMS->Number].UDH.Text[SMS->SMS[SMS->Number].UDH.Length-Length-1] = UsedText; | ||
277 | start = false; | ||
278 | } | ||
279 | |||
280 | Entry->RingtoneNotes = Entry->Ringtone->NoteTone.NrCommands; | ||
281 | |||
282 | break; | ||
283 | case SMS_EMSAnimation: | ||
284 | if (Entry->Protected) { | ||
285 | Buffer[0] = 0x17; /* ID for ODI */ | ||
286 | Buffer[1] = 2; /* Length of rest */ | ||
287 | Buffer[2] = 1; /* Number of protected objects */ | ||
288 | Buffer[3] = 1; /* 1=Protected,0=Not protected */ | ||
289 | GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,4,true,&UsedText,&CopiedText,&CopiedSMSText); | ||
290 | } | ||
291 | |||
292 | if (Entry->Bitmap->Bitmap[0].BitmapWidth > 8 || Entry->Bitmap->Bitmap[0].BitmapHeight > 8) { | ||
293 | BitmapType = GSM_EMSMediumPicture;/* Bitmap 16x16 */ | ||
294 | Buffer[0] = 0x0E; /* ID for 16x16 animation */ | ||
295 | } else { | ||
296 | BitmapType = GSM_EMSSmallPicture;/* Bitmap 8x8 */ | ||
297 | Buffer[0] = 0x0F; /* ID for 8x8 animation */ | ||
298 | } | ||
299 | Length = PHONE_GetBitmapSize(BitmapType,0,0); | ||
300 | |||
301 | Buffer[1] = Length*Entry->Bitmap->Number + 1; /* Length of rest */ | ||
302 | Buffer[2] = 0x00; /* Position in EMS msg */ | ||
303 | for (j=0;j<Entry->Bitmap->Number;j++) { | ||
304 | PHONE_EncodeBitmap(BitmapType, Buffer+3+j*Length, &Entry->Bitmap->Bitmap[j]); | ||
305 | } | ||
306 | GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,3+Length*Entry->Bitmap->Number,true,&UsedText,&CopiedText,&CopiedSMSText); | ||
307 | SMS->SMS[SMS->Number].UDH.Text[SMS->SMS[SMS->Number].UDH.Length-1-Length*Entry->Bitmap->Number] = UsedText; | ||
308 | break; | ||
309 | case SMS_EMSFixedBitmap: | ||
310 | if (Entry->Protected) { | ||
311 | Buffer[0] = 0x17; /* ID for ODI */ | ||
312 | Buffer[1] = 2; /* Length of rest */ | ||
313 | Buffer[2] = 1; /* Number of protected objects */ | ||
314 | Buffer[3] = 1; /* 1=Protected,0=Not protected */ | ||
315 | GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,4,true,&UsedText,&CopiedText,&CopiedSMSText); | ||
316 | } | ||
317 | |||
318 | if (Entry->Bitmap->Bitmap[0].BitmapWidth > 16 || Entry->Bitmap->Bitmap[0].BitmapHeight > 16) { | ||
319 | BitmapType = GSM_EMSBigPicture; /* Bitmap 32x32 */ | ||
320 | Buffer[0] = 0x10; /* ID for EMS bitmap*/ | ||
321 | } else { | ||
322 | BitmapType = GSM_EMSMediumPicture; /* Bitmap 16x16 */ | ||
323 | Buffer[0] = 0x11; /* ID for EMS bitmap*/ | ||
324 | } | ||
325 | Length = PHONE_GetBitmapSize(BitmapType,0,0); | ||
326 | PHONE_GetBitmapWidthHeight(BitmapType, &Width, &Height); | ||
327 | |||
328 | Buffer[1] = Length + 1; /* Length of rest */ | ||
329 | Buffer[2] = 0x00; /* Position in EMS msg*/ | ||
330 | PHONE_EncodeBitmap(BitmapType,Buffer+3, &Entry->Bitmap->Bitmap[0]); | ||
331 | GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,3+Length,true,&UsedText,&CopiedText,&CopiedSMSText); | ||
332 | SMS->SMS[SMS->Number].UDH.Text[SMS->SMS[SMS->Number].UDH.Length-1-Length] = UsedText; | ||
333 | break; | ||
334 | case SMS_EMSVariableBitmapLong: | ||
335 | BitmapType = GSM_EMSVariablePicture; | ||
336 | Width = Entry->Bitmap->Bitmap[0].BitmapWidth; | ||
337 | Height = Entry->Bitmap->Bitmap[0].BitmapHeight; | ||
338 | Bitmap = Entry->Bitmap->Bitmap[0]; | ||
339 | |||
340 | /* First check if we can use classical format */ | ||
341 | while (1) { | ||
342 | /* Width should be multiply of 8 */ | ||
343 | while (Width % 8 != 0) Width--; | ||
344 | |||
345 | /* specs */ | ||
346 | if (Width <= 96 && Height <= 128) break; | ||
347 | |||
348 | Height--; | ||
349 | } | ||
350 | Length = PHONE_GetBitmapSize(BitmapType,Width,Height); | ||
351 | if (Length <= 128) { | ||
352 | if (Entry->Protected) { | ||
353 | Buffer[0] = 0x17; /* ID for ODI */ | ||
354 | Buffer[1] = 2; /* Length of rest */ | ||
355 | Buffer[2] = 1; /* Number of protected objects */ | ||
356 | Buffer[3] = 1; /* 1=Protected,0=Not protected */ | ||
357 | GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,4,true,&UsedText,&CopiedText,&CopiedSMSText); | ||
358 | } | ||
359 | |||
360 | Buffer[0] = 0x12; /* ID for EMS bitmap*/ | ||
361 | Buffer[1] = Length + 3; /* Length of rest */ | ||
362 | Buffer[2] = 0x00; /* Position in EMS msg*/ | ||
363 | Buffer[3] = Width/8; /* Bitmap width/8 */ | ||
364 | Buffer[4] = Height; /* Bitmap height */ | ||
365 | |||
366 | GSM_ResizeBitmap(&Bitmap, &Entry->Bitmap->Bitmap[0], Width, Height); | ||
367 | #ifdef DEBUG | ||
368 | if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) GSM_PrintBitmap(di.df,&Bitmap); | ||
369 | #endif | ||
370 | PHONE_EncodeBitmap(BitmapType,Buffer+5, &Bitmap); | ||
371 | GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,5+Length,true,&UsedText,&CopiedText,&CopiedSMSText); | ||
372 | SMS->SMS[SMS->Number].UDH.Text[SMS->SMS[SMS->Number].UDH.Length-3-Length] = UsedText; | ||
373 | break; | ||
374 | } | ||
375 | |||
376 | /* Find free place in first SMS */ | ||
377 | GSM_Find_Free_Used_SMS2(Coding,SMS->SMS[SMS->Number], &UsedText, &FreeText, &FreeBytes); | ||
378 | Used = 0; | ||
379 | Length = FreeBytes - 3; | ||
380 | if (Entry->Protected)Length = Length - 4; | ||
381 | if (Length < 0) Length = 128; | ||
382 | if (Length > 128) Length = 128; | ||
383 | |||
384 | /* Checking number of SMS */ | ||
385 | FreeBytes = 0; | ||
386 | while (FreeBytes != Width) { | ||
387 | Width2 = 8; | ||
388 | while (FreeBytes + Width2 != Width) { | ||
389 | if (PHONE_GetBitmapSize(BitmapType,Width2+8,Height) > Length) break; | ||
390 | |||
391 | Width2 = Width2 + 8; | ||
392 | } | ||
393 | FreeBytes = FreeBytes + Width2; | ||
394 | Length = 128; | ||
395 | Used ++; | ||
396 | } | ||
397 | dbgprintf("Used SMS: %i\n",Used); | ||
398 | |||
399 | if (Entry->Protected) { | ||
400 | Buffer[0] = 0x17; /* ID for ODI */ | ||
401 | Buffer[1] = 2; /* Length of rest */ | ||
402 | Buffer[2] = Used+1; /* Number of protected objects */ | ||
403 | Buffer[3] = 1; /* 1=Protected,0=Not protected */ | ||
404 | GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,4,true,&UsedText,&CopiedText,&CopiedSMSText); | ||
405 | } | ||
406 | |||
407 | /* Save UPI UDH */ | ||
408 | Buffer[0] = 0x13; /* ID for UPI */ | ||
409 | Buffer[1] = 1; /* Length of rest */ | ||
410 | Buffer[2] = Used; /* Number of used parts*/ | ||
411 | |||
412 | /* Find free place in first SMS */ | ||
413 | GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,3,true,&UsedText,&CopiedText,&CopiedSMSText); | ||
414 | GSM_Find_Free_Used_SMS2(Coding,SMS->SMS[SMS->Number], &UsedText, &FreeText, &FreeBytes); | ||
415 | Length = FreeBytes - 3; | ||
416 | if (Length < 0) Length = 128; | ||
417 | if (Length > 128) Length = 128; | ||
418 | |||
419 | #ifdef DEBUG | ||
420 | if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) GSM_PrintBitmap(di.df,&Bitmap); | ||
421 | #endif | ||
422 | |||
423 | /* Saving SMS */ | ||
424 | FreeBytes = 0; | ||
425 | while (FreeBytes != Width) { | ||
426 | Width2 = 8; | ||
427 | while (FreeBytes + Width2 != Width) { | ||
428 | if (PHONE_GetBitmapSize(BitmapType,Width2+8,Height) > Length) break; | ||
429 | |||
430 | Width2 = Width2 + 8; | ||
431 | } | ||
432 | |||
433 | /* Copying part of bitmap to new structure */ | ||
434 | Bitmap2.BitmapWidth = Width2; | ||
435 | Bitmap2.BitmapHeight = Height; | ||
436 | GSM_ClearBitmap(&Bitmap2); | ||
437 | for (x=0;x<Width2;x++) { | ||
438 | for (y=0;y<Height;y++) { | ||
439 | if (GSM_IsPointBitmap(&Bitmap,x+FreeBytes,y)) { | ||
440 | GSM_SetPointBitmap(&Bitmap2, x, y); | ||
441 | } | ||
442 | } | ||
443 | } | ||
444 | #ifdef DEBUG | ||
445 | if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) GSM_PrintBitmap(di.df,&Bitmap2); | ||
446 | #endif | ||
447 | |||
448 | /* Adding new bitmap to SMS */ | ||
449 | Length = PHONE_GetBitmapSize(BitmapType,Width2,Height); | ||
450 | Buffer[0] = 0x12; /* ID for EMS bitmap*/ | ||
451 | Buffer[1] = Length + 3; /* Length of rest */ | ||
452 | Buffer[2] = 0x00; /* Position in EMS msg*/ | ||
453 | Buffer[3] = Width2/8; /* Bitmap width/8 */ | ||
454 | Buffer[4] = Height; /* Bitmap height */ | ||
455 | PHONE_EncodeBitmap(BitmapType,Buffer+5, &Bitmap2); | ||
456 | GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,5+Length,true,&UsedText,&CopiedText,&CopiedSMSText); | ||
457 | SMS->SMS[SMS->Number].UDH.Text[SMS->SMS[SMS->Number].UDH.Length-3-Length] = UsedText; | ||
458 | |||
459 | FreeBytes = FreeBytes + Width2; | ||
460 | Length = 128; | ||
461 | } | ||
462 | break; | ||
463 | case SMS_EMSVariableBitmap: | ||
464 | if (Entry->Protected) { | ||
465 | Buffer[0] = 0x17; /* ID for ODI */ | ||
466 | Buffer[1] = 2; /* Length of rest */ | ||
467 | Buffer[2] = 1; /* Number of protected objects */ | ||
468 | Buffer[3] = 1; /* 1=Protected,0=Not protected */ | ||
469 | GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,4,true,&UsedText,&CopiedText,&CopiedSMSText); | ||
470 | } | ||
471 | |||
472 | BitmapType = GSM_EMSVariablePicture; | ||
473 | Width = Entry->Bitmap->Bitmap[0].BitmapWidth; | ||
474 | Height = Entry->Bitmap->Bitmap[0].BitmapHeight; | ||
475 | |||
476 | while (1) { | ||
477 | /* Width should be multiply of 8 */ | ||
478 | while (Width % 8 != 0) Width--; | ||
479 | |||
480 | /* specs */ | ||
481 | if (PHONE_GetBitmapSize(BitmapType,Width,Height) <= 128) break; | ||
482 | |||
483 | Height--; | ||
484 | } | ||
485 | |||
486 | Length = PHONE_GetBitmapSize(BitmapType,Width,Height); | ||
487 | |||
488 | Buffer[0] = 0x12; /* ID for EMS bitmap*/ | ||
489 | Buffer[1] = Length + 3; /* Length of rest */ | ||
490 | Buffer[2] = 0x00; /* Position in EMS msg*/ | ||
491 | Buffer[3] = Width/8; /* Bitmap width/8 */ | ||
492 | Buffer[4] = Height; /* Bitmap height */ | ||
493 | |||
494 | GSM_ResizeBitmap(&Bitmap, &Entry->Bitmap->Bitmap[0], Width, Height); | ||
495 | #ifdef DEBUG | ||
496 | if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) GSM_PrintBitmap(di.df,&Bitmap); | ||
497 | #endif | ||
498 | PHONE_EncodeBitmap(BitmapType,Buffer+5, &Bitmap); | ||
499 | GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,5+Length,true,&UsedText,&CopiedText,&CopiedSMSText); | ||
500 | SMS->SMS[SMS->Number].UDH.Text[SMS->SMS[SMS->Number].UDH.Length-3-Length] = UsedText; | ||
501 | break; | ||
502 | default: | ||
503 | break; | ||
504 | } | ||
505 | } | ||
506 | |||
507 | SMS->Number++; | ||
508 | |||
509 | if (UDHType == UDH_ConcatenatedMessages) { | ||
510 | UDHID = GSM_MakeSMSIDFromTime(); | ||
511 | for (i=0;i<SMS->Number;i++) { | ||
512 | SMS->SMS[i].UDH.Text[2+1] = UDHID; | ||
513 | SMS->SMS[i].UDH.Text[3+1] = SMS->Number; | ||
514 | SMS->SMS[i].UDH.Text[4+1] = i+1; | ||
515 | } | ||
516 | } | ||
517 | if (UDHType == UDH_ConcatenatedMessages16bit) { | ||
518 | UDHID = GSM_MakeSMSIDFromTime(); | ||
519 | GSM_GetCurrentDateTime (&Date); | ||
520 | for (i=0;i<SMS->Number;i++) { | ||
521 | SMS->SMS[i].UDH.Text[2+1] = Date.Hour; | ||
522 | SMS->SMS[i].UDH.Text[3+1] = UDHID; | ||
523 | SMS->SMS[i].UDH.Text[4+1] = SMS->Number; | ||
524 | SMS->SMS[i].UDH.Text[5+1] = i+1; | ||
525 | } | ||
526 | } | ||
527 | |||
528 | #ifdef DEBUG | ||
529 | dbgprintf("SMS number is %i\n",SMS->Number); | ||
530 | for (i=0;i<SMS->Number;i++) { | ||
531 | dbgprintf("UDH length %i\n",SMS->SMS[i].UDH.Length); | ||
532 | DumpMessage(di.df, di.dl, SMS->SMS[i].UDH.Text, SMS->SMS[i].UDH.Length); | ||
533 | dbgprintf("SMS length %i\n",UnicodeLength(SMS->SMS[i].Text)*2); | ||
534 | DumpMessage(di.df, di.dl, SMS->SMS[i].Text, UnicodeLength(SMS->SMS[i].Text)*2); | ||
535 | } | ||
536 | #endif | ||
537 | return ERR_NONE; | ||
538 | } | ||
539 | |||
540 | static bool AddEMSText(GSM_SMSMessage *SMS, GSM_MultiPartSMSInfo *Info, int *Pos, int Len) | ||
541 | { | ||
542 | int BufferLen; | ||
543 | |||
544 | if (Len==0) return true; | ||
545 | |||
546 | if (Info->Entries[Info->EntriesNum].ID!=SMS_ConcatenatedTextLong && | ||
547 | Info->Entries[Info->EntriesNum].ID!=0) { | ||
548 | (Info->EntriesNum)++; | ||
549 | } | ||
550 | BufferLen = UnicodeLength(Info->Entries[Info->EntriesNum].Buffer)*2; | ||
551 | switch (SMS->Coding) { | ||
552 | case SMS_Coding_8bit: | ||
553 | // memcpy(Info->Entries[Info->EntriesNum].Buffer+BufferLen,SMS->Text+(*Pos),Len); | ||
554 | // BufferLen+=Len; | ||
555 | // (*Pos)+=Len; | ||
556 | break; | ||
557 | case SMS_Coding_Unicode: | ||
558 | case SMS_Coding_Default: | ||
559 | Info->Entries[Info->EntriesNum].Buffer = realloc(Info->Entries[Info->EntriesNum].Buffer, BufferLen + (Len * 2) + 2); | ||
560 | if (Info->Entries[Info->EntriesNum].Buffer == NULL) return false; | ||
561 | memcpy(Info->Entries[Info->EntriesNum].Buffer + BufferLen, SMS->Text + (*Pos) *2, Len * 2); | ||
562 | BufferLen += Len * 2; | ||
563 | break; | ||
564 | } | ||
565 | (*Pos)+=Len; | ||
566 | Info->Entries[Info->EntriesNum].Buffer[BufferLen]= 0; | ||
567 | Info->Entries[Info->EntriesNum].Buffer[BufferLen+1]= 0; | ||
568 | Info->Entries[Info->EntriesNum].ID = SMS_ConcatenatedTextLong; | ||
569 | return true; | ||
570 | } | ||
571 | |||
572 | bool GSM_DecodeEMSMultiPartSMS(GSM_MultiPartSMSInfo *Info, | ||
573 | GSM_MultiSMSMessage *SMS) | ||
574 | { | ||
575 | int i, w, Pos, z, UPI = 1, width, height; | ||
576 | bool RetVal = false, NewPicture = true; | ||
577 | GSM_Phone_Bitmap_Types BitmapType; | ||
578 | GSM_Bitmap Bitmap,Bitmap2; | ||
579 | |||
580 | for (i=0;i<MAX_MULTI_SMS;i++) { | ||
581 | Info->Entries[i].ID = 0; | ||
582 | } | ||
583 | |||
584 | for (i=0;i<SMS->Number;i++) { | ||
585 | Pos = 0; | ||
586 | w= 1; | ||
587 | while (w < SMS->SMS[i].UDH.Length) { | ||
588 | if (Info->EntriesNum + 1 == MAX_MULTI_SMS) { | ||
589 | dbgprintf("Couldn't parse SMS, contains too many EMS parts!\n"); | ||
590 | return false; | ||
591 | } | ||
592 | switch(SMS->SMS[i].UDH.Text[w]) { | ||
593 | case 0x00: | ||
594 | dbgprintf("UDH part - linked SMS with 8 bit ID\n"); | ||
595 | break; | ||
596 | case 0x08: | ||
597 | dbgprintf("UDH part - linked SMS with 16 bit ID\n"); | ||
598 | break; | ||
599 | // case 0x0A: | ||
600 | // dbgprintf("UDH part - EMS text formatting\n"); | ||
601 | // break; | ||
602 | case 0x0B: | ||
603 | dbgprintf("UDH part - default EMS sound\n"); | ||
604 | if (SMS->SMS[i].UDH.Text[w+2] > Pos) { | ||
605 | z = Pos; | ||
606 | if (!AddEMSText(&SMS->SMS[i], Info, &Pos, SMS->SMS[i].UDH.Text[w+2]-z)) return false; | ||
607 | } | ||
608 | if (Info->Entries[Info->EntriesNum].ID != 0) (Info->EntriesNum)++; | ||
609 | Info->Entries[Info->EntriesNum].Number = SMS->SMS[i].UDH.Text[w+3]; | ||
610 | Info->Entries[Info->EntriesNum].ID = SMS_EMSPredefinedSound; | ||
611 | RetVal = true; | ||
612 | break; | ||
613 | // case 0x0C: | ||
614 | // dbgprintf("UDH part - EMS sound\n"); | ||
615 | // break; | ||
616 | case 0x0D: | ||
617 | dbgprintf("UDH part - default EMS animation\n"); | ||
618 | if (SMS->SMS[i].UDH.Text[w+2] > Pos) { | ||
619 | z = Pos; | ||
620 | if (!AddEMSText(&SMS->SMS[i], Info, &Pos, SMS->SMS[i].UDH.Text[w+2]-z)) return false; | ||
621 | } | ||
622 | if (Info->Entries[Info->EntriesNum].ID != 0) (Info->EntriesNum)++; | ||
623 | Info->Entries[Info->EntriesNum].Number = SMS->SMS[i].UDH.Text[w+3]; | ||
624 | Info->Entries[Info->EntriesNum].ID = SMS_EMSPredefinedAnimation; | ||
625 | RetVal = true; | ||
626 | break; | ||
627 | case 0x0E: | ||
628 | case 0x0F: | ||
629 | if (SMS->SMS[i].UDH.Text[w] == 0x0E) { | ||
630 | dbgprintf("UDH part - EMS 16x16 animation\n"); | ||
631 | BitmapType = GSM_EMSMediumPicture; | ||
632 | } else { | ||
633 | dbgprintf("UDH part - EMS 8x8 animation\n"); | ||
634 | BitmapType = GSM_EMSSmallPicture; | ||
635 | } | ||
636 | dbgprintf("Position - %i\n",SMS->SMS[i].UDH.Text[w+2]); | ||
637 | if (SMS->SMS[i].UDH.Text[w+2] > Pos) { | ||
638 | z = Pos; | ||
639 | if (!AddEMSText(&SMS->SMS[i], Info, &Pos, SMS->SMS[i].UDH.Text[w+2]-z)) return false; | ||
640 | } | ||
641 | (Info->EntriesNum)++; | ||
642 | Info->Entries[Info->EntriesNum].ID = SMS_EMSAnimation; | ||
643 | Info->Entries[Info->EntriesNum].Bitmap = (GSM_MultiBitmap *)malloc(sizeof(GSM_MultiBitmap)); | ||
644 | if (Info->Entries[Info->EntriesNum].Bitmap == NULL) return false; | ||
645 | Info->Entries[Info->EntriesNum].Bitmap->Number = 0; | ||
646 | for (z=0;z<((SMS->SMS[i].UDH.Text[w+1]-1)/PHONE_GetBitmapSize(BitmapType,0,0));z++) { | ||
647 | Info->Entries[Info->EntriesNum].Bitmap->Bitmap[z].Type = GSM_PictureImage; | ||
648 | PHONE_DecodeBitmap(BitmapType, | ||
649 | SMS->SMS[i].UDH.Text + w + 3 + PHONE_GetBitmapSize(BitmapType,0,0) * z, | ||
650 | &Info->Entries[Info->EntriesNum].Bitmap->Bitmap[z]); | ||
651 | Info->Entries[Info->EntriesNum].Bitmap->Number++; | ||
652 | } | ||
653 | RetVal = true; | ||
654 | break; | ||
655 | case 0x10: | ||
656 | case 0x11: | ||
657 | if (SMS->SMS[i].UDH.Text[w] == 0x10) { | ||
658 | dbgprintf("UDH part - EMS 32x32 picture\n"); | ||
659 | BitmapType = GSM_EMSBigPicture; | ||
660 | } else { | ||
661 | dbgprintf("UDH part - EMS 16x16 picture\n"); | ||
662 | BitmapType = GSM_EMSMediumPicture; | ||
663 | } | ||
664 | dbgprintf("Position - %i\n",SMS->SMS[i].UDH.Text[w+2]); | ||
665 | if (SMS->SMS[i].UDH.Text[w+2] > Pos) { | ||
666 | z = Pos; | ||
667 | if (!AddEMSText(&SMS->SMS[i], Info, &Pos, SMS->SMS[i].UDH.Text[w+2]-z)) return false; | ||
668 | } | ||
669 | if (Info->Entries[Info->EntriesNum].ID != 0) (Info->EntriesNum)++; | ||
670 | Info->Entries[Info->EntriesNum].Bitmap = (GSM_MultiBitmap *)malloc(sizeof(GSM_MultiBitmap)); | ||
671 | if (Info->Entries[Info->EntriesNum].Bitmap == NULL) return false; | ||
672 | PHONE_DecodeBitmap(BitmapType, | ||
673 | SMS->SMS[i].UDH.Text + w + 3, | ||
674 | &Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0]); | ||
675 | Info->Entries[Info->EntriesNum].Bitmap->Number = 1; | ||
676 | Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0].Text[0] = 0; | ||
677 | Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0].Text[1] = 0; | ||
678 | Info->Entries[Info->EntriesNum].ID = SMS_EMSFixedBitmap; | ||
679 | RetVal = true; | ||
680 | break; | ||
681 | case 0x12: | ||
682 | dbgprintf("UDH part - EMS variable width bitmap\n"); | ||
683 | if (SMS->SMS[i].UDH.Text[w+2] > Pos) { | ||
684 | z = Pos; | ||
685 | if (!AddEMSText(&SMS->SMS[i], Info, &Pos, SMS->SMS[i].UDH.Text[w+2]-z)) return false; | ||
686 | } | ||
687 | if (NewPicture) { | ||
688 | (Info->EntriesNum)++; | ||
689 | Info->Entries[Info->EntriesNum].Bitmap->Number = 0; | ||
690 | Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0].BitmapWidth = 0; | ||
691 | Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0].BitmapHeight = 0; | ||
692 | } | ||
693 | Bitmap.BitmapWidth = SMS->SMS[i].UDH.Text[w+3]*8; | ||
694 | Bitmap.BitmapHeight = SMS->SMS[i].UDH.Text[w+4]; | ||
695 | Info->Entries[Info->EntriesNum].Bitmap = (GSM_MultiBitmap *)malloc(sizeof(GSM_MultiBitmap)); | ||
696 | if (Info->Entries[Info->EntriesNum].Bitmap == NULL) return false; | ||
697 | if (NewPicture) { | ||
698 | Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0].BitmapWidth = Bitmap.BitmapWidth; | ||
699 | Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0].BitmapHeight = Bitmap.BitmapHeight; | ||
700 | PHONE_DecodeBitmap(GSM_EMSVariablePicture, | ||
701 | SMS->SMS[i].UDH.Text + w + 5, | ||
702 | &Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0]); | ||
703 | } else { | ||
704 | PHONE_DecodeBitmap(GSM_EMSVariablePicture, | ||
705 | SMS->SMS[i].UDH.Text + w + 5, | ||
706 | &Bitmap); | ||
707 | Bitmap2 = Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0]; | ||
708 | Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0].BitmapWidth = Bitmap.BitmapWidth+Bitmap2.BitmapWidth; | ||
709 | Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0].BitmapHeight = Bitmap2.BitmapHeight; | ||
710 | for (width=0;width<Bitmap2.BitmapWidth;width++) { | ||
711 | for (height=0;height<Bitmap2.BitmapHeight;height++) { | ||
712 | if (GSM_IsPointBitmap(&Bitmap2, width, height)) { | ||
713 | GSM_SetPointBitmap(&Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0],width,height); | ||
714 | } else { | ||
715 | GSM_ClearPointBitmap(&Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0],width,height); | ||
716 | } | ||
717 | } | ||
718 | } | ||
719 | for (width=0;width<Bitmap.BitmapWidth;width++) { | ||
720 | for (height=0;height<Bitmap2.BitmapHeight;height++) { | ||
721 | if (GSM_IsPointBitmap(&Bitmap, width, height)) { | ||
722 | GSM_SetPointBitmap(&Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0],width+Bitmap2.BitmapWidth,height); | ||
723 | } else { | ||
724 | GSM_ClearPointBitmap(&Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0],width+Bitmap2.BitmapWidth,height); | ||
725 | } | ||
726 | } | ||
727 | } | ||
728 | } | ||
729 | if (UPI == 1) { | ||
730 | Info->Entries[Info->EntriesNum].Bitmap->Number = 1; | ||
731 | Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0].Text[0] = 0; | ||
732 | Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0].Text[1] = 0; | ||
733 | Info->Entries[Info->EntriesNum].ID = SMS_EMSVariableBitmap; | ||
734 | RetVal = true; | ||
735 | NewPicture = true; | ||
736 | dbgprintf("New variable picture\n"); | ||
737 | } else { | ||
738 | NewPicture = false; | ||
739 | UPI--; | ||
740 | } | ||
741 | break; | ||
742 | case 0x13: | ||
743 | dbgprintf("UDH part - UPI\n"); | ||
744 | dbgprintf("Value %i\n",SMS->SMS[i].UDH.Text[w+2]); | ||
745 | UPI = SMS->SMS[i].UDH.Text[w+2]; | ||
746 | break; | ||
747 | case 0x17: | ||
748 | dbgprintf("UDH part - Object Distribution Indicator (Media Rights Protecting) ignored now\n"); | ||
749 | break; | ||
750 | default: | ||
751 | dbgprintf("UDH part - block %02x\n",SMS->SMS[i].UDH.Text[w]); | ||
752 | Info->Unknown = true; | ||
753 | } /* switch */ | ||
754 | w=w+SMS->SMS[i].UDH.Text[w+1]+2; | ||
755 | } /* while */ | ||
756 | if (!AddEMSText(&SMS->SMS[i], Info, &Pos, SMS->SMS[i].Length-Pos)) return false; | ||
757 | RetVal = true; | ||
758 | } | ||
759 | if (RetVal) (Info->EntriesNum)++; | ||
760 | return RetVal; | ||
761 | } | ||
762 | |||
763 | /* How should editor hadle tabs in this file? Add editor commands here. | ||
764 | * vim: noexpandtab sw=8 ts=8 sts=8: | ||
765 | */ | ||
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 @@ | |||
1 | /* (c) 2002-2003 by Marcin Wiacek */ | ||
2 | |||
3 | #ifndef __gsm_ems_h | ||
4 | #define __gsm_ems_h | ||
5 | |||
6 | #include "../../gsmcomon.h" | ||
7 | #include "gsmmulti.h" | ||
8 | |||
9 | GSM_Error GSM_EncodeEMSMultiPartSMS(GSM_MultiPartSMSInfo *Info, | ||
10 | GSM_MultiSMSMessage *SMS, | ||
11 | GSM_UDH UDHType); | ||
12 | |||
13 | bool GSM_DecodeEMSMultiPartSMS(GSM_MultiPartSMSInfo *Info, | ||
14 | GSM_MultiSMSMessage *SMS); | ||
15 | |||
16 | #endif | ||
17 | |||
18 | /* How should editor hadle tabs in this file? Add editor commands here. | ||
19 | * vim: noexpandtab sw=8 ts=8 sts=8: | ||
20 | */ | ||
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 @@ | |||
1 | /* (c) 2002-2004 by Marcin Wiacek */ | ||
2 | |||
3 | #include <ctype.h> | ||
4 | #include <string.h> | ||
5 | #include <time.h> | ||
6 | |||
7 | #include "../../gsmcomon.h" | ||
8 | #include "../../misc/coding/coding.h" | ||
9 | #include "../gsmcal.h" | ||
10 | #include "../gsmpbk.h" | ||
11 | #include "../gsmlogo.h" | ||
12 | #include "../gsmring.h" | ||
13 | #include "../gsmdata.h" | ||
14 | #include "../gsmnet.h" | ||
15 | #include "gsmsms.h" | ||
16 | #include "gsmmulti.h" | ||
17 | #include "gsmems.h" | ||
18 | |||
19 | /* ----------------- Splitting SMS into parts ------------------------------ */ | ||
20 | |||
21 | unsigned char GSM_MakeSMSIDFromTime(void) | ||
22 | { | ||
23 | GSM_DateTime Date; | ||
24 | unsigned charretval; | ||
25 | |||
26 | GSM_GetCurrentDateTime (&Date); | ||
27 | retval = Date.Second; | ||
28 | switch (Date.Minute/10) { | ||
29 | case 2: case 7: retval = retval + 60; break; | ||
30 | case 4: case 8: retval = retval + 120; break; | ||
31 | case 9: case 5: case 0: retval = retval + 180; break; | ||
32 | } | ||
33 | retval += Date.Minute/10; | ||
34 | return retval; | ||
35 | } | ||
36 | |||
37 | void GSM_Find_Free_Used_SMS2(GSM_Coding_Type Coding,GSM_SMSMessage SMS, int *UsedText, int *FreeText, int *FreeBytes) | ||
38 | { | ||
39 | int UsedBytes; | ||
40 | |||
41 | switch (Coding) { | ||
42 | case SMS_Coding_Default: | ||
43 | FindDefaultAlphabetLen(SMS.Text,&UsedBytes,UsedText,500); | ||
44 | UsedBytes = *UsedText * 7 / 8; | ||
45 | if (UsedBytes * 8 / 7 != *UsedText) UsedBytes++; | ||
46 | *FreeBytes = GSM_MAX_8BIT_SMS_LENGTH - SMS.UDH.Length - UsedBytes; | ||
47 | *FreeText = (GSM_MAX_8BIT_SMS_LENGTH - SMS.UDH.Length) * 8 / 7 - *UsedText; | ||
48 | break; | ||
49 | case SMS_Coding_Unicode: | ||
50 | *UsedText = UnicodeLength(SMS.Text); | ||
51 | UsedBytes = *UsedText * 2; | ||
52 | *FreeBytes = GSM_MAX_8BIT_SMS_LENGTH - SMS.UDH.Length - UsedBytes; | ||
53 | *FreeText = *FreeBytes / 2; | ||
54 | break; | ||
55 | case SMS_Coding_8bit: | ||
56 | *UsedText = UsedBytes = SMS.Length; | ||
57 | *FreeBytes = GSM_MAX_8BIT_SMS_LENGTH - SMS.UDH.Length - UsedBytes; | ||
58 | *FreeText = *FreeBytes; | ||
59 | break; | ||
60 | } | ||
61 | dbgprintf("UDH len %i, UsedBytes %i, FreeText %i, UsedText %i, FreeBytes %i\n",SMS.UDH.Length,UsedBytes,*FreeText,*UsedText,*FreeBytes); | ||
62 | } | ||
63 | |||
64 | GSM_Error GSM_AddSMS_Text_UDH(GSM_MultiSMSMessage *SMS, | ||
65 | GSM_Coding_Type Coding, | ||
66 | char *Buffer, | ||
67 | int BufferLen, | ||
68 | bool UDH, | ||
69 | int *UsedText, | ||
70 | int *CopiedText, | ||
71 | int *CopiedSMSText) | ||
72 | { | ||
73 | int FreeText,FreeBytes,Copy,i,j; | ||
74 | |||
75 | dbgprintf("Checking used\n"); | ||
76 | GSM_Find_Free_Used_SMS2(Coding,SMS->SMS[SMS->Number], UsedText, &FreeText, &FreeBytes); | ||
77 | |||
78 | if (UDH) { | ||
79 | dbgprintf("Adding UDH\n"); | ||
80 | if (FreeBytes - BufferLen <= 0) { | ||
81 | dbgprintf("Going to the new SMS\n"); | ||
82 | SMS->Number++; | ||
83 | GSM_Find_Free_Used_SMS2(Coding,SMS->SMS[SMS->Number], UsedText, &FreeText, &FreeBytes); | ||
84 | } | ||
85 | if (SMS->SMS[SMS->Number].UDH.Length == 0) { | ||
86 | SMS->SMS[SMS->Number].UDH.Length = 1; | ||
87 | SMS->SMS[SMS->Number].UDH.Text[0] = 0x00; | ||
88 | } | ||
89 | memcpy(SMS->SMS[SMS->Number].UDH.Text+SMS->SMS[SMS->Number].UDH.Length,Buffer,BufferLen); | ||
90 | SMS->SMS[SMS->Number].UDH.Length += BufferLen; | ||
91 | SMS->SMS[SMS->Number].UDH.Text[0] += BufferLen; | ||
92 | SMS->SMS[SMS->Number].UDH.Type = UDH_UserUDH; | ||
93 | dbgprintf("UDH added %i\n",BufferLen); | ||
94 | } else { | ||
95 | dbgprintf("Adding text\n"); | ||
96 | if (FreeText == 0) { | ||
97 | dbgprintf("Going to the new SMS\n"); | ||
98 | SMS->Number++; | ||
99 | GSM_Find_Free_Used_SMS2(Coding,SMS->SMS[SMS->Number], UsedText, &FreeText, &FreeBytes); | ||
100 | } | ||
101 | |||
102 | Copy = FreeText; | ||
103 | dbgprintf("copy %i\n",Copy); | ||
104 | if (BufferLen < Copy) Copy = BufferLen; | ||
105 | dbgprintf("copy %i\n",Copy); | ||
106 | |||
107 | switch (Coding) { | ||
108 | case SMS_Coding_Default: | ||
109 | FindDefaultAlphabetLen(Buffer,&i,&j,FreeText); | ||
110 | dbgprintf("def length %i %i\n",i,j); | ||
111 | SMS->SMS[SMS->Number].Text[UnicodeLength(SMS->SMS[SMS->Number].Text)*2+i*2] = 0; | ||
112 | SMS->SMS[SMS->Number].Text[UnicodeLength(SMS->SMS[SMS->Number].Text)*2+i*2+1] = 0; | ||
113 | memcpy(SMS->SMS[SMS->Number].Text+UnicodeLength(SMS->SMS[SMS->Number].Text)*2,Buffer,i*2); | ||
114 | *CopiedText = i; | ||
115 | *CopiedSMSText = j; | ||
116 | SMS->SMS[SMS->Number].Length += i; | ||
117 | break; | ||
118 | case SMS_Coding_Unicode: | ||
119 | SMS->SMS[SMS->Number].Text[UnicodeLength(SMS->SMS[SMS->Number].Text)*2+Copy*2] = 0; | ||
120 | SMS->SMS[SMS->Number].Text[UnicodeLength(SMS->SMS[SMS->Number].Text)*2+Copy*2+1] = 0; | ||
121 | memcpy(SMS->SMS[SMS->Number].Text+UnicodeLength(SMS->SMS[SMS->Number].Text)*2,Buffer,Copy*2); | ||
122 | *CopiedText = *CopiedSMSText = Copy; | ||
123 | SMS->SMS[SMS->Number].Length += Copy; | ||
124 | break; | ||
125 | case SMS_Coding_8bit: | ||
126 | memcpy(SMS->SMS[SMS->Number].Text+SMS->SMS[SMS->Number].Length,Buffer,Copy); | ||
127 | SMS->SMS[SMS->Number].Length += Copy; | ||
128 | *CopiedText = *CopiedSMSText = Copy; | ||
129 | break; | ||
130 | } | ||
131 | dbgprintf("Text added\n"); | ||
132 | } | ||
133 | |||
134 | dbgprintf("Checking on the end\n"); | ||
135 | GSM_Find_Free_Used_SMS2(Coding,SMS->SMS[SMS->Number], UsedText, &FreeText, &FreeBytes); | ||
136 | |||
137 | return ERR_NONE; | ||
138 | } | ||
139 | |||
140 | void GSM_MakeMultiPartSMS(GSM_MultiSMSMessage*SMS, | ||
141 | unsigned char *MessageBuffer, | ||
142 | int MessageLength, | ||
143 | GSM_UDH UDHType, | ||
144 | GSM_Coding_TypeCoding, | ||
145 | int Class, | ||
146 | unsigned char ReplaceMessage) | ||
147 | { | ||
148 | int j,Len,UsedText,CopiedText,CopiedSMSText; | ||
149 | unsigned char UDHID; | ||
150 | GSM_DateTime Date; | ||
151 | |||
152 | Len = 0; | ||
153 | while(1) { | ||
154 | GSM_SetDefaultSMSData(&SMS->SMS[SMS->Number]); | ||
155 | SMS->SMS[SMS->Number].Class = Class; | ||
156 | SMS->SMS[SMS->Number].Coding = Coding; | ||
157 | |||
158 | SMS->SMS[SMS->Number].UDH.Type = UDHType; | ||
159 | GSM_EncodeUDHHeader(&SMS->SMS[SMS->Number].UDH); | ||
160 | |||
161 | if (Coding == SMS_Coding_8bit) { | ||
162 | GSM_AddSMS_Text_UDH(SMS,Coding,MessageBuffer+Len,MessageLength - Len,false,&UsedText,&CopiedText,&CopiedSMSText); | ||
163 | } else { | ||
164 | GSM_AddSMS_Text_UDH(SMS,Coding,MessageBuffer+Len*2,MessageLength - Len,false,&UsedText,&CopiedText,&CopiedSMSText); | ||
165 | } | ||
166 | Len += CopiedText; | ||
167 | dbgprintf("%i %i\n",Len,MessageLength); | ||
168 | if (Len == MessageLength) break; | ||
169 | if (SMS->Number == MAX_MULTI_SMS) break; | ||
170 | SMS->Number++; | ||
171 | } | ||
172 | |||
173 | SMS->Number++; | ||
174 | |||
175 | UDHID = GSM_MakeSMSIDFromTime(); | ||
176 | GSM_GetCurrentDateTime (&Date); | ||
177 | for (j=0;j<SMS->Number;j++) { | ||
178 | SMS->SMS[j].UDH.Type = UDHType; | ||
179 | SMS->SMS[j].UDH.ID8bit = UDHID; | ||
180 | SMS->SMS[j].UDH.ID16bit = UDHID + 256 * Date.Hour; | ||
181 | SMS->SMS[j].UDH.PartNumber = j+1; | ||
182 | SMS->SMS[j].UDH.AllParts = SMS->Number; | ||
183 | GSM_EncodeUDHHeader(&SMS->SMS[j].UDH); | ||
184 | } | ||
185 | if (SMS->Number == 1) SMS->SMS[0].ReplaceMessage = ReplaceMessage; | ||
186 | } | ||
187 | |||
188 | /* Calculates number of SMS and number of left chars in SMS */ | ||
189 | void GSM_SMSCounter(int MessageLength, | ||
190 | unsigned char *MessageBuffer, | ||
191 | GSM_UDH UDHType, | ||
192 | GSM_Coding_Type Coding, | ||
193 | int *SMSNum, | ||
194 | int *CharsLeft) | ||
195 | { | ||
196 | int UsedText,FreeBytes; | ||
197 | GSM_MultiSMSMessage MultiSMS; | ||
198 | |||
199 | MultiSMS.Number = 0; | ||
200 | GSM_MakeMultiPartSMS(&MultiSMS,MessageBuffer,MessageLength,UDHType,Coding,-1,false); | ||
201 | GSM_Find_Free_Used_SMS2(Coding,MultiSMS.SMS[MultiSMS.Number-1], &UsedText, CharsLeft, &FreeBytes); | ||
202 | *SMSNum = MultiSMS.Number; | ||
203 | } | ||
204 | |||
205 | /* Nokia Smart Messaging 3.0 */ | ||
206 | static void GSM_EncodeSMS30MultiPartSMS(GSM_MultiPartSMSInfo *Info, | ||
207 | char *Buffer, int *Length) | ||
208 | { | ||
209 | int len; | ||
210 | |||
211 | /*SM version. Here 3.0*/ | ||
212 | Buffer[(*Length)++] = 0x30; | ||
213 | |||
214 | if (Info->Entries[0].ID == SMS_NokiaProfileLong) { | ||
215 | if (Info->Entries[0].Buffer != NULL) { | ||
216 | if (Info->Entries[0].Buffer[0]!=0x00 || Info->Entries[0].Buffer[1]!=0x00) { | ||
217 | Buffer[(*Length)++] = SM30_PROFILENAME; | ||
218 | Buffer[(*Length)++] = 0x00; | ||
219 | Buffer[(*Length)++] = 2*UnicodeLength(Info->Entries[0].Buffer); | ||
220 | CopyUnicodeString(Buffer+(*Length),Info->Entries[0].Buffer); | ||
221 | *Length = *Length + 2*UnicodeLength(Info->Entries[0].Buffer); | ||
222 | } | ||
223 | } | ||
224 | if (Info->Entries[0].Ringtone != NULL) { | ||
225 | Buffer[(*Length)++] = SM30_RINGTONE; | ||
226 | /* Length for this part later will be changed */ | ||
227 | Buffer[(*Length)++] = 0x01; | ||
228 | Buffer[(*Length)++] = 0x00; | ||
229 | /* Smart Messaging 3.0 says: 16*9=144 bytes, | ||
230 | * but on 3310 4.02 it was possible to save about 196 chars | ||
231 | * (without cutting) */ | ||
232 | len = 196; | ||
233 | Info->Entries[0].RingtoneNotes=GSM_EncodeNokiaRTTLRingtone(*Info->Entries[0].Ringtone,Buffer+(*Length),&len); | ||
234 | Buffer[(*Length)-2] = len / 256; | ||
235 | Buffer[(*Length)-1] = len % 256; | ||
236 | *Length = *Length + len; | ||
237 | } | ||
238 | } | ||
239 | if (Info->Entries[0].Bitmap != NULL) { | ||
240 | if (Info->Entries[0].ID == SMS_NokiaPictureImageLong) { | ||
241 | Buffer[(*Length)++] = SM30_OTA; | ||
242 | } else { | ||
243 | Buffer[(*Length)++] = SM30_SCREENSAVER; | ||
244 | } | ||
245 | Buffer[(*Length)++] = 0x01; | ||
246 | Buffer[(*Length)++] = 0x00; | ||
247 | NOKIA_CopyBitmap(GSM_NokiaPictureImage, &Info->Entries[0].Bitmap->Bitmap[0], Buffer, Length); | ||
248 | if (Info->Entries[0].Bitmap->Bitmap[0].Text[0]!=0 || Info->Entries[0].Bitmap->Bitmap[0].Text[1]!=0) { | ||
249 | if (Info->UnicodeCoding) { | ||
250 | Buffer[(*Length)++] = SM30_UNICODETEXT; | ||
251 | /* Length for text part */ | ||
252 | Buffer[(*Length)++] = 0x00; | ||
253 | Buffer[(*Length)++] = UnicodeLength(Info->Entries[0].Bitmap->Bitmap[0].Text)*2; | ||
254 | memcpy(Buffer+(*Length),Info->Entries[0].Bitmap->Bitmap[0].Text,UnicodeLength(Info->Entries[0].Bitmap->Bitmap[0].Text)*2); | ||
255 | *Length = *Length + UnicodeLength(Info->Entries[0].Bitmap->Bitmap[0].Text)*2; | ||
256 | } else { | ||
257 | /*ID for ISO-8859-1 text*/ | ||
258 | Buffer[(*Length)++] = SM30_ISOTEXT; | ||
259 | Buffer[(*Length)++] = 0x00; | ||
260 | Buffer[(*Length)++] = UnicodeLength(Info->Entries[0].Bitmap->Bitmap[0].Text); | ||
261 | memcpy(Buffer+(*Length),DecodeUnicodeString(Info->Entries[0].Bitmap->Bitmap[0].Text),UnicodeLength(Info->Entries[0].Bitmap->Bitmap[0].Text)); | ||
262 | *Length = *Length +UnicodeLength(Info->Entries[0].Bitmap->Bitmap[0].Text); | ||
263 | } | ||
264 | } | ||
265 | } | ||
266 | } | ||
267 | |||
268 | /* Alcatel docs from www.alcatel.com/wap/ahead */ | ||
269 | GSM_Error GSM_EncodeAlcatelMultiPartSMS(GSM_MultiSMSMessage *SMS, | ||
270 | unsigned char *Data, | ||
271 | int Len, | ||
272 | unsigned char *Name, | ||
273 | int Type) | ||
274 | { | ||
275 | unsigned char buff[100],UDHID; | ||
276 | int p,i; | ||
277 | GSM_UDHHeaderMyUDH; | ||
278 | |||
279 | for (i=0;i<MAX_MULTI_SMS;i++) { | ||
280 | GSM_SetDefaultSMSData(&SMS->SMS[i]); | ||
281 | SMS->SMS[i].UDH.Type = UDH_UserUDH; | ||
282 | SMS->SMS[i].UDH.Text[1] = 0x80;/* Alcatel */ | ||
283 | p = UnicodeLength(Name); | ||
284 | EncodeDefault(buff, Name, &p, true, NULL); | ||
285 | SMS->SMS[i].UDH.Text[2]= GSM_PackSevenBitsToEight(0, buff, SMS->SMS[i].UDH.Text+3, p) + 4; | ||
286 | SMS->SMS[i].UDH.Text[3]= GSM_PackSevenBitsToEight(0, buff, SMS->SMS[i].UDH.Text+3, p); | ||
287 | SMS->SMS[i].UDH.Text[4] = Type; | ||
288 | SMS->SMS[i].UDH.Text[5] = Len / 256; | ||
289 | SMS->SMS[i].UDH.Text[6] = Len % 256; | ||
290 | SMS->SMS[i].UDH.Text[0] = 6 + SMS->SMS[i].UDH.Text[3]; | ||
291 | SMS->SMS[i].UDH.Length = SMS->SMS[i].UDH.Text[0] + 1; | ||
292 | |||
293 | if (Len > 140 - SMS->SMS[i].UDH.Length) { | ||
294 | MyUDH.Type = UDH_ConcatenatedMessages; | ||
295 | GSM_EncodeUDHHeader(&MyUDH); | ||
296 | |||
297 | memcpy(SMS->SMS[i].UDH.Text+SMS->SMS[i].UDH.Length,MyUDH.Text+1,MyUDH.Length-1); | ||
298 | SMS->SMS[i].UDH.Text[0] += MyUDH.Length-1; | ||
299 | SMS->SMS[i].UDH.Length += MyUDH.Length-1; | ||
300 | } | ||
301 | |||
302 | SMS->SMS[i].Coding = SMS_Coding_8bit; | ||
303 | SMS->SMS[i].Class = 1; | ||
304 | } | ||
305 | |||
306 | p = 0; | ||
307 | while (p != Len) { | ||
308 | i = 140-SMS->SMS[SMS->Number].UDH.Length; | ||
309 | if (Len - p < i) i = Len - p; | ||
310 | memcpy(SMS->SMS[SMS->Number].Text,Data+p,i); | ||
311 | p += i; | ||
312 | SMS->SMS[SMS->Number].Length = i; | ||
313 | SMS->Number++; | ||
314 | |||
315 | } | ||
316 | |||
317 | /* Linked sms UDH */ | ||
318 | if (SMS->Number != 1) { | ||
319 | UDHID = GSM_MakeSMSIDFromTime(); | ||
320 | for (i=0;i<SMS->Number;i++) { | ||
321 | SMS->SMS[i].UDH.Text[SMS->SMS[i].UDH.Length-3] = UDHID; | ||
322 | SMS->SMS[i].UDH.Text[SMS->SMS[i].UDH.Length-2] = SMS->Number; | ||
323 | SMS->SMS[i].UDH.Text[SMS->SMS[i].UDH.Length-1] = i+1; | ||
324 | } | ||
325 | } | ||
326 | |||
327 | return ERR_NONE; | ||
328 | } | ||
329 | |||
330 | /* Alcatel docs from www.alcatel.com/wap/ahead and other */ | ||
331 | GSM_Error GSM_EncodeMultiPartSMS(GSM_MultiPartSMSInfo *Info, | ||
332 | GSM_MultiSMSMessage *SMS) | ||
333 | { | ||
334 | unsigned charBuffer[GSM_MAX_SMS_LENGTH*2*MAX_MULTI_SMS]; | ||
335 | unsigned charBuffer2[GSM_MAX_SMS_LENGTH*2*MAX_MULTI_SMS]; | ||
336 | int Length = 0,smslen,i, Class = -1, j,p; | ||
337 | GSM_Errorerror; | ||
338 | GSM_Coding_Type Coding = SMS_Coding_8bit; | ||
339 | GSM_UDH UDH= UDH_NoUDH; | ||
340 | GSM_UDHHeader UDHHeader; | ||
341 | bool EMS= false; | ||
342 | int textnum = 0; | ||
343 | |||
344 | SMS->Number = 0; | ||
345 | |||
346 | if (Info->Entries[0].ID == SMS_AlcatelSMSTemplateName) { | ||
347 | Buffer[Length++] = 0x00; //number of elements | ||
348 | for (i=1;i<Info->EntriesNum;i++) { | ||
349 | switch (Info->Entries[i].ID) { | ||
350 | case SMS_EMSSound10: | ||
351 | case SMS_EMSSound12: | ||
352 | case SMS_EMSSonyEricssonSound: | ||
353 | case SMS_EMSSound10Long: | ||
354 | case SMS_EMSSound12Long: | ||
355 | case SMS_EMSSonyEricssonSoundLong: | ||
356 | case SMS_EMSVariableBitmap: | ||
357 | case SMS_EMSAnimation: | ||
358 | case SMS_EMSVariableBitmapLong: | ||
359 | break; | ||
360 | case SMS_EMSPredefinedSound: | ||
361 | Buffer[0]++; | ||
362 | Buffer[Length++] = 0x01; //type of data | ||
363 | Buffer[Length++] = 1 % 256;//len | ||
364 | Buffer[Length++] = 1 / 256; //len | ||
365 | Buffer[Length++] = Info->Entries[i].Number; | ||
366 | break; | ||
367 | case SMS_EMSPredefinedAnimation: | ||
368 | Buffer[0]++; | ||
369 | Buffer[Length++] = 0x02; //type of data | ||
370 | Buffer[Length++] = 1 % 256;//len | ||
371 | Buffer[Length++] = 1 / 256; //len | ||
372 | Buffer[Length++] = Info->Entries[i].Number; | ||
373 | break; | ||
374 | case SMS_ConcatenatedTextLong: | ||
375 | Buffer[0]++; | ||
376 | p = UnicodeLength(Info->Entries[i].Buffer); | ||
377 | EncodeDefault(Buffer2, Info->Entries[i].Buffer, &p, true, NULL); | ||
378 | Buffer[Length++] = 0x00; //type of data | ||
379 | Length = Length + 2; | ||
380 | smslen = GSM_PackSevenBitsToEight(0, Buffer2, Buffer+Length, p); | ||
381 | Buffer[Length-2] = smslen % 256; //len | ||
382 | Buffer[Length-1] = smslen / 256; //len | ||
383 | Length = Length + smslen; | ||
384 | break; | ||
385 | default: | ||
386 | return ERR_UNKNOWN; | ||
387 | } | ||
388 | } | ||
389 | Buffer[0] = Buffer[0] * 2; | ||
390 | return GSM_EncodeAlcatelMultiPartSMS(SMS,Buffer,Length,Info->Entries[0].Buffer,ALCATELTDD_SMSTEMPLATE); | ||
391 | } | ||
392 | |||
393 | for (i=0;i<Info->EntriesNum;i++) { | ||
394 | switch (Info->Entries[i].ID) { | ||
395 | case SMS_EMSPredefinedAnimation: | ||
396 | case SMS_EMSPredefinedSound: | ||
397 | case SMS_EMSSound10: | ||
398 | case SMS_EMSSound12: | ||
399 | case SMS_EMSSonyEricssonSound: | ||
400 | case SMS_EMSSound10Long: | ||
401 | case SMS_EMSSound12Long: | ||
402 | case SMS_EMSSonyEricssonSoundLong: | ||
403 | case SMS_EMSFixedBitmap: | ||
404 | case SMS_EMSVariableBitmap: | ||
405 | case SMS_EMSAnimation: | ||
406 | case SMS_EMSVariableBitmapLong: | ||
407 | EMS = true; | ||
408 | break; | ||
409 | case SMS_ConcatenatedTextLong: | ||
410 | case SMS_ConcatenatedTextLong16bit: | ||
411 | |||
412 | /* This covers situation, when somebody will call function | ||
413 | * with two or more SMS_Concatenated.... entries only. | ||
414 | * It will be still only linked sms, but functions below | ||
415 | * will pack only first entry according to own limits. | ||
416 | * We redirect to EMS functions, because they are more generic | ||
417 | * here and will handle it correctly and produce linked sms | ||
418 | * from all entries | ||
419 | */ | ||
420 | textnum ++; | ||
421 | if (textnum > 1) EMS = true; | ||
422 | |||
423 | if (Info->Entries[i].Left || Info->Entries[i].Right || | ||
424 | Info->Entries[i].Center || Info->Entries[i].Large || | ||
425 | Info->Entries[i].Small || Info->Entries[i].Bold || | ||
426 | Info->Entries[i].Italic || Info->Entries[i].Underlined || | ||
427 | Info->Entries[i].Strikethrough) { | ||
428 | EMS = true; | ||
429 | } | ||
430 | default: | ||
431 | break; | ||
432 | } | ||
433 | if (EMS) break; | ||
434 | } | ||
435 | if (EMS) { | ||
436 | error=GSM_EncodeEMSMultiPartSMS(Info,SMS,UDH_NoUDH); | ||
437 | if (error != ERR_NONE) return error; | ||
438 | if (SMS->Number != 1) { | ||
439 | SMS->Number = 0; | ||
440 | for (i=0;i<Info->EntriesNum;i++) { | ||
441 | if (Info->Entries[i].ID == SMS_ConcatenatedTextLong16bit) { | ||
442 | return GSM_EncodeEMSMultiPartSMS(Info,SMS,UDH_ConcatenatedMessages); | ||
443 | } | ||
444 | } | ||
445 | return GSM_EncodeEMSMultiPartSMS(Info,SMS,UDH_ConcatenatedMessages16bit); | ||
446 | } | ||
447 | return error; | ||
448 | } | ||
449 | |||
450 | if (Info->EntriesNum != 1) return ERR_UNKNOWN; | ||
451 | |||
452 | switch (Info->Entries[0].ID) { | ||
453 | case SMS_AlcatelMonoBitmapLong: | ||
454 | Buffer[0] = Info->Entries[0].Bitmap->Bitmap[0].BitmapWidth; | ||
455 | Buffer[1] = Info->Entries[0].Bitmap->Bitmap[0].BitmapHeight; | ||
456 | PHONE_EncodeBitmap(GSM_AlcatelBMMIPicture, Buffer+2, &Info->Entries[0].Bitmap->Bitmap[0]); | ||
457 | Length = PHONE_GetBitmapSize(GSM_AlcatelBMMIPicture,Info->Entries[0].Bitmap->Bitmap[0].BitmapWidth,Info->Entries[0].Bitmap->Bitmap[0].BitmapHeight)+2; | ||
458 | return GSM_EncodeAlcatelMultiPartSMS(SMS,Buffer,Length,Info->Entries[0].Bitmap->Bitmap[0].Text,ALCATELTDD_PICTURE); | ||
459 | case SMS_AlcatelMonoAnimationLong: | ||
460 | /* Number of sequence words */ | ||
461 | Buffer[0] = (Info->Entries[0].Bitmap->Number+1) % 256; | ||
462 | Buffer[1] = (Info->Entries[0].Bitmap->Number+1) / 256; | ||
463 | /* Picture display time 1 second (1 = 100ms) */ | ||
464 | Buffer[2] = 10 % 256; | ||
465 | Buffer[3] = 10 / 256 + 0xF0; | ||
466 | |||
467 | Length = 4; | ||
468 | j = 0; | ||
469 | |||
470 | /* Offsets to bitmaps */ | ||
471 | for (i=0;i<Info->Entries[0].Bitmap->Number;i++) { | ||
472 | Buffer[Length++] = (4+j+Info->Entries[0].Bitmap->Number*2) % 256; | ||
473 | Buffer[Length++] = (4+j+Info->Entries[0].Bitmap->Number*2) / 256; | ||
474 | j += PHONE_GetBitmapSize(GSM_AlcatelBMMIPicture,Info->Entries[0].Bitmap->Bitmap[i].BitmapWidth,Info->Entries[0].Bitmap->Bitmap[i].BitmapHeight)+2; | ||
475 | } | ||
476 | |||
477 | /* Bitmaps */ | ||
478 | for (i=0;i<Info->Entries[0].Bitmap->Number;i++) { | ||
479 | Buffer[Length++] = Info->Entries[0].Bitmap->Bitmap[i].BitmapWidth; | ||
480 | Buffer[Length++] = Info->Entries[0].Bitmap->Bitmap[i].BitmapHeight; | ||
481 | PHONE_EncodeBitmap(GSM_AlcatelBMMIPicture, Buffer+Length, &Info->Entries[0].Bitmap->Bitmap[i]); | ||
482 | Length += PHONE_GetBitmapSize(GSM_AlcatelBMMIPicture,Info->Entries[0].Bitmap->Bitmap[i].BitmapWidth,Info->Entries[0].Bitmap->Bitmap[i].BitmapHeight); | ||
483 | } | ||
484 | return GSM_EncodeAlcatelMultiPartSMS(SMS,Buffer,Length,Info->Entries[0].Bitmap->Bitmap[0].Text,ALCATELTDD_ANIMATION); | ||
485 | case SMS_MMSIndicatorLong: | ||
486 | Class= 1; | ||
487 | UDH= UDH_MMSIndicatorLong; | ||
488 | GSM_EncodeMMSIndicatorSMSText(Buffer,&Length,*Info->Entries[0].MMSIndicator); | ||
489 | break; | ||
490 | case SMS_NokiaRingtoneLong: | ||
491 | case SMS_NokiaRingtone: | ||
492 | UDH= UDH_NokiaRingtone; | ||
493 | Class= 1; | ||
494 | /* 7 = length of UDH_NokiaRingtone UDH header */ | ||
495 | Length = GSM_MAX_8BIT_SMS_LENGTH-7; | ||
496 | Info->Entries[0].RingtoneNotes = GSM_EncodeNokiaRTTLRingtone(*Info->Entries[0].Ringtone,Buffer,&Length); | ||
497 | if (Info->Entries[0].ID == SMS_NokiaRingtone) break; | ||
498 | if (Info->Entries[0].RingtoneNotes != Info->Entries[0].Ringtone->NoteTone.NrCommands) { | ||
499 | UDH = UDH_NokiaRingtoneLong; | ||
500 | Length = (GSM_MAX_8BIT_SMS_LENGTH-12)*3; | ||
501 | Info->Entries[0].RingtoneNotes = GSM_EncodeNokiaRTTLRingtone(*Info->Entries[0].Ringtone,Buffer,&Length); | ||
502 | } | ||
503 | break; | ||
504 | case SMS_NokiaOperatorLogoLong: | ||
505 | if (Info->Entries[0].Bitmap->Bitmap[0].BitmapWidth > 72 || Info->Entries[0].Bitmap->Bitmap[0].BitmapHeight > 14) { | ||
506 | UDH= UDH_NokiaOperatorLogoLong; | ||
507 | Class = 1; | ||
508 | NOKIA_EncodeNetworkCode(Buffer, Info->Entries[0].Bitmap->Bitmap[0].NetworkCode); | ||
509 | Length = Length + 3; | ||
510 | NOKIA_CopyBitmap(GSM_Nokia7110OperatorLogo, &Info->Entries[0].Bitmap->Bitmap[0], Buffer, &Length); | ||
511 | break; | ||
512 | } | ||
513 | case SMS_NokiaOperatorLogo: | ||
514 | UDH= UDH_NokiaOperatorLogo; | ||
515 | Class = 1; | ||
516 | NOKIA_EncodeNetworkCode(Buffer, Info->Entries[0].Bitmap->Bitmap[0].NetworkCode); | ||
517 | Length = Length + 3; | ||
518 | NOKIA_CopyBitmap(GSM_NokiaOperatorLogo, &Info->Entries[0].Bitmap->Bitmap[0], Buffer, &Length); | ||
519 | break; | ||
520 | case SMS_NokiaCallerLogo: | ||
521 | UDH= UDH_NokiaCallerLogo; | ||
522 | Class = 1; | ||
523 | NOKIA_CopyBitmap(GSM_NokiaCallerLogo, &Info->Entries[0].Bitmap->Bitmap[0], Buffer, &Length); | ||
524 | break; | ||
525 | case SMS_NokiaProfileLong: | ||
526 | case SMS_NokiaPictureImageLong: | ||
527 | case SMS_NokiaScreenSaverLong: | ||
528 | Class = 1; | ||
529 | UDH= UDH_NokiaProfileLong; | ||
530 | GSM_EncodeSMS30MultiPartSMS(Info,Buffer,&Length); | ||
531 | break; | ||
532 | case SMS_NokiaWAPBookmarkLong: | ||
533 | Class= 1; | ||
534 | NOKIA_EncodeWAPBookmarkSMSText(Buffer,&Length,Info->Entries[0].Bookmark); | ||
535 | /* 7 = length of UDH_NokiaWAP UDH header */ | ||
536 | if (Length>(GSM_MAX_8BIT_SMS_LENGTH-7)) { | ||
537 | UDH=UDH_NokiaWAPLong; | ||
538 | } else { | ||
539 | UDH=UDH_NokiaWAP; | ||
540 | } | ||
541 | break; | ||
542 | case SMS_NokiaWAPSettingsLong: | ||
543 | Class= 1; | ||
544 | UDH= UDH_NokiaWAPLong; | ||
545 | NOKIA_EncodeWAPMMSSettingsSMSText(Buffer,&Length,Info->Entries[0].Settings,false); | ||
546 | break; | ||
547 | case SMS_NokiaMMSSettingsLong: | ||
548 | Class= 1; | ||
549 | UDH= UDH_NokiaWAPLong; | ||
550 | NOKIA_EncodeWAPMMSSettingsSMSText(Buffer,&Length,Info->Entries[0].Settings,true); | ||
551 | break; | ||
552 | case SMS_NokiaVCARD10Long: | ||
553 | GSM_EncodeVCARD(Buffer,&Length,Info->Entries[0].Phonebook,true,Nokia_VCard10); | ||
554 | /* is 1 SMS ? 8 = length of ..SCKE2 */ | ||
555 | if (Length<=GSM_MAX_SMS_LENGTH-8) { | ||
556 | sprintf(Buffer,"//SCKE2 "); | ||
557 | Length = 8; | ||
558 | GSM_EncodeVCARD(Buffer,&Length,Info->Entries[0].Phonebook,true,Nokia_VCard10); | ||
559 | } else { | ||
560 | /* FIXME: It wasn't checked */ | ||
561 | UDH = UDH_NokiaPhonebookLong; | ||
562 | } | ||
563 | Coding = SMS_Coding_Default; | ||
564 | memcpy(Buffer2,Buffer,Length); | ||
565 | EncodeUnicode(Buffer,Buffer2,Length); | ||
566 | break; | ||
567 | case SMS_NokiaVCARD21Long: | ||
568 | GSM_EncodeVCARD(Buffer,&Length,Info->Entries[0].Phonebook,true,Nokia_VCard21); | ||
569 | /* Is 1 SMS ? 12 = length of ..SCKL23F4 */ | ||
570 | if (Length<=GSM_MAX_SMS_LENGTH-12) { | ||
571 | sprintf(Buffer,"//SCKL23F4%c%c",13,10); | ||
572 | Length = 12; | ||
573 | GSM_EncodeVCARD(Buffer,&Length,Info->Entries[0].Phonebook,true,Nokia_VCard21); | ||
574 | } else { | ||
575 | UDH = UDH_NokiaPhonebookLong; | ||
576 | /* Here can be also 8 bit coding */ | ||
577 | } | ||
578 | Coding = SMS_Coding_Default; | ||
579 | memcpy(Buffer2,Buffer,Length); | ||
580 | EncodeUnicode(Buffer,Buffer2,Length); | ||
581 | break; | ||
582 | case SMS_VCARD10Long: | ||
583 | GSM_EncodeVCARD(Buffer,&Length,Info->Entries[0].Phonebook,true,Nokia_VCard10); | ||
584 | if (Length>GSM_MAX_SMS_LENGTH) UDH = UDH_ConcatenatedMessages; | ||
585 | Coding = SMS_Coding_Default; | ||
586 | memcpy(Buffer2,Buffer,Length); | ||
587 | EncodeUnicode(Buffer,Buffer2,Length); | ||
588 | break; | ||
589 | case SMS_VCARD21Long: | ||
590 | GSM_EncodeVCARD(Buffer,&Length,Info->Entries[0].Phonebook,true,Nokia_VCard21); | ||
591 | if (Length>GSM_MAX_SMS_LENGTH) UDH = UDH_ConcatenatedMessages; | ||
592 | Coding = SMS_Coding_Default; | ||
593 | memcpy(Buffer2,Buffer,Length); | ||
594 | EncodeUnicode(Buffer,Buffer2,Length); | ||
595 | break; | ||
596 | case SMS_NokiaVCALENDAR10Long: | ||
597 | error=GSM_EncodeVCALENDAR(Buffer,&Length,Info->Entries[0].Calendar,true,Nokia_VCalendar); | ||
598 | if (error != ERR_NONE) return error; | ||
599 | /* Is 1 SMS ? 8 = length of ..SCKE4 */ | ||
600 | if (Length<=GSM_MAX_SMS_LENGTH-8) { | ||
601 | sprintf(Buffer,"//SCKE4 "); | ||
602 | Length = 8; | ||
603 | GSM_EncodeVCALENDAR(Buffer,&Length,Info->Entries[0].Calendar,true,Nokia_VCalendar); | ||
604 | } else { | ||
605 | UDH = UDH_NokiaCalendarLong; | ||
606 | /* can be here 8 bit coding ? */ | ||
607 | } | ||
608 | Coding = SMS_Coding_Default; | ||
609 | memcpy(Buffer2,Buffer,Length); | ||
610 | EncodeUnicode(Buffer,Buffer2,Length); | ||
611 | break; | ||
612 | case SMS_NokiaVTODOLong: | ||
613 | error=GSM_EncodeVTODO(Buffer,&Length,Info->Entries[0].ToDo,true,Nokia_VToDo); | ||
614 | if (error != ERR_NONE) return error; | ||
615 | UDH = UDH_NokiaCalendarLong; | ||
616 | Coding = SMS_Coding_Default; | ||
617 | memcpy(Buffer2,Buffer,Length); | ||
618 | EncodeUnicode(Buffer,Buffer2,Length); | ||
619 | break; | ||
620 | case SMS_DisableVoice: | ||
621 | case SMS_DisableFax: | ||
622 | case SMS_DisableEmail: | ||
623 | case SMS_EnableVoice: | ||
624 | case SMS_EnableFax: | ||
625 | case SMS_EnableEmail: | ||
626 | case SMS_VoidSMS: | ||
627 | case SMS_Text: | ||
628 | Class = Info->Class; | ||
629 | switch (Info->Entries[0].ID) { | ||
630 | case SMS_DisableVoice: UDH = UDH_DisableVoice; break; | ||
631 | case SMS_DisableFax : UDH = UDH_DisableFax; break; | ||
632 | case SMS_DisableEmail: UDH = UDH_DisableEmail; break; | ||
633 | case SMS_EnableVoice: UDH = UDH_EnableVoice; break; | ||
634 | case SMS_EnableFax : UDH = UDH_EnableFax; break; | ||
635 | case SMS_EnableEmail: UDH = UDH_EnableEmail; break; | ||
636 | case SMS_VoidSMS : UDH = UDH_VoidSMS; break; | ||
637 | case SMS_Text : UDH = UDH_NoUDH; break; | ||
638 | default : break; | ||
639 | } | ||
640 | UDHHeader.Type = UDH; | ||
641 | GSM_EncodeUDHHeader(&UDHHeader); | ||
642 | memcpy(Buffer,Info->Entries[0].Buffer,UnicodeLength(Info->Entries[0].Buffer)*2+2); | ||
643 | if (Info->UnicodeCoding) { | ||
644 | Coding = SMS_Coding_Unicode; | ||
645 | Length = UnicodeLength(Info->Entries[0].Buffer); | ||
646 | if (Length>(140-UDHHeader.Length)/2) Length = (140-UDHHeader.Length)/2; | ||
647 | } else { | ||
648 | Coding = SMS_Coding_Default; | ||
649 | FindDefaultAlphabetLen(Info->Entries[0].Buffer,&Length,&smslen,(GSM_MAX_8BIT_SMS_LENGTH-UDHHeader.Length)*8/7); | ||
650 | } | ||
651 | break; | ||
652 | case SMS_ConcatenatedAutoTextLong: | ||
653 | case SMS_ConcatenatedAutoTextLong16bit: | ||
654 | smslen = UnicodeLength(Info->Entries[0].Buffer); | ||
655 | memcpy(Buffer,Info->Entries[0].Buffer,smslen*2); | ||
656 | EncodeDefault(Buffer2, Buffer, &smslen, true, NULL); | ||
657 | DecodeDefault(Buffer, Buffer2, smslen, true, NULL); | ||
658 | #ifdef DEBUG | ||
659 | if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) { | ||
660 | dbgprintf("Info->Entries[0].Buffer:\n"); | ||
661 | DumpMessage(di.df, di.dl, Info->Entries[0].Buffer, UnicodeLength(Info->Entries[0].Buffer)*2); | ||
662 | dbgprintf("Buffer:\n"); | ||
663 | DumpMessage(di.df, di.dl, Buffer, UnicodeLength(Buffer)*2); | ||
664 | } | ||
665 | #endif | ||
666 | Info->UnicodeCoding = false; | ||
667 | for (smslen=0;smslen<(int)(UnicodeLength(Info->Entries[0].Buffer)*2);smslen++) { | ||
668 | if (Info->Entries[0].Buffer[smslen] != Buffer[smslen]) { | ||
669 | Info->UnicodeCoding = true; | ||
670 | dbgprintf("Setting to Unicode %i\n",smslen); | ||
671 | break; | ||
672 | } | ||
673 | } | ||
674 | /* No break here - we go to the SMS_ConcatenatedTextLong */ | ||
675 | case SMS_ConcatenatedTextLong: | ||
676 | case SMS_ConcatenatedTextLong16bit: | ||
677 | Class = Info->Class; | ||
678 | memcpy(Buffer,Info->Entries[0].Buffer,UnicodeLength(Info->Entries[0].Buffer)*2+2); | ||
679 | UDH = UDH_NoUDH; | ||
680 | if (Info->UnicodeCoding) { | ||
681 | Coding = SMS_Coding_Unicode; | ||
682 | Length = UnicodeLength(Info->Entries[0].Buffer); | ||
683 | if (Info->Entries[0].ID == SMS_ConcatenatedTextLong16bit || | ||
684 | Info->Entries[0].ID == SMS_ConcatenatedAutoTextLong16bit) { | ||
685 | if (Length>70) UDH=UDH_ConcatenatedMessages16bit; | ||
686 | } else { | ||
687 | if (Length>70) UDH=UDH_ConcatenatedMessages; | ||
688 | } | ||
689 | } else { | ||
690 | Coding = SMS_Coding_Default; | ||
691 | FindDefaultAlphabetLen(Info->Entries[0].Buffer,&Length,&smslen,5000); | ||
692 | if (Info->Entries[0].ID == SMS_ConcatenatedTextLong16bit || | ||
693 | Info->Entries[0].ID == SMS_ConcatenatedAutoTextLong16bit) { | ||
694 | if (smslen>GSM_MAX_SMS_LENGTH) UDH=UDH_ConcatenatedMessages16bit; | ||
695 | } else { | ||
696 | if (smslen>GSM_MAX_SMS_LENGTH) UDH=UDH_ConcatenatedMessages; | ||
697 | } | ||
698 | } | ||
699 | default: | ||
700 | break; | ||
701 | } | ||
702 | GSM_MakeMultiPartSMS(SMS,Buffer,Length,UDH,Coding,Class,Info->ReplaceMessage); | ||
703 | return ERR_NONE; | ||
704 | } | ||
705 | |||
706 | void GSM_ClearMultiPartSMSInfo(GSM_MultiPartSMSInfo *Info) | ||
707 | { | ||
708 | int i; | ||
709 | |||
710 | for (i=0;i<MAX_MULTI_SMS;i++) { | ||
711 | Info->Entries[i].Number = 0; | ||
712 | Info->Entries[i].Ringtone= NULL; | ||
713 | Info->Entries[i].Bitmap = NULL; | ||
714 | Info->Entries[i].Bookmark= NULL; | ||
715 | Info->Entries[i].Settings= NULL; | ||
716 | Info->Entries[i].MMSIndicator= NULL; | ||
717 | Info->Entries[i].Phonebook= NULL; | ||
718 | Info->Entries[i].Calendar= NULL; | ||
719 | Info->Entries[i].ToDo = NULL; | ||
720 | Info->Entries[i].Protected= false; | ||
721 | |||
722 | Info->Entries[i].Buffer = NULL; | ||
723 | Info->Entries[i].Left = false; | ||
724 | Info->Entries[i].Right = false; | ||
725 | Info->Entries[i].Center = false; | ||
726 | Info->Entries[i].Large = false; | ||
727 | Info->Entries[i].Small = false; | ||
728 | Info->Entries[i].Bold = false; | ||
729 | Info->Entries[i].Italic = false; | ||
730 | Info->Entries[i].Underlined= false; | ||
731 | Info->Entries[i].Strikethrough= false; | ||
732 | |||
733 | Info->Entries[i].RingtoneNotes= 0; | ||
734 | } | ||
735 | Info->Unknown = false; | ||
736 | Info->EntriesNum= 0; | ||
737 | Info->Class = -1; | ||
738 | Info->ReplaceMessage= 0; | ||
739 | Info->UnicodeCoding= false; | ||
740 | } | ||
741 | |||
742 | void GSM_FreeMultiPartSMSInfo(GSM_MultiPartSMSInfo *Info) | ||
743 | { | ||
744 | int i; | ||
745 | |||
746 | for (i=0;i<MAX_MULTI_SMS;i++) { | ||
747 | free(Info->Entries[i].Ringtone); | ||
748 | Info->Entries[i].Ringtone = NULL; | ||
749 | free(Info->Entries[i].Bitmap); | ||
750 | Info->Entries[i].Bitmap = NULL; | ||
751 | free(Info->Entries[i].Bookmark); | ||
752 | Info->Entries[i].Bookmark = NULL; | ||
753 | free(Info->Entries[i].Settings); | ||
754 | Info->Entries[i].Settings = NULL; | ||
755 | free(Info->Entries[i].MMSIndicator); | ||
756 | Info->Entries[i].MMSIndicator = NULL; | ||
757 | free(Info->Entries[i].Phonebook); | ||
758 | Info->Entries[i].Phonebook = NULL; | ||
759 | free(Info->Entries[i].Calendar); | ||
760 | Info->Entries[i].Calendar = NULL; | ||
761 | free(Info->Entries[i].ToDo); | ||
762 | Info->Entries[i].ToDo = NULL; | ||
763 | free(Info->Entries[i].Buffer); | ||
764 | Info->Entries[i].Buffer = NULL; | ||
765 | } | ||
766 | } | ||
767 | |||
768 | /* ----------------- Joining SMS from parts -------------------------------- */ | ||
769 | |||
770 | bool GSM_DecodeMultiPartSMS(GSM_MultiPartSMSInfo*Info, | ||
771 | GSM_MultiSMSMessage *SMS, | ||
772 | bool ems) | ||
773 | { | ||
774 | int i, Length = 0; | ||
775 | charBuffer[GSM_MAX_SMS_LENGTH*2*MAX_MULTI_SMS]; | ||
776 | bool emsexist = false; | ||
777 | |||
778 | GSM_ClearMultiPartSMSInfo(Info); | ||
779 | if (ems) { | ||
780 | emsexist = true; | ||
781 | for (i=0;i<SMS->Number;i++) { | ||
782 | if (SMS->SMS[i].UDH.Type != UDH_ConcatenatedMessages && | ||
783 | SMS->SMS[i].UDH.Type != UDH_ConcatenatedMessages16bit && | ||
784 | SMS->SMS[i].UDH.Type != UDH_UserUDH) { | ||
785 | emsexist = false; | ||
786 | break; | ||
787 | } | ||
788 | } | ||
789 | } | ||
790 | |||
791 | /* EMS decoding */ | ||
792 | if (emsexist) return GSM_DecodeEMSMultiPartSMS(Info,SMS); | ||
793 | |||
794 | /* Smart Messaging decoding */ | ||
795 | if (SMS->SMS[0].UDH.Type == UDH_NokiaRingtone && SMS->Number == 1) { | ||
796 | Info->Entries[0].Ringtone = (GSM_Ringtone *)malloc(sizeof(GSM_Ringtone)); | ||
797 | if (Info->Entries[0].Ringtone == NULL) return false; | ||
798 | if (GSM_DecodeNokiaRTTLRingtone(Info->Entries[0].Ringtone, SMS->SMS[0].Text, SMS->SMS[0].Length)==ERR_NONE) { | ||
799 | Info->Entries[0].ID = SMS_NokiaRingtone; | ||
800 | Info->EntriesNum= 1; | ||
801 | return true; | ||
802 | } | ||
803 | } | ||
804 | if (SMS->SMS[0].UDH.Type == UDH_NokiaCallerLogo && SMS->Number == 1) { | ||
805 | Info->Entries[0].Bitmap = (GSM_MultiBitmap *)malloc(sizeof(GSM_MultiBitmap)); | ||
806 | if (Info->Entries[0].Bitmap == NULL) return false; | ||
807 | Info->Entries[0].Bitmap->Number = 1; | ||
808 | PHONE_DecodeBitmap(GSM_NokiaCallerLogo, SMS->SMS[0].Text+4, &Info->Entries[0].Bitmap->Bitmap[0]); | ||
809 | #ifdef DEBUG | ||
810 | if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) GSM_PrintBitmap(di.df,&Info->Entries[0].Bitmap->Bitmap[0]); | ||
811 | #endif | ||
812 | Info->Entries[0].ID = SMS_NokiaCallerLogo; | ||
813 | Info->EntriesNum= 1; | ||
814 | return true; | ||
815 | } | ||
816 | if (SMS->SMS[0].UDH.Type == UDH_NokiaOperatorLogo && SMS->Number == 1) { | ||
817 | Info->Entries[0].Bitmap = (GSM_MultiBitmap *)malloc(sizeof(GSM_MultiBitmap)); | ||
818 | if (Info->Entries[0].Bitmap == NULL) return false; | ||
819 | Info->Entries[0].Bitmap->Number = 1; | ||
820 | PHONE_DecodeBitmap(GSM_NokiaOperatorLogo, SMS->SMS[0].Text+7, &Info->Entries[0].Bitmap->Bitmap[0]); | ||
821 | NOKIA_DecodeNetworkCode(SMS->SMS[0].Text, Info->Entries[0].Bitmap->Bitmap[0].NetworkCode); | ||
822 | #ifdef DEBUG | ||
823 | if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) GSM_PrintBitmap(di.df,&Info->Entries[0].Bitmap->Bitmap[0]); | ||
824 | #endif | ||
825 | Info->Entries[0].ID = SMS_NokiaOperatorLogo; | ||
826 | Info->EntriesNum= 1; | ||
827 | return true; | ||
828 | } | ||
829 | if (SMS->SMS[0].UDH.Type == UDH_NokiaProfileLong) { | ||
830 | for (i=0;i<SMS->Number;i++) { | ||
831 | if (SMS->SMS[i].UDH.Type != UDH_NokiaProfileLong || | ||
832 | SMS->SMS[i].UDH.Text[11] != i+1 || | ||
833 | SMS->SMS[i].UDH.Text[10] != SMS->Number) { | ||
834 | return false; | ||
835 | } | ||
836 | memcpy(Buffer+Length,SMS->SMS[i].Text,SMS->SMS[i].Length); | ||
837 | Length = Length + SMS->SMS[i].Length; | ||
838 | } | ||
839 | Info->EntriesNum = 1; | ||
840 | Info->Entries[0].ID = SMS_NokiaPictureImageLong; | ||
841 | Info->Entries[0].Bitmap = (GSM_MultiBitmap *)malloc(sizeof(GSM_MultiBitmap)); | ||
842 | if (Info->Entries[0].Bitmap == NULL) return false; | ||
843 | Info->Entries[0].Bitmap->Number = 1; | ||
844 | Info->Entries[0].Bitmap->Bitmap[0].Text[0] = 0; | ||
845 | Info->Entries[0].Bitmap->Bitmap[0].Text[1] = 0; | ||
846 | i=1; | ||
847 | while (i!=Length) { | ||
848 | switch (Buffer[i]) { | ||
849 | case SM30_ISOTEXT: | ||
850 | dbgprintf("ISO 8859-2 text\n"); | ||
851 | Info->Unknown = true; | ||
852 | break; | ||
853 | case SM30_UNICODETEXT: | ||
854 | dbgprintf("Unicode text\n"); | ||
855 | memcpy(Info->Entries[0].Bitmap->Bitmap[0].Text,Buffer+i+3,Buffer[i+1]*256+Buffer[i+2]); | ||
856 | Info->Entries[0].Bitmap->Bitmap[0].Text[Buffer[i+1]*256 + Buffer[i+2]] = 0; | ||
857 | Info->Entries[0].Bitmap->Bitmap[0].Text[Buffer[i+1]*256 + Buffer[i+2]+ 1] = 0; | ||
858 | dbgprintf("Unicode Text \"%s\"\n",DecodeUnicodeString(Info->Entries[0].Bitmap->Bitmap[0].Text)); | ||
859 | break; | ||
860 | case SM30_OTA: | ||
861 | dbgprintf("OTA bitmap as Picture Image\n"); | ||
862 | PHONE_DecodeBitmap(GSM_NokiaPictureImage, Buffer + i + 7, &Info->Entries[0].Bitmap->Bitmap[0]); | ||
863 | #ifdef DEBUG | ||
864 | if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) GSM_PrintBitmap(di.df,&Info->Entries[0].Bitmap->Bitmap[0]); | ||
865 | #endif | ||
866 | break; | ||
867 | case SM30_RINGTONE: | ||
868 | dbgprintf("RTTL ringtone\n"); | ||
869 | Info->Unknown = true; | ||
870 | break; | ||
871 | case SM30_PROFILENAME: | ||
872 | dbgprintf("Profile Name\n"); | ||
873 | Info->Entries[0].ID = SMS_NokiaProfileLong; | ||
874 | Info->Unknown = true; | ||
875 | break; | ||
876 | case SM30_SCREENSAVER: | ||
877 | dbgprintf("OTA bitmap as Screen Saver\n"); | ||
878 | PHONE_DecodeBitmap(GSM_NokiaPictureImage, Buffer + i + 7, &Info->Entries[0].Bitmap->Bitmap[0]); | ||
879 | #ifdef DEBUG | ||
880 | if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) GSM_PrintBitmap(di.df,&Info->Entries[0].Bitmap->Bitmap[0]); | ||
881 | #endif | ||
882 | Info->Entries[0].ID = SMS_NokiaScreenSaverLong; | ||
883 | break; | ||
884 | } | ||
885 | i = i + Buffer[i+1]*256 + Buffer[i+2] + 3; | ||
886 | dbgprintf("%i %i\n",i,Length); | ||
887 | } | ||
888 | return true; | ||
889 | } | ||
890 | |||
891 | /* Linked sms */ | ||
892 | if (SMS->SMS[0].UDH.Type == UDH_ConcatenatedMessages || | ||
893 | SMS->SMS[0].UDH.Type == UDH_ConcatenatedMessages16bit) { | ||
894 | Info->EntriesNum = 1; | ||
895 | Info->Entries[0].ID = SMS_ConcatenatedTextLong; | ||
896 | if (SMS->SMS[0].UDH.Type == UDH_ConcatenatedMessages16bit) { | ||
897 | Info->Entries[0].ID = SMS_ConcatenatedTextLong16bit; | ||
898 | } | ||
899 | |||
900 | for (i=0;i<SMS->Number;i++) { | ||
901 | switch (SMS->SMS[i].Coding) { | ||
902 | case SMS_Coding_8bit: | ||
903 | Info->Entries[0].Buffer = realloc(Info->Entries[0].Buffer, Length + SMS->SMS[i].Length + 2); | ||
904 | if (Info->Entries[0].Buffer == NULL) return false; | ||
905 | |||
906 | memcpy(Info->Entries[0].Buffer + Length, SMS->SMS[i].Text, SMS->SMS[i].Length); | ||
907 | Length=Length+SMS->SMS[i].Length; | ||
908 | break; | ||
909 | case SMS_Coding_Unicode: | ||
910 | if (Info->Entries[0].ID == SMS_ConcatenatedTextLong) { | ||
911 | Info->Entries[0].ID = SMS_ConcatenatedAutoTextLong; | ||
912 | } | ||
913 | if (Info->Entries[0].ID == SMS_ConcatenatedTextLong16bit) { | ||
914 | Info->Entries[0].ID = SMS_ConcatenatedAutoTextLong16bit; | ||
915 | } | ||
916 | case SMS_Coding_Default: | ||
917 | Info->Entries[0].Buffer = realloc(Info->Entries[0].Buffer, Length + UnicodeLength(SMS->SMS[i].Text)*2 + 2); | ||
918 | if (Info->Entries[0].Buffer == NULL) return false; | ||
919 | |||
920 | memcpy(Info->Entries[0].Buffer+Length,SMS->SMS[i].Text,UnicodeLength(SMS->SMS[i].Text)*2); | ||
921 | Length=Length+UnicodeLength(SMS->SMS[i].Text)*2; | ||
922 | break; | ||
923 | } | ||
924 | } | ||
925 | Info->Entries[0].Buffer[Length] = 0; | ||
926 | Info->Entries[0].Buffer[Length+1] = 0; | ||
927 | return true; | ||
928 | } | ||
929 | |||
930 | return false; | ||
931 | } | ||
932 | |||
933 | GSM_Error GSM_LinkSMS(GSM_MultiSMSMessage **INPUT, GSM_MultiSMSMessage **OUTPUT, bool ems) | ||
934 | { | ||
935 | bool *INPUTSorted, copyit; | ||
936 | int i,OUTPUTNum,j,z,w; | ||
937 | |||
938 | i = 0; | ||
939 | while (INPUT[i] != NULL) i++; | ||
940 | |||
941 | INPUTSorted = calloc(i, sizeof(bool)); | ||
942 | if (INPUTSorted == NULL) return ERR_MOREMEMORY; | ||
943 | |||
944 | OUTPUTNum = 0; | ||
945 | OUTPUT[0] = NULL; | ||
946 | |||
947 | if (ems) { | ||
948 | i=0; | ||
949 | while (INPUT[i] != NULL) { | ||
950 | if (INPUT[i]->SMS[0].UDH.Type == UDH_UserUDH) { | ||
951 | w=1; | ||
952 | while (w < INPUT[i]->SMS[0].UDH.Length) { | ||
953 | switch(INPUT[i]->SMS[0].UDH.Text[w]) { | ||
954 | case 0x00: | ||
955 | dbgprintf("Adding ID to user UDH - linked SMS with 8 bit ID\n"); | ||
956 | INPUT[i]->SMS[0].UDH.ID8bit= INPUT[i]->SMS[0].UDH.Text[w+2]; | ||
957 | INPUT[i]->SMS[0].UDH.AllParts= INPUT[i]->SMS[0].UDH.Text[w+3]; | ||
958 | INPUT[i]->SMS[0].UDH.PartNumber= INPUT[i]->SMS[0].UDH.Text[w+4]; | ||
959 | break; | ||
960 | case 0x08: | ||
961 | dbgprintf("Adding ID to user UDH - linked SMS with 16 bit ID\n"); | ||
962 | INPUT[i]->SMS[0].UDH.ID16bit= INPUT[i]->SMS[0].UDH.Text[w+2]*256+INPUT[i]->SMS[0].UDH.Text[w+3]; | ||
963 | INPUT[i]->SMS[0].UDH.AllParts= INPUT[i]->SMS[0].UDH.Text[w+4]; | ||
964 | INPUT[i]->SMS[0].UDH.PartNumber= INPUT[i]->SMS[0].UDH.Text[w+5]; | ||
965 | break; | ||
966 | default: | ||
967 | dbgprintf("Block %02x\n",INPUT[i]->SMS[0].UDH.Text[w]); | ||
968 | } | ||
969 | dbgprintf("%i %i %i %i\n", | ||
970 | INPUT[i]->SMS[0].UDH.ID8bit, | ||
971 | INPUT[i]->SMS[0].UDH.ID16bit, | ||
972 | INPUT[i]->SMS[0].UDH.PartNumber, | ||
973 | INPUT[i]->SMS[0].UDH.AllParts); | ||
974 | w=w+INPUT[i]->SMS[0].UDH.Text[w+1]+2; | ||
975 | } | ||
976 | } | ||
977 | i++; | ||
978 | } | ||
979 | } | ||
980 | |||
981 | i=0; | ||
982 | while (INPUT[i]!=NULL) { | ||
983 | /* If this one SMS was sorted earlier, do not touch */ | ||
984 | if (INPUTSorted[i]) { | ||
985 | i++; | ||
986 | continue; | ||
987 | } | ||
988 | copyit = false; | ||
989 | /* If we have: | ||
990 | * - linked sms returned by phone driver | ||
991 | * - sms without linking | ||
992 | * we copy it to OUTPUT | ||
993 | */ | ||
994 | if (INPUT[i]->Number != 1 || | ||
995 | INPUT[i]->SMS[0].UDH.Type == UDH_NoUDH || | ||
996 | INPUT[i]->SMS[0].UDH.PartNumber == -1) { | ||
997 | copyit = true; | ||
998 | } | ||
999 | /* If we have unknown UDH, we copy it to OUTPUT */ | ||
1000 | if (INPUT[i]->SMS[0].UDH.Type == UDH_UserUDH) { | ||
1001 | if (!ems) copyit = true; | ||
1002 | if (ems && INPUT[i]->SMS[0].UDH.PartNumber == -1) copyit = true; | ||
1003 | } | ||
1004 | if (copyit) { | ||
1005 | OUTPUT[OUTPUTNum] = malloc(sizeof(GSM_MultiSMSMessage)); | ||
1006 | if (OUTPUT[OUTPUTNum] == NULL) { | ||
1007 | free(INPUTSorted); | ||
1008 | return ERR_MOREMEMORY; | ||
1009 | } | ||
1010 | OUTPUT[OUTPUTNum+1] = NULL; | ||
1011 | |||
1012 | memcpy(OUTPUT[OUTPUTNum],INPUT[i],sizeof(GSM_MultiSMSMessage)); | ||
1013 | INPUTSorted[i]=true; | ||
1014 | OUTPUTNum++; | ||
1015 | i = 0; | ||
1016 | continue; | ||
1017 | } | ||
1018 | /* We have 1'st part of linked sms. It's single. | ||
1019 | * We will try to find other parts | ||
1020 | */ | ||
1021 | if (INPUT[i]->SMS[0].UDH.PartNumber == 1) { | ||
1022 | OUTPUT[OUTPUTNum] = malloc(sizeof(GSM_MultiSMSMessage)); | ||
1023 | if (OUTPUT[OUTPUTNum] == NULL) { | ||
1024 | free(INPUTSorted); | ||
1025 | return ERR_MOREMEMORY; | ||
1026 | } | ||
1027 | OUTPUT[OUTPUTNum+1] = NULL; | ||
1028 | |||
1029 | memcpy(&OUTPUT[OUTPUTNum]->SMS[0],&INPUT[i]->SMS[0],sizeof(GSM_SMSMessage)); | ||
1030 | OUTPUT[OUTPUTNum]->Number = 1; | ||
1031 | INPUTSorted[i]= true; | ||
1032 | j = 1; | ||
1033 | /* We're searching for other parts in sequence */ | ||
1034 | while (j!=INPUT[i]->SMS[0].UDH.AllParts) { | ||
1035 | z=0; | ||
1036 | while(INPUT[z]!=NULL) { | ||
1037 | /* This was sorted earlier or is not single */ | ||
1038 | if (INPUTSorted[z] || INPUT[z]->Number != 1) { | ||
1039 | z++; | ||
1040 | continue; | ||
1041 | } | ||
1042 | if (ems && INPUT[i]->SMS[0].UDH.Type != UDH_ConcatenatedMessages && | ||
1043 | INPUT[i]->SMS[0].UDH.Type != UDH_ConcatenatedMessages16bit && | ||
1044 | INPUT[i]->SMS[0].UDH.Type != UDH_UserUDH && | ||
1045 | INPUT[z]->SMS[0].UDH.Type != UDH_ConcatenatedMessages && | ||
1046 | INPUT[z]->SMS[0].UDH.Type != UDH_ConcatenatedMessages16bit && | ||
1047 | INPUT[z]->SMS[0].UDH.Type != UDH_UserUDH) { | ||
1048 | if (INPUT[z]->SMS[0].UDH.Type != INPUT[i]->SMS[0].UDH.Type) { | ||
1049 | z++; | ||
1050 | continue; | ||
1051 | } | ||
1052 | } | ||
1053 | if (!ems && INPUT[z]->SMS[0].UDH.Type != INPUT[i]->SMS[0].UDH.Type) { | ||
1054 | z++; | ||
1055 | continue; | ||
1056 | } | ||
1057 | dbgprintf("compare %i %i %i %i %i", | ||
1058 | j+1, | ||
1059 | INPUT[i]->SMS[0].UDH.ID8bit, | ||
1060 | INPUT[i]->SMS[0].UDH.ID16bit, | ||
1061 | INPUT[i]->SMS[0].UDH.PartNumber, | ||
1062 | INPUT[i]->SMS[0].UDH.AllParts); | ||
1063 | dbgprintf(" %i %i %i %i\n", | ||
1064 | INPUT[z]->SMS[0].UDH.ID8bit, | ||
1065 | INPUT[z]->SMS[0].UDH.ID16bit, | ||
1066 | INPUT[z]->SMS[0].UDH.PartNumber, | ||
1067 | INPUT[z]->SMS[0].UDH.AllParts); | ||
1068 | if (INPUT[z]->SMS[0].UDH.ID8bit != INPUT[i]->SMS[0].UDH.ID8bit|| | ||
1069 | INPUT[z]->SMS[0].UDH.ID16bit != INPUT[i]->SMS[0].UDH.ID16bit|| | ||
1070 | INPUT[z]->SMS[0].UDH.AllParts != INPUT[i]->SMS[0].UDH.AllParts || | ||
1071 | INPUT[z]->SMS[0].UDH.PartNumber != j+1) { | ||
1072 | z++; | ||
1073 | continue; | ||
1074 | } | ||
1075 | /* For SMS_Deliver compare also SMSC and Sender number */ | ||
1076 | if (INPUT[z]->SMS[0].PDU == SMS_Deliver && | ||
1077 | (strcmp(DecodeUnicodeString(INPUT[z]->SMS[0].SMSC.Number),DecodeUnicodeString(INPUT[i]->SMS[0].SMSC.Number)) || | ||
1078 | strcmp(DecodeUnicodeString(INPUT[z]->SMS[0].Number),DecodeUnicodeString(INPUT[i]->SMS[0].Number)))) { | ||
1079 | z++; | ||
1080 | continue; | ||
1081 | } | ||
1082 | /* DCT4 Outbox: SMS Deliver. Empty number and SMSC. We compare dates */ | ||
1083 | if (INPUT[z]->SMS[0].PDU == SMS_Deliver && | ||
1084 | UnicodeLength(INPUT[z]->SMS[0].SMSC.Number)==0 && | ||
1085 | UnicodeLength(INPUT[z]->SMS[0].Number)==0 && | ||
1086 | (INPUT[z]->SMS[0].DateTime.Day != INPUT[i]->SMS[0].DateTime.Day || | ||
1087 | INPUT[z]->SMS[0].DateTime.Month != INPUT[i]->SMS[0].DateTime.Month || | ||
1088 | INPUT[z]->SMS[0].DateTime.Year != INPUT[i]->SMS[0].DateTime.Year || | ||
1089 | INPUT[z]->SMS[0].DateTime.Hour != INPUT[i]->SMS[0].DateTime.Hour || | ||
1090 | INPUT[z]->SMS[0].DateTime.Minute != INPUT[i]->SMS[0].DateTime.Minute || | ||
1091 | INPUT[z]->SMS[0].DateTime.Second != INPUT[i]->SMS[0].DateTime.Second)) { | ||
1092 | z++; | ||
1093 | continue; | ||
1094 | } | ||
1095 | /* We found correct sms. Copy it */ | ||
1096 | memcpy(&OUTPUT[OUTPUTNum]->SMS[j],&INPUT[z]->SMS[0],sizeof(GSM_SMSMessage)); | ||
1097 | OUTPUT[OUTPUTNum]->Number++; | ||
1098 | INPUTSorted[z]=true; | ||
1099 | break; | ||
1100 | } | ||
1101 | /* Incomplete sequence */ | ||
1102 | if (OUTPUT[OUTPUTNum]->Number==j) { | ||
1103 | dbgprintf("Incomplete sequence\n"); | ||
1104 | break; | ||
1105 | } | ||
1106 | j++; | ||
1107 | } | ||
1108 | OUTPUTNum++; | ||
1109 | i = 0; | ||
1110 | continue; | ||
1111 | } | ||
1112 | /* We have some next linked sms from sequence */ | ||
1113 | if (INPUT[i]->SMS[0].UDH.PartNumber > 1) { | ||
1114 | j = 0; | ||
1115 | while (INPUT[j]!=NULL) { | ||
1116 | if (INPUTSorted[j]) { | ||
1117 | j++; | ||
1118 | continue; | ||
1119 | } | ||
1120 | /* We have some not unassigned first sms from sequence. | ||
1121 | * We can't touch other sms from sequences | ||
1122 | */ | ||
1123 | if (INPUT[j]->SMS[0].UDH.PartNumber == 1) break; | ||
1124 | j++; | ||
1125 | } | ||
1126 | if (INPUT[j]==NULL) { | ||
1127 | OUTPUT[OUTPUTNum] = malloc(sizeof(GSM_MultiSMSMessage)); | ||
1128 | if (OUTPUT[OUTPUTNum] == NULL) { | ||
1129 | free(INPUTSorted); | ||
1130 | return ERR_MOREMEMORY; | ||
1131 | } | ||
1132 | OUTPUT[OUTPUTNum+1] = NULL; | ||
1133 | |||
1134 | memcpy(OUTPUT[OUTPUTNum],INPUT[i],sizeof(GSM_MultiSMSMessage)); | ||
1135 | INPUTSorted[i]=true; | ||
1136 | OUTPUTNum++; | ||
1137 | i = 0; | ||
1138 | continue; | ||
1139 | } else i++; | ||
1140 | } | ||
1141 | } | ||
1142 | free(INPUTSorted); | ||
1143 | return ERR_NONE; | ||
1144 | } | ||
1145 | |||
1146 | /* How should editor hadle tabs in this file? Add editor commands here. | ||
1147 | * vim: noexpandtab sw=8 ts=8 sts=8: | ||
1148 | */ | ||
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 @@ | |||
1 | /* (c) 2002-2004 by Marcin Wiacek */ | ||
2 | |||
3 | #ifndef __gsm_multi_h | ||
4 | #define __gsm_multi_h | ||
5 | |||
6 | #include "../../gsmcomon.h" | ||
7 | #include "../gsmlogo.h" | ||
8 | #include "../gsmcal.h" | ||
9 | #include "../gsmpbk.h" | ||
10 | #include "../gsmdata.h" | ||
11 | #include "../gsmring.h" | ||
12 | #include "gsmsms.h" | ||
13 | |||
14 | /* ---------------------- multi SMS --------------------------------------- */ | ||
15 | |||
16 | /* Identifiers for Smart Messaging 3.0 multipart SMS */ | ||
17 | |||
18 | #define SM30_ISOTEXT 0 /* ISO 8859-1 text */ | ||
19 | #define SM30_UNICODETEXT 1 | ||
20 | #define SM30_OTA 2 | ||
21 | #define SM30_RINGTONE 3 | ||
22 | #define SM30_PROFILENAME 4 | ||
23 | /* ... */ | ||
24 | #define SM30_SCREENSAVER 6 | ||
25 | |||
26 | /* Identifiers for Alcatel Terminal Data Download */ | ||
27 | #define ALCATELTDD_PICTURE 4 | ||
28 | #define ALCATELTDD_ANIMATION 5 | ||
29 | #define ALCATELTDD_SMSTEMPLATE 6 | ||
30 | |||
31 | void GSM_SMSCounter(int MessageLength, | ||
32 | unsigned char *MessageBuffer, | ||
33 | GSM_UDH UDHType, | ||
34 | GSM_Coding_Type Coding, | ||
35 | int *SMSNum, | ||
36 | int *CharsLeft); | ||
37 | |||
38 | #define MAX_MULTI_SMS 10 | ||
39 | |||
40 | /** | ||
41 | * Multiple SMS messages, used for Smart Messaging 3.0/EMS. | ||
42 | */ | ||
43 | typedef struct { | ||
44 | /** | ||
45 | * Sender or recipient number. | ||
46 | */ | ||
47 | unsigned char Number; | ||
48 | /** | ||
49 | * Array of SMSes. | ||
50 | */ | ||
51 | GSM_SMSMessage SMS[MAX_MULTI_SMS]; | ||
52 | } GSM_MultiSMSMessage; | ||
53 | |||
54 | GSM_Error GSM_AddSMS_Text_UDH(GSM_MultiSMSMessage *SMS, | ||
55 | GSM_Coding_Type Coding, | ||
56 | char *Buffer, | ||
57 | int BufferLen, | ||
58 | bool UDH, | ||
59 | int *UsedText, | ||
60 | int *CopiedText, | ||
61 | int *CopiedSMSText); | ||
62 | |||
63 | void GSM_MakeMultiPartSMS(GSM_MultiSMSMessage *SMS, | ||
64 | unsigned char *MessageBuffer, | ||
65 | int MessageLength, | ||
66 | GSM_UDH UDHType, | ||
67 | GSM_Coding_Type Coding, | ||
68 | int Class, | ||
69 | unsigned char RejectDuplicates); | ||
70 | |||
71 | void GSM_Find_Free_Used_SMS2(GSM_Coding_Type Coding,GSM_SMSMessage SMS, int *UsedText, int *FreeText, int *FreeBytes); | ||
72 | |||
73 | unsigned char GSM_MakeSMSIDFromTime(void); | ||
74 | |||
75 | /** | ||
76 | * ID during packing SMS for Smart Messaging 3.0, EMS and other | ||
77 | */ | ||
78 | typedef enum { | ||
79 | /** | ||
80 | * 1 text SMS. | ||
81 | */ | ||
82 | SMS_Text = 1, | ||
83 | /** | ||
84 | * Contacenated SMS, when longer than 1 SMS. | ||
85 | */ | ||
86 | SMS_ConcatenatedTextLong, | ||
87 | /** | ||
88 | * Contacenated SMS, auto Default/Unicode coding. | ||
89 | */ | ||
90 | SMS_ConcatenatedAutoTextLong, | ||
91 | SMS_ConcatenatedTextLong16bit, | ||
92 | SMS_ConcatenatedAutoTextLong16bit, | ||
93 | /** | ||
94 | * Nokia profile = Name, Ringtone, ScreenSaver | ||
95 | */ | ||
96 | SMS_NokiaProfileLong, | ||
97 | /** | ||
98 | * Nokia Picture Image + (text) | ||
99 | */ | ||
100 | SMS_NokiaPictureImageLong, | ||
101 | /** | ||
102 | * Nokia screen saver + (text) | ||
103 | */ | ||
104 | SMS_NokiaScreenSaverLong, | ||
105 | /** | ||
106 | * Nokia ringtone - old SM2.0 format, 1 SMS | ||
107 | */ | ||
108 | SMS_NokiaRingtone, | ||
109 | /** | ||
110 | * Nokia ringtone contacenated, when very long | ||
111 | */ | ||
112 | SMS_NokiaRingtoneLong, | ||
113 | /** | ||
114 | * Nokia 72x14 operator logo, 1 SMS | ||
115 | */ | ||
116 | SMS_NokiaOperatorLogo, | ||
117 | /** | ||
118 | * Nokia 72x14 op logo or 78x21 in 2 SMS | ||
119 | */ | ||
120 | SMS_NokiaOperatorLogoLong, | ||
121 | /** | ||
122 | * Nokia 72x14 caller logo, 1 SMS | ||
123 | */ | ||
124 | SMS_NokiaCallerLogo, | ||
125 | /** | ||
126 | * Nokia WAP bookmark in 1 or 2 SMS | ||
127 | */ | ||
128 | SMS_NokiaWAPBookmarkLong, | ||
129 | /** | ||
130 | * Nokia WAP settings in 2 SMS | ||
131 | */ | ||
132 | SMS_NokiaWAPSettingsLong, | ||
133 | /** | ||
134 | * Nokia MMS settings in 2 SMS | ||
135 | */ | ||
136 | SMS_NokiaMMSSettingsLong, | ||
137 | /** | ||
138 | * Nokia VCARD 1.0 - only name and default number | ||
139 | */ | ||
140 | SMS_NokiaVCARD10Long, | ||
141 | /** | ||
142 | * Nokia VCARD 2.1 - all numbers + text | ||
143 | */ | ||
144 | SMS_NokiaVCARD21Long, | ||
145 | /** | ||
146 | * Nokia VCALENDAR 1.0 - can be in few sms | ||
147 | */ | ||
148 | SMS_NokiaVCALENDAR10Long, | ||
149 | SMS_NokiaVTODOLong, | ||
150 | SMS_VCARD10Long, | ||
151 | SMS_VCARD21Long, | ||
152 | SMS_DisableVoice, | ||
153 | SMS_DisableFax, | ||
154 | SMS_DisableEmail, | ||
155 | SMS_EnableVoice, | ||
156 | SMS_EnableFax, | ||
157 | SMS_EnableEmail, | ||
158 | SMS_VoidSMS, | ||
159 | /** | ||
160 | * IMelody 1.0 | ||
161 | */ | ||
162 | SMS_EMSSound10, | ||
163 | /** | ||
164 | * IMelody 1.2 | ||
165 | */ | ||
166 | SMS_EMSSound12, | ||
167 | /** | ||
168 | * IMelody without header - SonyEricsson extension | ||
169 | */ | ||
170 | SMS_EMSSonyEricssonSound, | ||
171 | /** | ||
172 | * IMelody 1.0 with UPI. | ||
173 | */ | ||
174 | SMS_EMSSound10Long, | ||
175 | /*** | ||
176 | * IMelody 1.2 with UPI. | ||
177 | */ | ||
178 | SMS_EMSSound12Long, | ||
179 | /** | ||
180 | * IMelody without header with UPI. | ||
181 | */ | ||
182 | SMS_EMSSonyEricssonSoundLong, | ||
183 | SMS_EMSPredefinedSound, | ||
184 | SMS_EMSPredefinedAnimation, | ||
185 | SMS_EMSAnimation, | ||
186 | /** | ||
187 | * Fixed bitmap of size 16x16 or 32x32. | ||
188 | */ | ||
189 | SMS_EMSFixedBitmap, | ||
190 | SMS_EMSVariableBitmap, | ||
191 | SMS_EMSVariableBitmapLong, | ||
192 | SMS_MMSIndicatorLong, | ||
193 | /** | ||
194 | * Variable bitmap with black and white colors | ||
195 | */ | ||
196 | SMS_AlcatelMonoBitmapLong, | ||
197 | /** | ||
198 | * Variable animation with black and white colors | ||
199 | */ | ||
200 | SMS_AlcatelMonoAnimationLong, | ||
201 | SMS_AlcatelSMSTemplateName | ||
202 | } EncodeMultiPartSMSID; | ||
203 | |||
204 | typedef struct { | ||
205 | EncodeMultiPartSMSID ID; | ||
206 | |||
207 | int Number; | ||
208 | GSM_Ringtone *Ringtone; | ||
209 | GSM_MultiBitmap *Bitmap; | ||
210 | GSM_WAPBookmark *Bookmark; | ||
211 | GSM_WAPSettings *Settings; | ||
212 | GSM_MMSIndicator*MMSIndicator; | ||
213 | GSM_MemoryEntry *Phonebook; | ||
214 | GSM_CalendarEntry *Calendar; | ||
215 | GSM_ToDoEntry *ToDo; | ||
216 | bool Protected; | ||
217 | |||
218 | unsigned char *Buffer; | ||
219 | bool Left; | ||
220 | bool Right; | ||
221 | bool Center; | ||
222 | bool Large; | ||
223 | bool Small; | ||
224 | bool Bold; | ||
225 | bool Italic; | ||
226 | bool Underlined; | ||
227 | bool Strikethrough; | ||
228 | |||
229 | /* Return values */ | ||
230 | int RingtoneNotes; | ||
231 | } MultiPartSMSEntry; | ||
232 | |||
233 | typedef struct { | ||
234 | MultiPartSMSEntryEntries[MAX_MULTI_SMS]; | ||
235 | int EntriesNum; | ||
236 | bool UnicodeCoding; | ||
237 | int Class; | ||
238 | unsigned char ReplaceMessage; | ||
239 | bool Unknown; | ||
240 | } GSM_MultiPartSMSInfo; | ||
241 | |||
242 | /** | ||
243 | * Encodes multi part SMS from "readable" format. | ||
244 | */ | ||
245 | GSM_Error GSM_EncodeMultiPartSMS (GSM_MultiPartSMSInfo *Info, GSM_MultiSMSMessage *SMS); | ||
246 | |||
247 | /** | ||
248 | * Decodes multi part SMS to "readable" format. | ||
249 | */ | ||
250 | bool GSM_DecodeMultiPartSMS (GSM_MultiPartSMSInfo *Info, GSM_MultiSMSMessage *SMS, bool ems); | ||
251 | |||
252 | /** | ||
253 | * Clears @ref GSM_MultiPartSMSInfo to default values. | ||
254 | */ | ||
255 | void GSM_ClearMultiPartSMSInfo (GSM_MultiPartSMSInfo *Info); | ||
256 | |||
257 | /** | ||
258 | * Frees any allocated structures inside @ref GSM_MultiPartSMSInfo. | ||
259 | */ | ||
260 | void GSM_FreeMultiPartSMSInfo (GSM_MultiPartSMSInfo *Info); | ||
261 | |||
262 | /** | ||
263 | * Links SMS messages according to IDs. | ||
264 | */ | ||
265 | GSM_Error GSM_LinkSMS(GSM_MultiSMSMessage **INPUT, GSM_MultiSMSMessage **OUTPUT, bool ems); | ||
266 | |||
267 | #endif | ||
268 | |||
269 | /* How should editor hadle tabs in this file? Add editor commands here. | ||
270 | * vim: noexpandtab sw=8 ts=8 sts=8: | ||
271 | */ | ||
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 @@ | |||
1 | /* (c) 2001-2004 by Marcin Wiacek */ | ||
2 | /* based on some work from Pawel Kot, others and Gnokii */ | ||
3 | |||
4 | #include <ctype.h> | ||
5 | #include <string.h> | ||
6 | #include <time.h> | ||
7 | |||
8 | #include "../../gsmcomon.h" | ||
9 | #include "../../misc/coding/coding.h" | ||
10 | #include "../gsmcal.h" | ||
11 | #include "../gsmpbk.h" | ||
12 | #include "../gsmlogo.h" | ||
13 | #include "../gsmring.h" | ||
14 | #include "../gsmdata.h" | ||
15 | #include "../gsmnet.h" | ||
16 | #include "gsmsms.h" | ||
17 | |||
18 | /* User data headers */ | ||
19 | static GSM_UDHHeader UDHHeaders[] = { | ||
20 | /* See GSM 03.40 section 9.2.3.24.1 | ||
21 | * 1 byte 0x00 | ||
22 | * 1 byte 0x03 | ||
23 | * 1 byte 0x01: unique ID for message series | ||
24 | * 1 byte 0x00: how many SMS in sequence | ||
25 | * 1 byte 0x00: number of current SMS in sequence */ | ||
26 | { UDH_ConcatenatedMessages, 0x05, "\x00\x03\x01\x00\x00",2,-1,4,3}, | ||
27 | |||
28 | /* See GSM 03.40 section 9.2.3.24.2 for voice, fax and email messages */ | ||
29 | { UDH_DisableVoice, 0x04, "\x01\x02\x00\x00",-1,-1,-1,-1}, | ||
30 | { UDH_DisableFax, 0x04, "\x01\x02\x01\x00",-1,-1,-1,-1}, | ||
31 | { UDH_DisableEmail, 0x04, "\x01\x02\x02\x00",-1,-1,-1,-1}, | ||
32 | { UDH_EnableVoice, 0x04, "\x01\x02\x00\x01",-1,-1,-1,-1}, | ||
33 | { UDH_EnableFax, 0x04, "\x01\x02\x01\x01",-1,-1,-1,-1}, | ||
34 | { UDH_EnableEmail, 0x04, "\x01\x02\x02\x01",-1,-1,-1,-1}, | ||
35 | |||
36 | /* When send such SMS to some phones, they don't display anything, | ||
37 | * only beep and enable vibra/light | ||
38 | */ | ||
39 | { UDH_VoidSMS, 0x08, "\x01\x02\x02\x01\x01\x02\x02\x00",-1,-1,-1,-1}, | ||
40 | |||
41 | /* Nokia Smart Messaging (short version) UDH | ||
42 | * General format : | ||
43 | * 1 byte 0x05 : IEI application port addressing scheme, 16 bit address | ||
44 | * 1 byte 0x04 : IEI length | ||
45 | * 2 bytes : destination address : high & low byte | ||
46 | * 2 bytes 0x00 0x00 : originator address : high & low byte */ | ||
47 | { UDH_NokiaRingtone, 0x06, "\x05\x04\x15\x81\x00\x00",-1,-1,-1,-1}, | ||
48 | { UDH_NokiaOperatorLogo, 0x06, "\x05\x04\x15\x82\x00\x00",-1,-1,-1,-1}, | ||
49 | { UDH_NokiaCallerLogo, 0x06, "\x05\x04\x15\x83\x00\x00",-1,-1,-1,-1}, | ||
50 | { UDH_NokiaWAP, 0x06, "\x05\x04\xc3\x4f\x00\x00",-1,-1,-1,-1}, | ||
51 | |||
52 | /* Nokia Smart Messaging (long version) UDH and other | ||
53 | * General format: | ||
54 | * 1 byte 0x05 : IEI application port addressing scheme, 16 bit address | ||
55 | * 1 byte 0x04 : IEI length | ||
56 | * 2 bytes 0x00 0x00 : destination address : high & low byte | ||
57 | * 2 bytes 0x00 0x00 : originator address : high & low byte | ||
58 | * 1 byte 0x00 : SAR | ||
59 | * 1 byte 0x03 : SAR length | ||
60 | * 1 byte : diagram reference number (unique ID for message series) | ||
61 | * 1 byte : number of all SMS | ||
62 | * 1 byte : number of current SMS */ | ||
63 | { UDH_NokiaCalendarLong, 0x0b, "\x05\x04\x00\xe4\x00\x00\x00\x03\xc7\x00\x00",8,-1,10,9}, | ||
64 | { UDH_MMSIndicatorLong, 0x0b, "\x05\x04\x0b\x84\x23\xf0\x00\x03\xe5\x00\x00",8,-1,10,9}, | ||
65 | { UDH_NokiaRingtoneLong, 0x0b, "\x05\x04\x15\x81\x00\x00\x00\x03\x01\x00\x00",8,-1,10,9}, | ||
66 | { UDH_NokiaOperatorLogoLong, 0x0b, "\x05\x04\x15\x82\x00\x00\x00\x03\x02\x00\x00",8,-1,10,9}, | ||
67 | { UDH_NokiaProfileLong, 0x0b, "\x05\x04\x15\x8a\x00\x00\x00\x03\xce\x00\x00",8,-1,10,9}, | ||
68 | { UDH_NokiaPhonebookLong, 0x0b, "\x05\x04\x23\xf4\x00\x00\x00\x03\x01\x00\x00",8,-1,10,9}, | ||
69 | { UDH_NokiaWAPLong, 0x0b, "\x05\x04\xc3\x4f\x00\x00\x00\x03\x7f\x00\x00",8,-1,10,9}, | ||
70 | |||
71 | { UDH_ConcatenatedMessages16bit,0x06, "\x08\x04\x00\x00\x00\x00",-1,2,5,4}, | ||
72 | |||
73 | { UDH_NoUDH, 0x00, "",-1,-1,-1,-1} | ||
74 | }; | ||
75 | |||
76 | /* --------------------------- Unpacking SMS ------------------------------- */ | ||
77 | |||
78 | /* See GSM 03.40 section 9.2.3.11 */ | ||
79 | static GSM_Error GSM_DecodeSMSDateTime(GSM_DateTime *DT, unsigned char *req) | ||
80 | { | ||
81 | DT->Year = DecodeWithBCDAlphabet(req[0]); | ||
82 | if (DT->Year<90) DT->Year=DT->Year+2000; else DT->Year=DT->Year+1990; | ||
83 | DT->Month = DecodeWithBCDAlphabet(req[1]); | ||
84 | DT->Day = DecodeWithBCDAlphabet(req[2]); | ||
85 | DT->Hour = DecodeWithBCDAlphabet(req[3]); | ||
86 | DT->Minute = DecodeWithBCDAlphabet(req[4]); | ||
87 | DT->Second = DecodeWithBCDAlphabet(req[5]); | ||
88 | |||
89 | /* Base for timezone is GMT. It's in quarters */ | ||
90 | DT->Timezone=(10*(req[6]&0x07)+(req[6]>>4))/4; | ||
91 | |||
92 | if (req[6]&0x08) DT->Timezone = -DT->Timezone; | ||
93 | |||
94 | dbgprintf("Decoding date & time: "); | ||
95 | dbgprintf("%s %4d/%02d/%02d ", DayOfWeek(DT->Year, DT->Month, DT->Day), | ||
96 | DT->Year, DT->Month, DT->Day); | ||
97 | dbgprintf("%02d:%02d:%02d %02d00\n", DT->Hour, DT->Minute, DT->Second, DT->Timezone); | ||
98 | |||
99 | return ERR_NONE; | ||
100 | } | ||
101 | |||
102 | void GSM_DecodeUDHHeader(GSM_UDHHeader *UDH) | ||
103 | { | ||
104 | inti, tmp, w; | ||
105 | boolUDHOK; | ||
106 | |||
107 | UDH->Type = UDH_UserUDH; | ||
108 | UDH->ID8bit= -1; | ||
109 | UDH->ID16bit= -1; | ||
110 | UDH->PartNumber= -1; | ||
111 | UDH->AllParts= -1; | ||
112 | |||
113 | i=-1; | ||
114 | while (true) { | ||
115 | i++; | ||
116 | if (UDHHeaders[i].Type==UDH_NoUDH) break; | ||
117 | |||
118 | tmp=UDHHeaders[i].Length; | ||
119 | /* if length is the same */ | ||
120 | if (tmp==UDH->Text[0]) { | ||
121 | |||
122 | if (tmp==0x05) tmp=tmp-3;/*three last bytes can be different for such UDH*/ | ||
123 | if (tmp==0x0b) tmp=tmp-3;/*three last bytes can be different for such UDH*/ | ||
124 | if (tmp==0x06 && UDH->Text[1] == 0x08) tmp=tmp-4; | ||
125 | |||
126 | UDHOK=true; | ||
127 | for (w=0;w<tmp;w++) { | ||
128 | if (UDHHeaders[i].Text[w]!=UDH->Text[w+1]) { | ||
129 | UDHOK=false; | ||
130 | break; | ||
131 | } | ||
132 | } | ||
133 | if (UDHOK) { | ||
134 | UDH->Type=UDHHeaders[i].Type; | ||
135 | |||
136 | if (UDHHeaders[i].ID8bit !=-1) UDH->ID8bit = UDH->Text[UDHHeaders[i].ID8bit+1]; | ||
137 | if (UDHHeaders[i].ID16bit !=-1) UDH->ID16bit = UDH->Text[UDHHeaders[i].ID16bit+1]*256+UDH->Text[UDHHeaders[i].ID16bit+2]; | ||
138 | if (UDHHeaders[i].PartNumber !=-1) UDH->PartNumber = UDH->Text[UDHHeaders[i].PartNumber+1]; | ||
139 | if (UDHHeaders[i].AllParts !=-1) UDH->AllParts = UDH->Text[UDHHeaders[i].AllParts+1]; | ||
140 | break; | ||
141 | } | ||
142 | } | ||
143 | } | ||
144 | |||
145 | #ifdef DEBUG | ||
146 | dbgprintf("Type of UDH: "); | ||
147 | switch (UDH->Type) { | ||
148 | case UDH_ConcatenatedMessages : dbgprintf("Concatenated (linked) message"); break; | ||
149 | case UDH_ConcatenatedMessages16bit : dbgprintf("Concatenated (linked) message"); break; | ||
150 | case UDH_DisableVoice : dbgprintf("Disables voice indicator"); break; | ||
151 | case UDH_EnableVoice : dbgprintf("Enables voice indicator"); break; | ||
152 | case UDH_DisableFax : dbgprintf("Disables fax indicator"); break; | ||
153 | case UDH_EnableFax : dbgprintf("Enables fax indicator"); break; | ||
154 | case UDH_DisableEmail : dbgprintf("Disables email indicator"); break; | ||
155 | case UDH_EnableEmail : dbgprintf("Enables email indicator"); break; | ||
156 | case UDH_VoidSMS : dbgprintf("Void SMS"); break; | ||
157 | case UDH_NokiaWAP : dbgprintf("Nokia WAP Bookmark"); break; | ||
158 | case UDH_NokiaOperatorLogoLong : dbgprintf("Nokia operator logo"); break; | ||
159 | case UDH_NokiaWAPLong : dbgprintf("Nokia WAP Bookmark or WAP/MMS Settings");break; | ||
160 | case UDH_NokiaRingtone : dbgprintf("Nokia ringtone"); break; | ||
161 | case UDH_NokiaRingtoneLong : dbgprintf("Nokia ringtone"); break; | ||
162 | case UDH_NokiaOperatorLogo : dbgprintf("Nokia GSM operator logo"); break; | ||
163 | case UDH_NokiaCallerLogo : dbgprintf("Nokia caller logo"); break; | ||
164 | case UDH_NokiaProfileLong : dbgprintf("Nokia profile"); break; | ||
165 | case UDH_NokiaCalendarLong : dbgprintf("Nokia calendar note"); break; | ||
166 | case UDH_NokiaPhonebookLong : dbgprintf("Nokia phonebook entry"); break; | ||
167 | case UDH_UserUDH : dbgprintf("User UDH"); break; | ||
168 | case UDH_MMSIndicatorLong : dbgprintf("MMS indicator"); break; | ||
169 | case UDH_NoUDH: break; | ||
170 | } | ||
171 | if (UDH->ID8bit != -1) dbgprintf(", ID 8 bit %i",UDH->ID8bit); | ||
172 | if (UDH->ID16bit != -1) dbgprintf(", ID 16 bit %i",UDH->ID16bit); | ||
173 | if (UDH->PartNumber != -1 && UDH->AllParts != -1) { | ||
174 | dbgprintf(", part %i of %i",UDH->PartNumber,UDH->AllParts); | ||
175 | } | ||
176 | dbgprintf("\n"); | ||
177 | if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) DumpMessage(di.df, di.dl, UDH->Text, UDH->Length); | ||
178 | #endif | ||
179 | } | ||
180 | |||
181 | GSM_Error GSM_DecodeSMSFrameText(GSM_SMSMessage *SMS, unsigned char *buffer, GSM_SMSMessageLayout Layout) | ||
182 | { | ||
183 | int off=0; // length of the User Data Header | ||
184 | int w,i,tmp=0; | ||
185 | unsigned charoutput[161]; | ||
186 | |||
187 | SMS->UDH.Length = 0; | ||
188 | /* UDH header available */ | ||
189 | if (buffer[Layout.firstbyte] & 64) { | ||
190 | /* Length of UDH header */ | ||
191 | off = (buffer[Layout.Text] + 1); | ||
192 | SMS->UDH.Length = off; | ||
193 | dbgprintf("UDH header available (length %i)\n",off); | ||
194 | |||
195 | /* Copy UDH header into SMS->UDH */ | ||
196 | for (i = 0; i < off; i++) SMS->UDH.Text[i] = buffer[Layout.Text + i]; | ||
197 | |||
198 | GSM_DecodeUDHHeader(&SMS->UDH); | ||
199 | } | ||
200 | |||
201 | /* GSM 03.40 section 9.2.3.10 (TP-Data-Coding-Scheme) and GSM 03.38 section 4 */ | ||
202 | if ((buffer[Layout.TPDCS] & 0xf4) == 0xf4) SMS->Coding=SMS_Coding_8bit; | ||
203 | if ((buffer[Layout.TPDCS] & 0x08) == 0x08) SMS->Coding=SMS_Coding_Unicode; | ||
204 | |||
205 | switch (SMS->Coding) { | ||
206 | case SMS_Coding_Default: | ||
207 | i = 0; | ||
208 | do { | ||
209 | i+=7; | ||
210 | w=(i-off)%i; | ||
211 | } while (w<0); | ||
212 | SMS->Length=buffer[Layout.TPUDL] - (off*8 + w) / 7; | ||
213 | tmp=GSM_UnpackEightBitsToSeven(w, buffer[Layout.TPUDL]-off, SMS->Length, buffer+(Layout.Text+off), output); | ||
214 | dbgprintf("7 bit SMS, length %i\n",SMS->Length); | ||
215 | DecodeDefault (SMS->Text, output, SMS->Length, true, NULL); | ||
216 | dbgprintf("%s\n",DecodeUnicodeString(SMS->Text)); | ||
217 | break; | ||
218 | case SMS_Coding_8bit: | ||
219 | SMS->Length=buffer[Layout.TPUDL] - off; | ||
220 | memcpy(SMS->Text,buffer+(Layout.Text+off),SMS->Length); | ||
221 | #ifdef DEBUG | ||
222 | dbgprintf("8 bit SMS, length %i\n",SMS->Length); | ||
223 | if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) DumpMessage(di.df, di.dl, SMS->Text, SMS->Length); | ||
224 | #endif | ||
225 | break; | ||
226 | case SMS_Coding_Unicode: | ||
227 | SMS->Length=(buffer[Layout.TPUDL] - off) / 2; | ||
228 | DecodeUnicodeSpecialNOKIAChars(SMS->Text,buffer+(Layout.Text+off), SMS->Length); | ||
229 | #ifdef DEBUG | ||
230 | dbgprintf("Unicode SMS, length %i\n",SMS->Length); | ||
231 | if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) DumpMessage(di.df, di.dl, buffer+(Layout.Text+off), SMS->Length*2); | ||
232 | dbgprintf("%s\n",DecodeUnicodeString(SMS->Text)); | ||
233 | #endif | ||
234 | break; | ||
235 | } | ||
236 | |||
237 | return ERR_NONE; | ||
238 | } | ||
239 | |||
240 | GSM_Error GSM_DecodeSMSFrameStatusReportData(GSM_SMSMessage *SMS, unsigned char *buffer, GSM_SMSMessageLayout Layout) | ||
241 | { | ||
242 | SMS->DeliveryStatus = buffer[Layout.TPStatus]; | ||
243 | |||
244 | if (buffer[Layout.TPStatus] < 0x03) { | ||
245 | EncodeUnicode(SMS->Text,"Delivered",9); | ||
246 | SMS->Length = 9; | ||
247 | } else if (buffer[Layout.TPStatus] & 0x40) { | ||
248 | EncodeUnicode(SMS->Text,"Failed",6); | ||
249 | SMS->Length = 6; | ||
250 | } else if (buffer[Layout.TPStatus] & 0x20) { | ||
251 | EncodeUnicode(SMS->Text,"Pending",7); | ||
252 | SMS->Length = 7; | ||
253 | } else { | ||
254 | EncodeUnicode(SMS->Text,"Unknown",7); | ||
255 | SMS->Length = 7; | ||
256 | } | ||
257 | |||
258 | #ifdef DEBUG | ||
259 | /* See GSM 03.40 section 9.2.3.15 (TP-Status) */ | ||
260 | if (buffer[Layout.TPStatus] & 0x40) { | ||
261 | if (buffer[Layout.TPStatus] & 0x20) { | ||
262 | /* 0x60, 0x61, ... */ | ||
263 | dbgprintf("Temporary error, SC is not making any more transfer attempts\n"); | ||
264 | } else { | ||
265 | /* 0x40, 0x41, ... */ | ||
266 | dbgprintf("Permanent error, SC is not making any more transfer attempts\n"); | ||
267 | } | ||
268 | } else if (buffer[Layout.TPStatus] & 0x20) { | ||
269 | /* 0x20, 0x21, ... */ | ||
270 | dbgprintf("Temporary error, SC still trying to transfer SM\n"); | ||
271 | } | ||
272 | switch (buffer[Layout.TPStatus]) { | ||
273 | case 0x00: dbgprintf("SM received by the SME"); break; | ||
274 | case 0x01: dbgprintf("SM forwarded by the SC to the SME but the SC is unable to confirm delivery");break; | ||
275 | case 0x02: dbgprintf("SM replaced by the SC"); break; | ||
276 | case 0x20: dbgprintf("Congestion"); break; | ||
277 | case 0x21: dbgprintf("SME busy"); break; | ||
278 | case 0x22: dbgprintf("No response from SME"); break; | ||
279 | case 0x23: dbgprintf("Service rejected"); break; | ||
280 | case 0x24: dbgprintf("Quality of service not available"); break; | ||
281 | case 0x25: dbgprintf("Error in SME"); break; | ||
282 | case 0x40: dbgprintf("Remote procedure error"); break; | ||
283 | case 0x41: dbgprintf("Incompatibile destination"); break; | ||
284 | case 0x42: dbgprintf("Connection rejected by SME"); break; | ||
285 | case 0x43: dbgprintf("Not obtainable"); break; | ||
286 | case 0x44: dbgprintf("Quality of service not available"); break; | ||
287 | case 0x45: dbgprintf("No internetworking available"); break; | ||
288 | case 0x46: dbgprintf("SM Validity Period Expired"); break; | ||
289 | case 0x47: dbgprintf("SM deleted by originating SME"); break; | ||
290 | case 0x48: dbgprintf("SM Deleted by SC Administration"); break; | ||
291 | case 0x49: dbgprintf("SM does not exist"); break; | ||
292 | case 0x60: dbgprintf("Congestion"); break; | ||
293 | case 0x61: dbgprintf("SME busy"); break; | ||
294 | case 0x62: dbgprintf("No response from SME"); break; | ||
295 | case 0x63: dbgprintf("Service rejected"); break; | ||
296 | case 0x64: dbgprintf("Quality of service not available"); break; | ||
297 | case 0x65: dbgprintf("Error in SME"); break; | ||
298 | default : dbgprintf("Reserved/Specific to SC: %x",buffer[Layout.TPStatus]);break; | ||
299 | } | ||
300 | dbgprintf("\n"); | ||
301 | #endif | ||
302 | |||
303 | return ERR_NONE; | ||
304 | } | ||
305 | |||
306 | GSM_Error GSM_DecodeSMSFrame(GSM_SMSMessage *SMS, unsigned char *buffer, GSM_SMSMessageLayout Layout) | ||
307 | { | ||
308 | GSM_DateTimezerodt = {0,0,0,0,0,0,0}; | ||
309 | #ifdef DEBUG | ||
310 | if (Layout.firstbyte == 255) { | ||
311 | dbgprintf("ERROR: firstbyte in SMS layout not set\n"); | ||
312 | return ERR_UNKNOWN; | ||
313 | } | ||
314 | if (Layout.TPDCS != 255) dbgprintf("TPDCS : %02x %i\n",buffer[Layout.TPDCS] ,buffer[Layout.TPDCS]); | ||
315 | if (Layout.TPMR != 255) dbgprintf("TPMR : %02x %i\n",buffer[Layout.TPMR] ,buffer[Layout.TPMR]); | ||
316 | if (Layout.TPPID != 255) dbgprintf("TPPID : %02x %i\n",buffer[Layout.TPPID] ,buffer[Layout.TPPID]); | ||
317 | if (Layout.TPUDL != 255) dbgprintf("TPUDL : %02x %i\n",buffer[Layout.TPUDL] ,buffer[Layout.TPUDL]); | ||
318 | if (Layout.firstbyte != 255) dbgprintf("FirstByte : %02x %i\n",buffer[Layout.firstbyte],buffer[Layout.firstbyte]); | ||
319 | if (Layout.Text != 255) dbgprintf("Text : %02x %i\n",buffer[Layout.Text] ,buffer[Layout.Text]); | ||
320 | #endif | ||
321 | |||
322 | SMS->UDH.Type = UDH_NoUDH; | ||
323 | SMS->Coding = SMS_Coding_Default; | ||
324 | SMS->Length = 0; | ||
325 | SMS->SMSC.Location = 0; | ||
326 | SMS->SMSC.DefaultNumber[0]= 0; | ||
327 | SMS->SMSC.DefaultNumber[1]= 0; | ||
328 | SMS->SMSC.Number[0] = 0; | ||
329 | SMS->SMSC.Number[1] = 0; | ||
330 | SMS->SMSC.Name[0] = 0; | ||
331 | SMS->SMSC.Name[1] = 0; | ||
332 | SMS->SMSC.Validity.Format= SMS_Validity_NotAvailable; | ||
333 | SMS->SMSC.Format = SMS_FORMAT_Text; | ||
334 | SMS->Number[0] = 0; | ||
335 | SMS->Number[1] = 0; | ||
336 | SMS->Name[0] = 0; | ||
337 | SMS->Name[1] = 0; | ||
338 | SMS->ReplyViaSameSMSC = false; | ||
339 | if (Layout.SMSCNumber!=255) { | ||
340 | GSM_UnpackSemiOctetNumber(SMS->SMSC.Number,buffer+Layout.SMSCNumber,false); | ||
341 | dbgprintf("SMS center number : \"%s\"\n",DecodeUnicodeString(SMS->SMSC.Number)); | ||
342 | } | ||
343 | if ((buffer[Layout.firstbyte] & 0x80)!=0) SMS->ReplyViaSameSMSC=true; | ||
344 | #ifdef DEBUG | ||
345 | if (SMS->ReplyViaSameSMSC) dbgprintf("SMS centre set for reply\n"); | ||
346 | #endif | ||
347 | if (Layout.Number!=255) { | ||
348 | GSM_UnpackSemiOctetNumber(SMS->Number,buffer+Layout.Number,true); | ||
349 | dbgprintf("Remote number : \"%s\"\n",DecodeUnicodeString(SMS->Number)); | ||
350 | } | ||
351 | if (Layout.Text != 255 && Layout.TPDCS!=255 && Layout.TPUDL!=255) { | ||
352 | GSM_DecodeSMSFrameText(SMS, buffer, Layout); | ||
353 | } | ||
354 | if (Layout.DateTime != 255) { | ||
355 | GSM_DecodeSMSDateTime(&SMS->DateTime,buffer+(Layout.DateTime)); | ||
356 | } else { | ||
357 | SMS->DateTime = zerodt; | ||
358 | } | ||
359 | if (Layout.SMSCTime != 255 && Layout.TPStatus != 255) { | ||
360 | /* GSM 03.40 section 9.2.3.11 (TP-Service-Centre-Time-Stamp) */ | ||
361 | dbgprintf("SMSC response date: "); | ||
362 | GSM_DecodeSMSDateTime(&SMS->SMSCTime, buffer+(Layout.SMSCTime)); | ||
363 | GSM_DecodeSMSFrameStatusReportData(SMS,buffer,Layout); | ||
364 | } else { | ||
365 | SMS->SMSCTime = zerodt; | ||
366 | } | ||
367 | SMS->Class = -1; | ||
368 | if (Layout.TPDCS != 255) { | ||
369 | if ((buffer[Layout.TPDCS] & 0xF3)==0xF0) SMS->Class = 0; | ||
370 | if ((buffer[Layout.TPDCS] & 0xF3)==0xF1) SMS->Class = 1; | ||
371 | if ((buffer[Layout.TPDCS] & 0xF3)==0xF2) SMS->Class = 2; | ||
372 | if ((buffer[Layout.TPDCS] & 0xF3)==0xF3) SMS->Class = 3; | ||
373 | } | ||
374 | dbgprintf("SMS class: %i\n",SMS->Class); | ||
375 | |||
376 | SMS->MessageReference = 0; | ||
377 | if (Layout.TPMR != 255) SMS->MessageReference = buffer[Layout.TPMR]; | ||
378 | |||
379 | SMS->ReplaceMessage = 0; | ||
380 | if (Layout.TPPID != 255) { | ||
381 | if (buffer[Layout.TPPID] > 0x40 && buffer[Layout.TPPID] < 0x48) { | ||
382 | SMS->ReplaceMessage = buffer[Layout.TPPID] - 0x40; | ||
383 | } | ||
384 | } | ||
385 | SMS->RejectDuplicates = false; | ||
386 | if ((buffer[Layout.firstbyte] & 0x04)==0x04) SMS->RejectDuplicates = true; | ||
387 | |||
388 | return ERR_NONE; | ||
389 | } | ||
390 | |||
391 | /* ----------------------------- Packing SMS ------------------------------- */ | ||
392 | |||
393 | /* See GSM 03.40 section 9.2.3.11 */ | ||
394 | static GSM_Error GSM_EncodeSMSDateTime(GSM_DateTime *DT, unsigned char *req) | ||
395 | { | ||
396 | int Year; | ||
397 | |||
398 | dbgprintf("Encoding SMS datetime: %02i/%02i/%04i %02i:%02i:%02i\n", | ||
399 | DT->Day,DT->Month,DT->Year,DT->Hour,DT->Minute,DT->Second); | ||
400 | |||
401 | /* We need to have only two last digits of year */ | ||
402 | if (DT->Year>1900) { | ||
403 | if (DT->Year<2000) Year = DT->Year-1900; | ||
404 | else Year = DT->Year-2000; | ||
405 | } else Year = DT->Year; | ||
406 | |||
407 | req[0]=EncodeWithBCDAlphabet(Year); | ||
408 | req[1]=EncodeWithBCDAlphabet(DT->Month); | ||
409 | req[2]=EncodeWithBCDAlphabet(DT->Day); | ||
410 | req[3]=EncodeWithBCDAlphabet(DT->Hour); | ||
411 | req[4]=EncodeWithBCDAlphabet(DT->Minute); | ||
412 | req[5]=EncodeWithBCDAlphabet(DT->Second); | ||
413 | |||
414 | /* FIXME: do it */ | ||
415 | req[6]=0; /* TimeZone = +-0 */ | ||
416 | |||
417 | return ERR_NONE; | ||
418 | } | ||
419 | |||
420 | static int GSM_EncodeSMSFrameText(GSM_SMSMessage *SMS, unsigned char *buffer, GSM_SMSMessageLayout Layout) | ||
421 | { | ||
422 | int off = 0;// length of the User Data Header | ||
423 | intsize = 0, size2 = 0, w,p; | ||
424 | charbuff[200]; | ||
425 | |||
426 | if (SMS->UDH.Type!=UDH_NoUDH) { | ||
427 | buffer[Layout.firstbyte] |= 0x40; /* GSM 03.40 section 9.2.3.23 (TP-User-Data-Header-Indicator) */ | ||
428 | off = 1 + SMS->UDH.Text[0]; /* off - length of the User Data Header */ | ||
429 | memcpy(buffer+Layout.Text, SMS->UDH.Text, off); /* we copy the udh */ | ||
430 | #ifdef DEBUG | ||
431 | dbgprintf("UDH, length %i\n",off); | ||
432 | if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) DumpMessage(di.df, di.dl, SMS->UDH.Text, off); | ||
433 | #endif | ||
434 | } | ||
435 | switch (SMS->Coding) { | ||
436 | case SMS_Coding_8bit: | ||
437 | /* the mask for the 8-bit data */ | ||
438 | /* GSM 03.40 section 9.2.3.10 (TP-Data-Coding-Scheme) | ||
439 | * and GSM 03.38 section 4 */ | ||
440 | buffer[Layout.TPDCS] |= 0xf4; | ||
441 | memcpy(buffer+(Layout.Text+off), SMS->Text, SMS->Length); | ||
442 | size2 = size = SMS->Length+off; | ||
443 | #ifdef DEBUG | ||
444 | dbgprintf("8 bit SMS, length %i\n",SMS->Length); | ||
445 | if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) DumpMessage(di.df, di.dl, SMS->Text, SMS->Length); | ||
446 | #endif | ||
447 | break; | ||
448 | case SMS_Coding_Default: | ||
449 | p = 0; | ||
450 | do { | ||
451 | p+=7; | ||
452 | w=(p-off)%p; | ||
453 | } while (w<0); | ||
454 | p = UnicodeLength(SMS->Text); | ||
455 | EncodeDefault(buff, SMS->Text, &p, true, NULL); | ||
456 | size = GSM_PackSevenBitsToEight(w, buff, buffer+(Layout.Text+off), p); | ||
457 | size += off; | ||
458 | size2 = (off*8 + w) / 7 + p; | ||
459 | dbgprintf("7 bit SMS, length %i, %i\n",size,size2); | ||
460 | dbgprintf("%s\n",DecodeUnicodeString(SMS->Text)); | ||
461 | if (size > GSM_MAX_8BIT_SMS_LENGTH) { | ||
462 | size = 0; size2 = 0; | ||
463 | } | ||
464 | break; | ||
465 | case SMS_Coding_Unicode: | ||
466 | /* GSM 03.40 section 9.2.3.10 (TP-Data-Coding-Scheme) | ||
467 | * and GSM 03.38 section 4 */ | ||
468 | buffer[Layout.TPDCS] |= 0x08; | ||
469 | EncodeUnicodeSpecialNOKIAChars(buffer+(Layout.Text+off), SMS->Text, UnicodeLength(SMS->Text)); | ||
470 | size=size2=UnicodeLength(buffer+(Layout.Text+off))*2+off; | ||
471 | #ifdef DEBUG | ||
472 | dbgprintf("Unicode SMS, length %i\n",(size2-off)/2); | ||
473 | if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) DumpMessage(di.df, di.dl, buffer+(Layout.Text+off), size2-off); | ||
474 | dbgprintf("%s\n",DecodeUnicodeString(buffer+(Layout.Text+off))); | ||
475 | #endif | ||
476 | break; | ||
477 | } | ||
478 | |||
479 | /* GSM 03.40 section 9.2.3.16 (TP-User-Data-Length) | ||
480 | * SMS->Length is: | ||
481 | - integer representation of the number od octets within the | ||
482 | user data when TP-User-Data is coded using 8 bit data | ||
483 | - the sum of the number of septets in UDH including any padding | ||
484 | and the number of septets in TP-User-Data in other case | ||
485 | */ | ||
486 | buffer[Layout.TPUDL] = size2; | ||
487 | return size; | ||
488 | } | ||
489 | |||
490 | GSM_Error GSM_EncodeSMSFrame(GSM_SMSMessage *SMS, unsigned char *buffer, GSM_SMSMessageLayout Layout, int *length, bool clear) | ||
491 | { | ||
492 | int i; | ||
493 | |||
494 | if (clear) { | ||
495 | /* Cleaning up to the SMS text */ | ||
496 | for (i=0;i<Layout.Text;i++) buffer[i] = 0; | ||
497 | } | ||
498 | |||
499 | /* GSM 03.40 section 9.2.3.1 (TP-Message-Type-Indicator) */ | ||
500 | switch (SMS->PDU) { | ||
501 | case SMS_Submit: | ||
502 | buffer[Layout.firstbyte] |= 0x01; | ||
503 | break; | ||
504 | /* SMS_Status_Report when Submit sms should have delivery report */ | ||
505 | /* We DON'T CREATE FRAME FOR REAL SMS_STATUS_REPORT */ | ||
506 | case SMS_Status_Report: | ||
507 | buffer[Layout.firstbyte] |= 0x01; | ||
508 | /* GSM 03.40 section 9.2.3.5 (TP-Status-Raport-Request) */ | ||
509 | /* Set when want delivery report from SMSC */ | ||
510 | buffer[Layout.firstbyte] |= 0x20; | ||
511 | break; | ||
512 | case SMS_Deliver: | ||
513 | buffer[Layout.firstbyte] |= 0x00; | ||
514 | } | ||
515 | |||
516 | /* GSM 03.40 section 9.2.3.17 (TP-Reply-Path) */ | ||
517 | if (SMS->ReplyViaSameSMSC) buffer[Layout.firstbyte] |= 0x80; | ||
518 | |||
519 | if (Layout.Number!=255) { | ||
520 | buffer[Layout.Number] = GSM_PackSemiOctetNumber(SMS->Number,buffer+(Layout.Number+1),true); | ||
521 | dbgprintf("Recipient number \"%s\"\n",DecodeUnicodeString(SMS->Number)); | ||
522 | } | ||
523 | if (Layout.SMSCNumber!=255) { | ||
524 | buffer[Layout.SMSCNumber]=GSM_PackSemiOctetNumber(SMS->SMSC.Number,buffer+(Layout.SMSCNumber+1), false); | ||
525 | dbgprintf("SMSC number \"%s\"\n",DecodeUnicodeString(SMS->SMSC.Number)); | ||
526 | } | ||
527 | |||
528 | /* Message Class*/ | ||
529 | /* GSM 03.40 section 9.2.3.10 (TP-Data-Coding-Scheme) and GSM 03.38 section 4 */ | ||
530 | if (Layout.TPDCS != 255) { | ||
531 | if (SMS->Class>=0 && SMS->Class<5) buffer[Layout.TPDCS] |= (240+SMS->Class); | ||
532 | dbgprintf("SMS class %i\n",SMS->Class); | ||
533 | } | ||
534 | |||
535 | if (Layout.TPVP != 255) { | ||
536 | /* GSM 03.40 section 9.2.3.3 (TP-Validity-Period-Format) */ | ||
537 | /* Bits 4 and 3: 10. TP-VP field present and integer represent (relative) */ | ||
538 | buffer[Layout.firstbyte] |= 0x10; | ||
539 | buffer[Layout.TPVP]=((unsigned char)SMS->SMSC.Validity.Relative); | ||
540 | dbgprintf("SMS validity %02x\n",SMS->SMSC.Validity.Relative); | ||
541 | } | ||
542 | |||
543 | if (Layout.DateTime != 255) { | ||
544 | GSM_EncodeSMSDateTime(&SMS->DateTime, buffer+Layout.DateTime); | ||
545 | } | ||
546 | |||
547 | if (Layout.TPMR != 255) { | ||
548 | dbgprintf("TPMR: %02x %i\n",SMS->MessageReference,SMS->MessageReference); | ||
549 | buffer[Layout.TPMR] = SMS->MessageReference; | ||
550 | } | ||
551 | |||
552 | if (SMS->RejectDuplicates) { | ||
553 | /* GSM 03.40 section 9.2.3.25 (TP Reject Duplicates) */ | ||
554 | buffer[Layout.firstbyte] |= 0x04; | ||
555 | } | ||
556 | |||
557 | if (Layout.TPPID != 255) { | ||
558 | buffer[Layout.TPPID] = 0; | ||
559 | if (SMS->ReplaceMessage > 0 && SMS->ReplaceMessage < 8) { | ||
560 | buffer[Layout.TPPID] = 0x40 + SMS->ReplaceMessage; | ||
561 | } | ||
562 | } | ||
563 | |||
564 | /* size is the length of the data in octets including UDH */ | ||
565 | *length=GSM_EncodeSMSFrameText(SMS,buffer,Layout); | ||
566 | //if (*length == 0) return GE_UNKNOWN; | ||
567 | *length += Layout.Text; | ||
568 | |||
569 | return ERR_NONE; | ||
570 | } | ||
571 | |||
572 | /* ----------------- Some help functions ----------------------------------- */ | ||
573 | |||
574 | void GSM_SetDefaultSMSData(GSM_SMSMessage *SMS) | ||
575 | { | ||
576 | SMS->Class = -1; | ||
577 | SMS->SMSC.Location = 1; | ||
578 | SMS->SMSC.Format = SMS_FORMAT_Text; | ||
579 | SMS->SMSC.Validity.Format= SMS_Validity_RelativeFormat; | ||
580 | SMS->SMSC.Validity.Relative= SMS_VALID_Max_Time; | ||
581 | SMS->ReplyViaSameSMSC = false; | ||
582 | SMS->UDH.Type = UDH_NoUDH; | ||
583 | SMS->UDH.Length = 0; | ||
584 | SMS->UDH.Text[0] = 0; | ||
585 | SMS->UDH.ID8bit = 0; | ||
586 | SMS->UDH.ID16bit = 0; | ||
587 | SMS->UDH.PartNumber = 0; | ||
588 | SMS->UDH.AllParts = 0; | ||
589 | SMS->Coding = SMS_Coding_Default; | ||
590 | SMS->Text[0] = 0; | ||
591 | SMS->Text[1] = 0; | ||
592 | SMS->PDU = SMS_Submit; | ||
593 | SMS->RejectDuplicates = false; | ||
594 | SMS->MessageReference = 0; | ||
595 | SMS->ReplaceMessage = 0; | ||
596 | SMS->Length = 0; | ||
597 | |||
598 | /* This part is required to save SMS */ | ||
599 | SMS->State = SMS_UnSent; | ||
600 | SMS->Location = 0; | ||
601 | SMS->Folder = 0x02;/*Outbox*/ | ||
602 | GSM_GetCurrentDateTime (&SMS->DateTime); | ||
603 | SMS->Name[0] = 0; | ||
604 | SMS->Name[1] = 0; | ||
605 | } | ||
606 | |||
607 | /** | ||
608 | * GSM 03.40 section 9.2.3.24 | ||
609 | */ | ||
610 | void GSM_EncodeUDHHeader(GSM_UDHHeader *UDH) | ||
611 | { | ||
612 | int i=0; | ||
613 | |||
614 | if (UDH->Type == UDH_NoUDH) { | ||
615 | UDH->Length = 0; | ||
616 | return; | ||
617 | } | ||
618 | if (UDH->Type == UDH_UserUDH) { | ||
619 | UDH->Length = UDH->Text[0] + 1; | ||
620 | return; | ||
621 | } | ||
622 | while (true) { | ||
623 | if (UDHHeaders[i].Type==UDH_NoUDH) { | ||
624 | dbgprintf("Not supported UDH type\n"); | ||
625 | break; | ||
626 | } | ||
627 | if (UDHHeaders[i].Type!=UDH->Type) { | ||
628 | i++; | ||
629 | continue; | ||
630 | } | ||
631 | /* UDH Length */ | ||
632 | UDH->Text[0] = UDHHeaders[i].Length; | ||
633 | memcpy(UDH->Text+1, UDHHeaders[i].Text, UDHHeaders[i].Length); | ||
634 | UDH->Length = UDH->Text[0] + 1; | ||
635 | |||
636 | if (UDHHeaders[i].ID8bit != -1) { | ||
637 | UDH->Text[UDHHeaders[i].ID8bit+1] = UDH->ID8bit % 256; | ||
638 | } else { | ||
639 | UDH->ID8bit = -1; | ||
640 | } | ||
641 | if (UDHHeaders[i].ID16bit != -1) { | ||
642 | UDH->Text[UDHHeaders[i].ID16bit+1] = UDH->ID16bit / 256; | ||
643 | UDH->Text[UDHHeaders[i].ID16bit+2] = UDH->ID16bit % 256; | ||
644 | } else { | ||
645 | UDH->ID16bit = -1; | ||
646 | } | ||
647 | if (UDHHeaders[i].PartNumber != -1) { | ||
648 | UDH->Text[UDHHeaders[i].PartNumber+1] = UDH->PartNumber; | ||
649 | } else { | ||
650 | UDH->PartNumber = -1; | ||
651 | } | ||
652 | if (UDHHeaders[i].AllParts != -1) { | ||
653 | UDH->Text[UDHHeaders[i].AllParts+1] = UDH->AllParts; | ||
654 | } else { | ||
655 | UDH->AllParts = -1; | ||
656 | } | ||
657 | break; | ||
658 | } | ||
659 | } | ||
660 | |||
661 | /* How should editor hadle tabs in this file? Add editor commands here. | ||
662 | * vim: noexpandtab sw=8 ts=8 sts=8: | ||
663 | */ | ||
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 @@ | |||
1 | /* (c) 2001-2004 by Marcin Wiacek */ | ||
2 | /* based on some work from Pawel Kot, others and Gnokii */ | ||
3 | |||
4 | #ifndef __gsm_sms_h | ||
5 | #define __gsm_sms_h | ||
6 | |||
7 | #include "../../gsmcomon.h" | ||
8 | #include "../gsmlogo.h" | ||
9 | #include "../gsmcal.h" | ||
10 | #include "../gsmpbk.h" | ||
11 | #include "../gsmdata.h" | ||
12 | #include "../gsmring.h" | ||
13 | |||
14 | /* --------------------- Some general definitions ------------------------- */ | ||
15 | |||
16 | #define GSM_MAX_UDH_LENGTH 140 | ||
17 | #define GSM_MAX_SMS_LENGTH 160 | ||
18 | #define GSM_MAX_8BIT_SMS_LENGTH 140 | ||
19 | |||
20 | /* -------------------- Cell Broadcast ------------------------------------ */ | ||
21 | |||
22 | /** | ||
23 | * Structure for Cell Broadcast messages. | ||
24 | */ | ||
25 | typedef struct { | ||
26 | /** | ||
27 | * Message text. | ||
28 | */ | ||
29 | char Text[300]; | ||
30 | /** | ||
31 | * Channel number. | ||
32 | */ | ||
33 | int Channel; | ||
34 | } GSM_CBMessage; | ||
35 | |||
36 | /* ------------------------ SMS status ------------------------------------ */ | ||
37 | |||
38 | /** | ||
39 | * Status of SMS memory. | ||
40 | */ | ||
41 | typedef struct { | ||
42 | /** | ||
43 | * Number of unread messages on SIM. | ||
44 | */ | ||
45 | int SIMUnRead; | ||
46 | /** | ||
47 | * Number of all saved messages (including unread) on SIM. | ||
48 | */ | ||
49 | int SIMUsed; | ||
50 | /** | ||
51 | * Number of all possible messages on SIM. | ||
52 | */ | ||
53 | int SIMSize; | ||
54 | /** | ||
55 | * Number of used templates (62xx/63xx/7110/etc.). | ||
56 | */ | ||
57 | int TemplatesUsed; | ||
58 | /** | ||
59 | * Number of unread messages in phone. | ||
60 | */ | ||
61 | int PhoneUnRead; | ||
62 | /** | ||
63 | * Number of all saved messages in phone. | ||
64 | */ | ||
65 | int PhoneUsed; | ||
66 | /** | ||
67 | * Number of all possible messages on phone. | ||
68 | */ | ||
69 | int PhoneSize; | ||
70 | } GSM_SMSMemoryStatus; | ||
71 | |||
72 | /* --------------------- SMS Center --------------------------------------- */ | ||
73 | |||
74 | /** | ||
75 | * Enum defines format of SMS messages. See GSM 03.40 section 9.2.3.9 | ||
76 | */ | ||
77 | typedef enum { | ||
78 | SMS_FORMAT_Pager = 1, | ||
79 | SMS_FORMAT_Fax, | ||
80 | SMS_FORMAT_Email, | ||
81 | SMS_FORMAT_Text | ||
82 | /* Some values not handled here */ | ||
83 | } GSM_SMSFormat; | ||
84 | |||
85 | /** | ||
86 | * Enum defines some the most often used validity lengths for SMS messages | ||
87 | * for relative validity format. See GSM 03.40 section 9.2.3.12.1 - it gives | ||
88 | * more values | ||
89 | */ | ||
90 | typedef enum { | ||
91 | SMS_VALID_1_Hour = 0x0b, | ||
92 | SMS_VALID_6_Hours = 0x47, | ||
93 | SMS_VALID_1_Day = 0xa7, | ||
94 | SMS_VALID_3_Days = 0xa9, | ||
95 | SMS_VALID_1_Week = 0xad, | ||
96 | SMS_VALID_Max_Time = 0xff | ||
97 | } GSM_ValidityPeriod; | ||
98 | |||
99 | /** | ||
100 | * Enum defines format of validity period for SMS messages. | ||
101 | * See GSM 03.40 section 9.2.3.12 | ||
102 | */ | ||
103 | typedef enum { | ||
104 | SMS_Validity_NotAvailable = 1, | ||
105 | SMS_Validity_RelativeFormat | ||
106 | /* Specification gives also other possibilities */ | ||
107 | } GSM_ValidityPeriodFormat; | ||
108 | |||
109 | /** | ||
110 | * Structure for validity of SMS messages | ||
111 | */ | ||
112 | typedef struct { | ||
113 | GSM_ValidityPeriodFormatFormat; | ||
114 | /** | ||
115 | * Value defines period for relative format | ||
116 | */ | ||
117 | GSM_ValidityPeriod Relative; | ||
118 | } GSM_SMSValidity; | ||
119 | |||
120 | #define GSM_MAX_SMSC_NAME_LENGTH30 | ||
121 | |||
122 | /** | ||
123 | * Structure for SMSC (SMS Center) information. | ||
124 | */ | ||
125 | typedef struct { | ||
126 | /** | ||
127 | * Number of the SMSC on SIM | ||
128 | */ | ||
129 | int Location; | ||
130 | /** | ||
131 | * Name of the SMSC | ||
132 | */ | ||
133 | unsigned char Name[(GSM_MAX_SMSC_NAME_LENGTH+1)*2]; | ||
134 | /** | ||
135 | * SMSC phone number. | ||
136 | */ | ||
137 | unsigned char Number[(GSM_MAX_NUMBER_LENGTH+1)*2]; | ||
138 | /** | ||
139 | * Validity of SMS messages. | ||
140 | */ | ||
141 | GSM_SMSValidity Validity; | ||
142 | /** | ||
143 | * Format of sent SMS messages. | ||
144 | */ | ||
145 | GSM_SMSFormat Format; | ||
146 | /** | ||
147 | * Default recipient number. In old DCT3 ignored | ||
148 | */ | ||
149 | unsigned char DefaultNumber[(GSM_MAX_NUMBER_LENGTH+1)*2]; | ||
150 | } GSM_SMSC; | ||
151 | |||
152 | /* --------------------- single SMS --------------------------------------- */ | ||
153 | |||
154 | /** | ||
155 | * Status of SMS message. | ||
156 | */ | ||
157 | typedef enum { | ||
158 | SMS_Sent = 1, | ||
159 | SMS_UnSent, | ||
160 | SMS_Read, | ||
161 | SMS_UnRead | ||
162 | } GSM_SMS_State; | ||
163 | |||
164 | /** | ||
165 | * Coding type of SMS. | ||
166 | */ | ||
167 | typedef enum { | ||
168 | /** | ||
169 | * Unicode | ||
170 | */ | ||
171 | SMS_Coding_Unicode = 1, | ||
172 | /** | ||
173 | * Default GSM aplhabet. | ||
174 | */ | ||
175 | SMS_Coding_Default, | ||
176 | /** | ||
177 | * 8-bit. | ||
178 | */ | ||
179 | SMS_Coding_8bit | ||
180 | } GSM_Coding_Type; | ||
181 | |||
182 | /** | ||
183 | * Types of UDH (User Data Header). | ||
184 | */ | ||
185 | typedef enum { | ||
186 | UDH_NoUDH = 1, | ||
187 | /** | ||
188 | * Linked SMS. | ||
189 | */ | ||
190 | UDH_ConcatenatedMessages, | ||
191 | /** | ||
192 | * Linked SMS with 16 bit reference. | ||
193 | */ | ||
194 | UDH_ConcatenatedMessages16bit, | ||
195 | UDH_DisableVoice, | ||
196 | UDH_DisableFax, | ||
197 | UDH_DisableEmail, | ||
198 | UDH_EnableVoice, | ||
199 | UDH_EnableFax, | ||
200 | UDH_EnableEmail, | ||
201 | UDH_VoidSMS, | ||
202 | UDH_NokiaRingtone, | ||
203 | UDH_NokiaRingtoneLong, | ||
204 | UDH_NokiaOperatorLogo, | ||
205 | UDH_NokiaOperatorLogoLong, | ||
206 | UDH_NokiaCallerLogo, | ||
207 | UDH_NokiaWAP, | ||
208 | UDH_NokiaWAPLong, | ||
209 | UDH_NokiaCalendarLong, | ||
210 | UDH_NokiaProfileLong, | ||
211 | UDH_NokiaPhonebookLong, | ||
212 | UDH_UserUDH, | ||
213 | UDH_MMSIndicatorLong | ||
214 | } GSM_UDH; | ||
215 | |||
216 | /** | ||
217 | * Structure for User Data Header. | ||
218 | */ | ||
219 | typedef struct { | ||
220 | /** | ||
221 | * UDH type. | ||
222 | */ | ||
223 | GSM_UDH Type; | ||
224 | /** | ||
225 | * UDH length. | ||
226 | */ | ||
227 | int Length; | ||
228 | /** | ||
229 | * UDH text. | ||
230 | */ | ||
231 | unsigned char Text[GSM_MAX_UDH_LENGTH]; | ||
232 | /** | ||
233 | * 8-bit ID, when required (-1 otherwise). | ||
234 | */ | ||
235 | int ID8bit; | ||
236 | /** | ||
237 | * 16-bit ID, when required (-1 otherwise). | ||
238 | */ | ||
239 | int ID16bit; | ||
240 | /** | ||
241 | * Number of current part. | ||
242 | */ | ||
243 | int PartNumber; | ||
244 | /** | ||
245 | * Total number of parts. | ||
246 | */ | ||
247 | int AllParts; | ||
248 | } GSM_UDHHeader; | ||
249 | |||
250 | /** | ||
251 | * TP-Message-Type-Indicator. See GSM 03.40 section 9.2.3.1. | ||
252 | */ | ||
253 | typedef enum { | ||
254 | /** | ||
255 | * SMS in Inbox. | ||
256 | */ | ||
257 | SMS_Deliver = 1, | ||
258 | /** | ||
259 | * Delivery Report | ||
260 | */ | ||
261 | SMS_Status_Report, | ||
262 | /** | ||
263 | * SMS for sending or in Outbox | ||
264 | */ | ||
265 | SMS_Submit | ||
266 | /* specification gives more */ | ||
267 | } GSM_SMSMessageType; | ||
268 | |||
269 | /** | ||
270 | * Maximal length of SMS name. | ||
271 | */ | ||
272 | #define GSM_MAX_SMS_NAME_LENGTH 40 | ||
273 | |||
274 | /** | ||
275 | * SMS message data. | ||
276 | */ | ||
277 | typedef struct { | ||
278 | /** | ||
279 | * Message to be replaced. | ||
280 | */ | ||
281 | unsigned char ReplaceMessage; | ||
282 | /** | ||
283 | * Whether to reject duplicates. | ||
284 | */ | ||
285 | bool RejectDuplicates; | ||
286 | /** | ||
287 | * UDH (User Data Header) | ||
288 | */ | ||
289 | GSM_UDHHeader UDH; | ||
290 | /** | ||
291 | * Sender or recipient number. | ||
292 | */ | ||
293 | unsigned char Number[(GSM_MAX_NUMBER_LENGTH+1)*2]; | ||
294 | /** | ||
295 | * SMSC (SMS Center) | ||
296 | */ | ||
297 | GSM_SMSC SMSC; | ||
298 | /** | ||
299 | * For saved SMS: where exactly it's saved (SIM/phone) | ||
300 | */ | ||
301 | GSM_MemoryType Memory; | ||
302 | /** | ||
303 | * For saved SMS: location of SMS in memory. | ||
304 | */ | ||
305 | int Location; | ||
306 | /** | ||
307 | * For saved SMS: number of folder, where SMS is saved | ||
308 | */ | ||
309 | int Folder; | ||
310 | /** | ||
311 | * For saved SMS: whether SMS is really in Inbox. | ||
312 | */ | ||
313 | bool InboxFolder; | ||
314 | /** | ||
315 | * Length of the SMS message. | ||
316 | */ | ||
317 | int Length; | ||
318 | /** | ||
319 | * Status (read/unread/...) of SMS message. | ||
320 | */ | ||
321 | GSM_SMS_State State; | ||
322 | /** | ||
323 | * Name in Nokia with SMS memory (6210/7110, etc.) Ignored in other. | ||
324 | */ | ||
325 | unsigned char Name[(GSM_MAX_SMS_NAME_LENGTH+1)*2]; | ||
326 | /** | ||
327 | * Text for SMS. | ||
328 | */ | ||
329 | unsigned char Text[(GSM_MAX_SMS_LENGTH+1)*2]; | ||
330 | /** | ||
331 | * Type of message. | ||
332 | */ | ||
333 | GSM_SMSMessageType PDU; | ||
334 | /** | ||
335 | * Type of coding. | ||
336 | */ | ||
337 | GSM_Coding_Type Coding; | ||
338 | /** | ||
339 | * Date and time, when SMS was saved or sent | ||
340 | */ | ||
341 | GSM_DateTime DateTime; | ||
342 | /** | ||
343 | * Date of SMSC response in DeliveryReport messages. | ||
344 | */ | ||
345 | GSM_DateTime SMSCTime; | ||
346 | /** | ||
347 | * In delivery reports: status. | ||
348 | */ | ||
349 | unsigned char DeliveryStatus; | ||
350 | /** | ||
351 | * Indicates whether "Reply via same center" is set. | ||
352 | */ | ||
353 | bool ReplyViaSameSMSC; | ||
354 | /** | ||
355 | * SMS class. | ||
356 | */ | ||
357 | char Class; | ||
358 | /** | ||
359 | * Message reference. | ||
360 | */ | ||
361 | unsigned char MessageReference; | ||
362 | } GSM_SMSMessage; | ||
363 | |||
364 | /* In layouts are saved locations for some SMS part. Below are listed | ||
365 | * specs, which describe them | ||
366 | */ | ||
367 | typedef struct { | ||
368 | /** | ||
369 | * TP-User-Data. GSM 03.40 section 9.2.3.24. | ||
370 | */ | ||
371 | unsigned char Text; | ||
372 | /** | ||
373 | * - In SMS-Deliver: TP-Originating-Address. GSM 03.40 section 9.2.3.7. | ||
374 | * - In SMS-Submit: TP-Destination-Address. GSM 03.40 section 9.2.3.8. | ||
375 | * - In SMS-Status-Report: TP-Recipient-Address. GSM 03.40 section 9.2.3.14. | ||
376 | */ | ||
377 | unsigned char Number; | ||
378 | /** | ||
379 | * SMSC number | ||
380 | */ | ||
381 | unsigned char SMSCNumber; | ||
382 | /** | ||
383 | * TP-Data-Coding-Scheme. GSM 03.40 section 9.2.3.10 | ||
384 | */ | ||
385 | unsigned char TPDCS; | ||
386 | /** | ||
387 | * - For SMS-Submit: TP-Validity-Period. GSM 03.40 section 9.2.3.12. | ||
388 | * - For SMS-Status-Report: TP-Discharge Time. GSM 03.40 section 9.2.3.13. | ||
389 | */ | ||
390 | unsigned char DateTime; | ||
391 | /** | ||
392 | * TP-Service-Centre-Time-Stamp in SMS-Status-Report. GSM 03.40 section 9.2.3.11. | ||
393 | */ | ||
394 | unsigned char SMSCTime; | ||
395 | /** | ||
396 | * TP-Status in SMS-Status-Report. GSM 03.40 section 9.2.3.15. | ||
397 | */ | ||
398 | unsigned char TPStatus; | ||
399 | /** | ||
400 | * TP-User-Data-Length. GSM 03.40 section 9.2.3.16. | ||
401 | */ | ||
402 | unsigned char TPUDL; | ||
403 | /** | ||
404 | * TP-Validity Period in SMS-Submit. GSM 03.40 section 9.2.3.12. | ||
405 | */ | ||
406 | unsigned char TPVP; | ||
407 | /** | ||
408 | * Byte contains in SMS-Deliver: | ||
409 | * - TP-Message-Type-Indicator (2 bits) GSM 03.40 section 9.2.3.1 | ||
410 | * - TP-More-Messages-To-Send (1 bit). GSM 03.40 section 9.2.3.2 | ||
411 | * - TP-Reply-Path (1 bit). GSM 03.40 section 9.2.3.17 | ||
412 | * - TP-User-Data-Header-Indicator (1 bit). GSM 03.40 section 9.2.3.23 | ||
413 | * - TP-Status-Report-Indicator (1 bit). GSM 03.40 section 9.2.3.4 | ||
414 | * | ||
415 | * Byte contains in SMS-Submit: | ||
416 | * - TP-Message-Type-Indicator (2 bits) GSM 03.40 section 9.2.3.1 | ||
417 | * - TP-Reject-Duplicates (1 bit). GSM 03.40 section | ||
418 | * - TP-Validity-Period-Format (2 bits).GSM 03.40 section 9.2.3.3 | ||
419 | * - TP-Reply-Path (1 bit). GSM 03.40 section 9.2.3.17 | ||
420 | * - TP-User-Data-Header-Indicator (1 bit). GSM 03.40 section 9.2.3.23 | ||
421 | * - TP-Status-Report-Request (1 bit). GSM 03.40 section 9.2.3.5 | ||
422 | */ | ||
423 | unsigned char firstbyte; | ||
424 | /** | ||
425 | * TP-Message Reference in SMS-Submit. GSM 03.40 section 9.2.3.6 | ||
426 | */ | ||
427 | unsigned char TPMR; | ||
428 | /** | ||
429 | * TP-Protocol-Identifier. GSM 03.40 section 9.2.3.9 | ||
430 | */ | ||
431 | unsigned char TPPID; | ||
432 | } GSM_SMSMessageLayout; | ||
433 | |||
434 | GSM_Error GSM_DecodeSMSFrame(GSM_SMSMessage *SMS, unsigned char *buffer, GSM_SMSMessageLayout Layout); | ||
435 | GSM_Error GSM_EncodeSMSFrame(GSM_SMSMessage *SMS, unsigned char *buffer, GSM_SMSMessageLayout Layout, int *length, bool clear); | ||
436 | |||
437 | GSM_Error GSM_DecodeSMSFrameStatusReportData (GSM_SMSMessage *SMS, unsigned char *buffer, GSM_SMSMessageLayout Layout); | ||
438 | GSM_Error GSM_DecodeSMSFrameText (GSM_SMSMessage *SMS, unsigned char *buffer, GSM_SMSMessageLayout Layout); | ||
439 | |||
440 | void GSM_DecodeUDHHeader(GSM_UDHHeader *UDH); | ||
441 | void GSM_EncodeUDHHeader(GSM_UDHHeader *UDH); | ||
442 | |||
443 | void GSM_SetDefaultSMSData(GSM_SMSMessage *SMS); | ||
444 | |||
445 | /* ---------------------- SMS folders ------------------------------------- */ | ||
446 | |||
447 | /** | ||
448 | * Number of possible SMS folders. | ||
449 | */ | ||
450 | #define GSM_MAX_SMS_FOLDERS 24 | ||
451 | /** | ||
452 | * Maximal length of SMS folder name. | ||
453 | */ | ||
454 | #define GSM_MAX_SMS_FOLDER_NAME_LEN 20 | ||
455 | |||
456 | /** | ||
457 | * Information about SMS folder. | ||
458 | */ | ||
459 | typedef struct { | ||
460 | /** | ||
461 | * Whether it is really inbox. | ||
462 | */ | ||
463 | bool InboxFolder; | ||
464 | /** | ||
465 | * Where exactly it's saved | ||
466 | */ | ||
467 | GSM_MemoryType Memory; | ||
468 | /** | ||
469 | * Name for SMS folder. | ||
470 | */ | ||
471 | char Name[(GSM_MAX_SMS_FOLDER_NAME_LEN+1)*2]; | ||
472 | } GSM_OneSMSFolder; | ||
473 | |||
474 | /** | ||
475 | * List of SMS folders. | ||
476 | */ | ||
477 | typedef struct { | ||
478 | /** | ||
479 | * Array of structures holding information about each folder. | ||
480 | */ | ||
481 | GSM_OneSMSFolderFolder[GSM_MAX_SMS_FOLDERS]; | ||
482 | /** | ||
483 | * Number of SMS folders. | ||
484 | */ | ||
485 | unsigned char Number; | ||
486 | } GSM_SMSFolders; | ||
487 | |||
488 | #endif | ||
489 | |||
490 | /* How should editor hadle tabs in this file? Add editor commands here. | ||
491 | * vim: noexpandtab sw=8 ts=8 sts=8: | ||
492 | */ | ||