summaryrefslogtreecommitdiffabout
path: root/gammu/emb/common/service/sms
authorzautrix <zautrix>2004-08-07 17:24:40 (UTC)
committer zautrix <zautrix>2004-08-07 17:24:40 (UTC)
commit88b0d33b8b0b1f6ae320cfc863ca6a47fa8fec22 (patch) (unidiff)
tree6331418973714243beb674abc87692277b83869d /gammu/emb/common/service/sms
parentef8a09ce74ad3f0a51484d03fdf009bd5b3677bf (diff)
downloadkdepimpi-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.c765
-rw-r--r--gammu/emb/common/service/sms/gsmems.h20
-rw-r--r--gammu/emb/common/service/sms/gsmmulti.c1148
-rw-r--r--gammu/emb/common/service/sms/gsmmulti.h271
-rw-r--r--gammu/emb/common/service/sms/gsmsms.c663
-rw-r--r--gammu/emb/common/service/sms/gsmsms.h492
6 files changed, 3359 insertions, 0 deletions
diff --git a/gammu/emb/common/service/sms/gsmems.c b/gammu/emb/common/service/sms/gsmems.c
new file mode 100644
index 0000000..a7e20f4
--- a/dev/null
+++ b/gammu/emb/common/service/sms/gsmems.c
@@ -0,0 +1,765 @@
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
540static 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
21unsigned 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
37void 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 */
206static 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
706void 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
742void 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
933GSM_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 */
43typedef 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
54GSM_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
63void 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
71void GSM_Find_Free_Used_SMS2(GSM_Coding_Type Coding,GSM_SMSMessage SMS, int *UsedText, int *FreeText, int *FreeBytes);
72
73unsigned char GSM_MakeSMSIDFromTime(void);
74
75/**
76 * ID during packing SMS for Smart Messaging 3.0, EMS and other
77 */
78typedef 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
204typedef 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
233typedef 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 */
245GSM_Error GSM_EncodeMultiPartSMS (GSM_MultiPartSMSInfo *Info, GSM_MultiSMSMessage *SMS);
246
247/**
248 * Decodes multi part SMS to "readable" format.
249 */
250bool GSM_DecodeMultiPartSMS (GSM_MultiPartSMSInfo *Info, GSM_MultiSMSMessage *SMS, bool ems);
251
252/**
253 * Clears @ref GSM_MultiPartSMSInfo to default values.
254 */
255void GSM_ClearMultiPartSMSInfo (GSM_MultiPartSMSInfo *Info);
256
257/**
258 * Frees any allocated structures inside @ref GSM_MultiPartSMSInfo.
259 */
260void GSM_FreeMultiPartSMSInfo (GSM_MultiPartSMSInfo *Info);
261
262/**
263 * Links SMS messages according to IDs.
264 */
265GSM_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 */
19static 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 */
79static 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
102void 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
181GSM_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
240GSM_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
306GSM_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 */
394static 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
420static 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
490GSM_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
574void 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 */
610void 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 */
25typedef 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 */
41typedef 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 */
77typedef 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 */
90typedef 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 */
103typedef 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 */
112typedef 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 */
125typedef 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 */
157typedef 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 */
167typedef 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 */
185typedef 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 */
219typedef 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 */
277typedef 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 */
367typedef 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
434GSM_Error GSM_DecodeSMSFrame(GSM_SMSMessage *SMS, unsigned char *buffer, GSM_SMSMessageLayout Layout);
435GSM_Error GSM_EncodeSMSFrame(GSM_SMSMessage *SMS, unsigned char *buffer, GSM_SMSMessageLayout Layout, int *length, bool clear);
436
437GSM_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
440void GSM_DecodeUDHHeader(GSM_UDHHeader *UDH);
441void GSM_EncodeUDHHeader(GSM_UDHHeader *UDH);
442
443void 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 */
459typedef 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 */
477typedef 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 */