Implemented connection type "tcp" (GCT_TCP), use <hostname>:<port> as "port"
[gnokii.git] / common / gsm-sms.c
1 /*
2
3   $Id$
4
5   G N O K I I
6
7   A Linux/Unix toolset and driver for Nokia mobile phones.
8
9   Copyright (C) 2001 Pawe³ Kot <pkot@linuxnews.pl>
10
11   Released under the terms of the GNU GPL, see file COPYING for more details.
12
13   Library for parsing and creating Short Messages (SMS).
14
15   $Log$
16   Revision 1.1.1.8  2002/04/03 00:08:04  short
17   Found in "gnokii-working" directory, some November-patches version
18
19   Revision 1.1  2001/11/08 16:23:21  pkot
20   New version of libsms. Not functional yet, but it reasonably stable API.
21
22   Revision 1.1  2001/07/09 23:06:26  pkot
23   Moved sms.* files from my hard disk to CVS
24
25 */
26
27 #include <stdlib.h>
28
29 #include "gsm-common.h"
30 #include "gsm-encoding.h"
31
32 struct udh_data {
33         unsigned int length;
34         char *header;
35 };
36
37 /* Number of header specific octets in SMS header (before data) */
38 static unsigned short DataOffset[] = {
39         4, /* SMS Deliver */
40         3, /* SMS Deliver Report */
41         5, /* SMS Submit */
42         3, /* SMS Submit Report */
43         3, /* SMS Command */
44         3  /* SMS Status Report */
45 };
46
47 /* User data headers */
48 static struct udh_data headers[] = {
49         { 0x00, "" },
50         { 0x05, "\x00\x03\x01\x00\x00" }, /* Concatenated messages */
51         { 0x06, "\x05\x04\x15\x82\x00\x00" }, /* Operator logos */
52         { 0x06, "\x05\x04\x15\x82\x00\x00" }, /* Caller logos */
53         { 0x06, "\x05\x04\x15\x81\x00\x00" }, /* Ringtones */
54         { 0x04, "\x03\x01\x00\x00" }, /* Voice Messages */
55         { 0x04, "\x03\x01\x01\x00" }, /* Fax Messages */
56         { 0x04, "\x03\x01\x02\x00" }, /* Email Messages */
57         { 0x00, "" }
58 };
59
60
61 /***
62  *** Util functions
63  ***/
64
65 static char *GetBCDNumber(u8 *Number)
66 {
67         static char Buffer[20] = "";
68
69         /* This is the length of BCD coded number */
70         int length=Number[0];
71         int count;
72         int Digit;
73
74         switch (Number[1]) {
75
76         case 0xd0:
77                 Unpack7BitCharacters(0, length, length, Number+2, Buffer);
78                 Buffer[length] = 0;
79                 break;
80         default:
81                 if (Number[1] == SMS_International)
82                         sprintf(Buffer, "+");
83                 else
84                         Buffer[0] = '\0';
85                 for (count = 0; count < length - 1; count++) {
86                         Digit = Number[count+2] & 0x0f;
87                         if (Digit < 10) sprintf(Buffer, "%s%d", Buffer, Digit);
88                         Digit = Number[count+2] >> 4;
89                         if (Digit < 10) sprintf(Buffer, "%s%d", Buffer, Digit);
90                 }
91                 break;
92         }
93         return Buffer;
94 }
95
96 #if 0
97 char *GetBCDNumber(u8 *Number, int maxdigits, int maxbytes) 
98 {
99         static char Buffer[22] = "";
100         int length = Number[0]; /* This is the length of BCD coded number */
101         int bytes = 0, digits = 0;
102         int Digit = 0;
103         
104         dprintf("%i\n", length);
105         
106         if (Number[1] == 0x91) {
107                 sprintf(Buffer, "+");
108         } else {
109                 Buffer[0] = '\0';
110         }
111         
112         while ((Digit < 10) && (bytes < length) && (digits < maxdigits)) {
113                 Digit = Number[bytes + 2] & 0x0f;
114                 if (Digit < 10) {
115                         sprintf(Buffer, "%s%d", Buffer, Digit);
116                         digits++;
117                         Digit = Number[bytes + 2] >> 4;
118                         if (Digit < 10) {
119                                 sprintf(Buffer, "%s%d", Buffer, Digit);
120                                 digits++;
121                         }
122                 }
123                 bytes++;
124         } 
125         
126         return Buffer;
127 }
128 #endif
129
130 static char *PrintDateTime(u8 *Number) 
131 {
132         static char Buffer[23] = "";
133
134         memset(Buffer, 0, 23);
135         sprintf(Buffer, "%d%d-", Number[0] & 0x0f, Number[0] >> 4);
136         sprintf(Buffer, "%s%d%d-", Buffer, Number[1] & 0x0f, Number[1] >> 4);
137         sprintf(Buffer, "%s%d%d ", Buffer, Number[2] & 0x0f, Number[2] >> 4);
138         sprintf(Buffer, "%s%d%d:", Buffer, Number[3] & 0x0f, Number[3] >> 4);
139         sprintf(Buffer, "%s%d%d:", Buffer, Number[4] & 0x0f, Number[4] >> 4);
140         sprintf(Buffer, "%s%d%d",  Buffer, Number[5] & 0x0f, Number[5] >> 4);
141         if (Number[6] & 0x08) 
142                 sprintf(Buffer, "%s-", Buffer);
143         else
144                 sprintf(Buffer, "%s+", Buffer);
145         sprintf(Buffer, "%s%02d00", Buffer, (10 * (Number[6] & 0x07) + (Number[6] >> 4)) / 4);
146
147         return Buffer;
148 }
149
150 static SMS_DateTime *UnpackDateTime(u8 *Number, SMS_DateTime *dt)
151 {
152         dt->Year     =  10 * (Number[0] & 0x0f) + (Number[0] >> 4);
153         dt->Month    =  10 * (Number[1] & 0x0f) + (Number[1] >> 4);
154         dt->Day      =  10 * (Number[2] & 0x0f) + (Number[2] >> 4);
155         dt->Hour     =  10 * (Number[3] & 0x0f) + (Number[3] >> 4);
156         dt->Minute   =  10 * (Number[4] & 0x0f) + (Number[4] >> 4);
157         dt->Second   =  10 * (Number[5] & 0x0f) + (Number[5] >> 4);
158         dt->Timezone = (10 * (Number[6] & 0x07) + (Number[6] >> 4)) / 4;
159         if (Number[6] & 0x08) dt->Timezone = -dt->Timezone;
160
161         return dt;
162 }
163
164 /***
165  *** ENCODING SMS
166  ***/
167
168 /* This function encodes the UserDataHeader as described in:
169    - GSM 03.40 version 6.1.0 Release 1997, section 9.2.3.24
170    - Smart Messaging Specification, Revision 1.0.0, September 15, 1997
171 */
172 static GSM_Error EncodeUDH(SMS_UDHInfo UDHi, char *UDH)
173 {
174         unsigned char pos;
175
176         pos = UDH[0];
177         switch (UDHi.Type) {
178         case SMS_NoUDH:
179                 break;
180         case SMS_VoiceMessage:
181         case SMS_FaxMessage:
182         case SMS_EmailMessage:
183                 UDH[pos+4] = UDHi.u.SpecialSMSMessageIndication.MessageCount;
184                 if (UDHi.u.SpecialSMSMessageIndication.Store) UDH[pos+3] |= 0x80;
185         case SMS_ConcatenatedMessages:
186         case SMS_OpLogo:
187         case SMS_CallerIDLogo:
188         case SMS_Ringtone:
189                 UDH[0] += headers[UDHi.Type].length;
190                 memcpy(UDH+pos+1, headers[UDHi.Type].header, headers[UDHi.Type].length);
191                 break;
192         default:
193                 fprintf(stderr, _("Not supported User Data Header type\n"));
194                 break;
195         }
196         return GE_NONE;
197 }
198
199 static GSM_Error EncodeSMSSubmitHeader(GSM_SMSMessage *SMS, char *frame)
200 {
201         GSM_Error error = GE_NONE;
202         int i;
203
204         /* SMS Center */
205
206         /* Reply Path */
207         if (SMS->ReplyViaSameSMSC) frame[13] |= 0x80;
208
209         /* User Data Header */
210         for (i = 0; SMS->UDH[i].Type != SMS_NoUDH; i++) {
211                 frame[13] |= 0x40;
212                 error = EncodeUDH(SMS->UDH[i], frame);
213                 if (error != GE_NONE) return error;
214         }
215
216         /* Status (Delivery) Report Request */
217         if (SMS->Report) frame[13] |= 0x20;
218
219         /* Validity Period Format: mask - 0x00, 0x10, 0x08, 0x18 */
220         frame[13] |= ((SMS->Validity.VPF & 0x03) << 3);
221
222         /* Reject Duplicates */
223         if (SMS->RejectDuplicates) frame[13] |= 0x04;
224
225         /* Message Type is already set */
226
227         /* Message Reference */
228         /* Can we set this? */
229
230         /* Protocol Identifier */
231         /* FIXME: allow to change this in better way.
232            currently only 0x5f == `Return Call Message' is used */
233         frame[16] = SMS->PID;
234
235         /* Data Coding Scheme */
236         switch (SMS->DCS.Type) {
237         case SMS_GeneralDataCoding:
238                 if (SMS->DCS.u.General.Compressed) frame[17] |= 0x20;
239                 if (SMS->DCS.u.General.Class) frame[17] |= (0x10 | (SMS->DCS.u.General.Class - 1));
240                 frame[17] |= ((SMS->DCS.u.General.Alphabet & 0x03) << 2);
241                 break;
242         case SMS_MessageWaiting:
243                 if (SMS->DCS.u.MessageWaiting.Discard) frame[17] |= 0xc0;
244                 else if (SMS->DCS.u.MessageWaiting.Alphabet == SMS_UCS2) frame[17] |= 0xe0;
245                 else frame[17] |= 0xd0;
246                 if (SMS->DCS.u.MessageWaiting.Active) frame[17] |= 0x80;
247                 frame[17] |= (SMS->DCS.u.MessageWaiting.Type & 0x03);
248                 break;
249         default:
250                 fprintf(stderr, _("Wrong Data Coding Scheme (DCS) format\n"));
251                 return GE_SMSWRONGFORMAT;
252         }
253
254         /* User Data Length */
255         /* Will be filled later. */
256
257         /* Destination Address */
258
259         /* Validity Period */
260         switch (SMS->Validity.VPF) {
261         case SMS_EnhancedFormat:
262                 break;
263         case SMS_RelativeFormat:
264                 break;
265         case SMS_AbsoluteFormat:
266                 break;
267         default:
268                 break;
269         }
270
271         return GE_NONE;
272 }
273
274 static GSM_Error EncodeSMSDeliverHeader()
275 {
276         return GE_NONE;
277 }
278
279 static GSM_Error EncodeSMSHeader(GSM_SMSMessage *SMS, char *frame)
280 /* We can create either SMS DELIVER (for saving in Inbox) or SMS SUBMIT
281    (for sending or saving in Outbox) message */
282 {
283         /* Set SMS type */
284         frame[12] |= (SMS->Type >> 1);
285         switch (SMS->Type) {
286         case SMS_Submit: /* we send SMS or save it in Outbox */
287                 return EncodeSMSSubmitHeader(SMS, frame);
288         case SMS_Deliver: /* we save SMS in Inbox */
289                 return EncodeSMSSubmitHeader(SMS, frame);
290         default: /* we don't create other formats of SMS */
291                 return GE_SMSWRONGFORMAT;
292         }
293 }
294
295 /* This function encodes SMS as described in:
296    - GSM 03.40 version 6.1.0 Release 1997, section 9
297 */
298 GSM_Error EncodePDUSMS(GSM_SMSMessage *SMS, char *frame)
299 {
300         GSM_Error error = GE_NONE;
301         int i;
302
303         /* Short Message Data info element id */
304
305         /* Length of Short Message Data */
306
307         /* Short Message Reference value */
308         if (SMS->Number) frame[3] = SMS->Number;
309
310         /* Short Message status */
311         if (SMS->Status) frame[1] = SMS->Status;
312
313         /* Message Type */
314
315         /* SMSC number */
316         if (SMS->MessageCenter.Number) {
317 //              error = GSM->GetSMSCenter(&SMS->MessageCenter);
318                 
319                 if (error != GE_NONE)
320                         return error;
321                 strcpy(SMS->MessageCenter.Number, "0");
322         }
323         dprintf("Sending SMS to %s via message center %s\n", SMS->Sender, SMS->MessageCenter.Number);
324
325         /* Header coding */
326 //      EncodeUDH(SMS, frame);
327 //      if (error != GE_NONE) return error;
328
329         /* User Data Header - if present */
330         for (i = 0; SMS->UDH[i].Type != SMS_NoUDH; i++) {
331                 error = EncodeUDH(SMS->UDH[i], frame);
332                 if (error != GE_NONE) return error;
333         }
334
335         /* User Data */
336         //      EncodeData(&(SMS->MessageText), &(SMS->DCS), frame);
337
338         return error;
339 }
340
341 /* This function does simple SMS encoding - no PDU coding */
342 GSM_Error EncodeTextSMS()
343 {
344         return GE_NONE;
345 }
346
347 /***
348  *** DECODING SMS
349  ***/
350
351 static GSM_Error SMSStatus(unsigned char status, GSM_SMSMessage *sms)
352 {
353         if (status < 0x03) {
354                 strcpy(sms->MessageText, _("Delivered"));
355                 switch (status) {
356                 case 0x00:
357                         dprintf(_("SM received by the SME"));
358                         break;
359                 case 0x01:
360                         dprintf(_("SM forwarded by the SC to the SME but the SC is unable to confirm delivery"));
361                         break;
362                 case 0x02:
363                         dprintf(_("SM replaced by the SC"));
364                         break;
365                 }
366                 sms->Length = 10;
367         } else if (status & 0x40) {
368
369                 strcpy(sms->MessageText, _("Failed"));
370
371                 /* more detailed reason only for debug */
372
373                 if (status & 0x20) {
374                         dprintf(_("Temporary error, SC is not making any more transfer attempts\n"));
375
376                         switch (status) {
377                         case 0x60:
378                                 dprintf(_("Congestion"));
379                                 break;
380                         case 0x61:
381                                 dprintf(_("SME busy"));
382                                 break;
383                         case 0x62:
384                                 dprintf(_("No response from SME"));
385                                 break;
386                         case 0x63:
387                                 dprintf(_("Service rejected"));
388                                 break;
389                         case 0x64:
390                                 dprintf(_("Quality of service not aviable"));
391                                 break;
392                         case 0x65:
393                                 dprintf(_("Error in SME"));
394                                 break;
395                         default:
396                                 dprintf(_("Reserved/Specific to SC: %x"), status);
397                                 break;
398                         }
399                 } else {
400                         dprintf(_("Permanent error, SC is not making any more transfer attempts\n"));
401                         switch (status) {
402                         case 0x40:
403                                 dprintf(_("Remote procedure error"));
404                                 break;
405                         case 0x41:
406                                 dprintf(_("Incompatibile destination"));
407                                 break;
408                         case 0x42:
409                                 dprintf(_("Connection rejected by SME"));
410                                 break;
411                         case 0x43:
412                                 dprintf(_("Not obtainable"));
413                                 break;
414                         case 0x44:
415                                 dprintf(_("Quality of service not aviable"));
416                                 break;
417                         case 0x45:
418                                 dprintf(_("No internetworking available"));
419                                 break;
420                         case 0x46:
421                                 dprintf(_("SM Validity Period Expired"));
422                                 break;
423                         case 0x47:
424                                 dprintf(_("SM deleted by originating SME"));
425                                 break;
426                         case 0x48:
427                                 dprintf(_("SM Deleted by SC Administration"));
428                                 break;
429                         case 0x49:
430                                 dprintf(_("SM does not exist"));
431                                 break;
432                         default:
433                                 dprintf(_("Reserved/Specific to SC: %x"), status);
434                                 break;
435                         }
436                 }
437                 sms->Length = 6;
438         } else if (status & 0x20) {
439                 strcpy(sms->MessageText, _("Pending"));
440
441                 /* more detailed reason only for debug */
442                 dprintf(_("Temporary error, SC still trying to transfer SM\n"));
443                 switch (status) {
444                 case 0x20:
445                         dprintf(_("Congestion"));
446                         break;
447                 case 0x21:
448                         dprintf(_("SME busy"));
449                         break;
450                 case 0x22:
451                         dprintf(_("No response from SME"));
452                         break;
453                 case 0x23:
454                         dprintf(_("Service rejected"));
455                         break;
456                 case 0x24:
457                         dprintf(_("Quality of service not aviable"));
458                         break;
459                 case 0x25:
460                         dprintf(_("Error in SME"));
461                         break;
462                 default:
463                         dprintf(_("Reserved/Specific to SC: %x"), status);
464                         break;
465                 }
466                 sms->Length = 7;
467         } else {
468                 strcpy(sms->MessageText, _("Unknown"));
469
470                 /* more detailed reason only for debug */
471                 dprintf(_("Reserved/Specific to SC: %x"), status);
472                 sms->Length = 8;
473         }
474         return GE_NONE;
475 }
476
477 static GSM_Error DecodeData(char *message, char *output, int length, SMS_DataCodingScheme dcs, int udhlen, int size)
478 {
479         /* Unicode */
480         if ((dcs.Type & 0x08) == 0x08) {
481                 length = (length - udhlen)/2;
482                 DecodeUnicode(output, message, length);
483         /* 8bit SMS */
484         } else {
485                 if ((dcs.Type & 0xf4) == 0xf4) {
486                         memcpy(output, message, length);
487                         /* 7bit SMS */
488                 } else {
489                         length = length - (udhlen * 8 + ((7-udhlen)%7)) / 7;
490                         Unpack7BitCharacters((7-udhlen)%7, size, length, message, output);
491                 }
492                 DecodeAscii(output, output, length);
493         }
494         dprintf("%s\n", output);
495         return GE_NONE;
496 }
497
498 /* This function decodes UDH as described in:
499    - GSM 03.40 version 6.1.0 Release 1997, section 9.2.3.24
500    - Smart Messaging Specification, Revision 1.0.0, September 15, 1997
501 */
502 static GSM_Error DecodeUDH(char *SMSMessage, SMS_UDHInfo **UDHi, GSM_SMSMessage *sms)
503 {
504         unsigned char length, pos, nr;
505
506         length = SMSMessage[0];
507         pos = 1;
508         nr = 0;
509         while (length > 0) {
510                 unsigned char udh_length;
511
512                 udh_length = SMSMessage[pos+1];
513                 switch (SMSMessage[pos]) {
514                 case 0x00: // Concatenated short messages
515                         dprintf("Concat UDH length: %d\n", udh_length);
516                         UDHi[nr]->Type = SMS_ConcatenatedMessages;
517                         UDHi[nr]->u.ConcatenatedShortMessage.ReferenceNumber = SMSMessage[pos + 3];
518                         UDHi[nr]->u.ConcatenatedShortMessage.MaximumNumber   = SMSMessage[pos + 4];
519                         UDHi[nr]->u.ConcatenatedShortMessage.CurrentNumber   = SMSMessage[pos + 5];
520                         break;
521                 case 0x01: // Special SMS Message Indication
522                         switch (SMSMessage[pos + 3] & 0x03) {
523                         case 0x00:
524                                 UDHi[nr]->Type = SMS_VoiceMessage;
525                                 break;
526                         case 0x01:
527                                 UDHi[nr]->Type = SMS_FaxMessage;
528                                 break;
529                         case 0x02:
530                                 UDHi[nr]->Type = SMS_EmailMessage;
531                                 break;
532                         default:
533                                 UDHi[nr]->Type = SMS_UnknownUDH;
534                                 break;
535                         }
536                         UDHi[nr]->u.SpecialSMSMessageIndication.Store = (SMSMessage[pos + 3] & 0x80) >> 7;
537                         UDHi[nr]->u.SpecialSMSMessageIndication.MessageCount = SMSMessage[pos + 4];
538                         break;
539                 case 0x04: // Application port addression scheme, 8 bit address
540                         break;
541                 case 0x05: // Application port addression scheme, 16 bit address
542                         break;
543                 case 0x06: // SMSC Control Parameters
544                         break;
545                 case 0x07: // UDH Source Indicator
546                         break;
547                 default:
548                         break;
549                 }
550                 length -= (udh_length + 2);
551                 pos += (udh_length + 2);
552                 nr++;
553         }
554         sms->UDH_No = nr;
555
556         return GE_NONE;
557 }
558
559 static GSM_Error DecodeSMSSubmit()
560 {
561         return GE_NONE;
562 }
563
564 static GSM_Error DecodeSMSDeliver()
565 {
566         return GE_NONE;
567 }
568
569 static GSM_Error DecodeSMSHeader(unsigned char *message, GSM_SMSMessage *sms)
570 {
571         /* Short Message Type */
572         switch (sms->Type = message[7]) {
573         case SMS_Deliver:
574                 dprintf("Mobile Terminated message:\n");
575                 break;
576         case SMS_Delivery_Report:
577                 dprintf("Delivery Report:\n");
578                 UnpackDateTime(message + 39 + DataOffset[sms->Type], &(sms->Time));
579                 dprintf("\tDelivery date: %s\n", PrintDateTime(message + 39 + DataOffset[sms->Type]));
580                 break;
581         case SMS_Submit:
582                 dprintf("Mobile Originated message:\n");
583                 break;
584         default:
585                 dprintf("Not supported message:\n");
586                 break;
587         }
588         /* Short Message status */
589         sms->Status = message[4];
590         dprintf("\tStatus: ");
591         switch (sms->Status) {
592         case SMS_Read:
593                 dprintf("READ\n");
594                 break;
595         case SMS_Unread:
596                 dprintf("UNREAD\n");
597                 break;
598         case SMS_Sent:
599                 dprintf("SENT\n");
600                 break;
601         case SMS_Unsent:
602                 dprintf("UNSENT\n");
603                 break;
604         default:
605                 dprintf("UNKNOWN\n");
606                 break;
607         }
608
609         /* Short Message location in memory */
610         sms->Number = message[6];
611         dprintf("\tLocation: %d\n", sms->Number);
612
613         /* Short Message Center */
614         strcpy(sms->MessageCenter.Number, GetBCDNumber(message));
615         dprintf("\tSMS center number: %s\n", sms->MessageCenter.Number);
616         sms->ReplyViaSameSMSC = false;
617         if (sms->RemoteNumber.number[0] == 0 && (message[12] & 0x80)) {
618                 sms->ReplyViaSameSMSC = true;
619         }
620
621         /* Remote number */
622         message[20+DataOffset[sms->Type]] = ((message[20+DataOffset[sms->Type]])+1)/2+1;
623         dprintf("\tRemote number (recipient or sender): %s\n", GSM_GetBCDNumber(message + 20 + DataOffset[sms->Type]));
624         strcpy(sms->RemoteNumber.number, GetBCDNumber(message + 20 + DataOffset[sms->Type]));
625
626         UnpackDateTime(message + 24 + DataOffset[sms->Type], &(sms->Time));
627         dprintf("\tDate: %s\n", PrintDateTime(message + 24 + DataOffset[sms->Type]));
628
629         /* Data Coding Scheme */
630         if (sms->Type != SMS_Delivery_Report)
631                 sms->DCS.Type = message[18 + DataOffset[sms->Type]];
632         else
633                 sms->DCS.Type = 0;
634
635         /* User Data Header */
636         if (message[20] & 0x40) /* UDH header available */
637                 DecodeUDH(message + 31 + DataOffset[sms->Type], (SMS_UDHInfo **)sms->UDH, sms);
638         else                    /* No UDH */
639                 sms->UDH_No = 0;
640
641         return GE_NONE;
642 }
643
644 /* This function decodes SMS as described in:
645    - GSM 03.40 version 6.1.0 Release 1997, section 9
646 */
647 GSM_Error DecodePDUSMS(unsigned char *message, GSM_SMSMessage *SMS, int MessageLength)
648 {
649         int i, udhlen = 0;
650
651         DecodeSMSHeader(message, SMS);
652         for (i = 0; i < SMS->UDH_No; i++) {
653                 udhlen += headers[SMS->UDH[i].Type].length;
654         }
655         if (SMS->Type == SMS_Delivery_Report) {
656                 SMSStatus(message[22], SMS);
657         } else {
658                 int size = MessageLength -
659                            39 -                    /* Header Length */
660                            DataOffset[SMS->Type] - /* offset */
661                            udhlen -                /* UDH Length */
662                            2;                      /* checksum */
663                 DecodeData(message + 39 + DataOffset[SMS->Type] + udhlen,
664                            (unsigned char *)&(SMS->MessageText),
665                            SMS->Length, SMS->DCS,
666                            udhlen, size);
667         }
668         
669         return GE_NONE;
670 }
671
672 /* This function does simple SMS decoding - no PDU coding */
673 GSM_Error DecodeTextSMS(unsigned char *message, GSM_SMSMessage *sms)
674 {
675 #if 0
676         int w, tmp, i;
677         unsigned char output[161];
678         
679         sms->EightBit = false;
680         w = (7 - off) % 7;
681         if (w < 0) w = (14 - off) % 14;
682         sms->Length = message[9 + 11 + offset] - (off * 8 + w) / 7;
683         offset += off;
684         w = (7 - off) % 7;
685         if (w < 0) w = (14 - off) % 14;
686         tmp = Unpack7BitCharacters(w, length-31-9-offset, sms->Length, message+9+31+offset, output);
687         dprintf("   7 bit SMS, body is (length %i): ",sms->Length);
688         for (i = 0; i < tmp; i++) {
689                 dprintf("%c", DecodeWithDefaultAlphabet(output[i]));
690                 sms->MessageText[i] = DecodeWithDefaultAlphabet(output[i]);
691         }
692         dprintf("\n");
693 #endif
694         return GE_NONE;
695 }