summaryrefslogtreecommitdiffabout
path: root/gammu/emb/common/service/sms/gsmsms.c
Unidiff
Diffstat (limited to 'gammu/emb/common/service/sms/gsmsms.c') (more/less context) (ignore whitespace changes)
-rw-r--r--gammu/emb/common/service/sms/gsmsms.c663
1 files changed, 663 insertions, 0 deletions
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 */