Sync froyo ril blob from hyc's codebase.
[xdandroid:rootfs.git] / sms.c
1 //\r
2 // Convert CDMA SMS to GSM and vice versa.\r
3 // By Martin Johnson <M.J.Johnson@massey.ac.nz>\r
4 // GPL\r
5 //\r
6 #include <stdio.h>\r
7 #include <string.h>\r
8 #include "sms_gsm.h"\r
9 \r
10 #ifndef nodroid\r
11 #define LOG_TAG "SMS_RIL"\r
12 #include <utils/Log.h>\r
13 #else\r
14 #define LOGD printf\r
15 #define LOGE printf\r
16 #define LOGI printf\r
17 #endif\r
18 \r
19 int hex2int(char c) {\r
20         if(c>'9') return c-'A'+10;\r
21         return c-'0';\r
22 }\r
23 \r
24 int getbit(char *s,int b) {\r
25         int byte=b/4;\r
26         int bit=b%4;\r
27         \r
28         int data=hex2int(s[byte]);\r
29         if(data&(1<<(3-bit))) return 1;\r
30                 else return 0;\r
31 }\r
32 \r
33 const char hextable[17]="0123456789ABCDEF";\r
34 \r
35 void setbit(char *s,int b, int val) {\r
36         int byte=b/4;\r
37         int bit=b%4;\r
38         \r
39         s[byte]=hextable[hex2int(s[byte]) | (val<<(3-bit))] ;\r
40 }\r
41 \r
42 int getbits(char *s,int startbit,int nbits) {\r
43         int val=0;\r
44         int i;\r
45 \r
46         for(i=0;i<nbits;i++)\r
47                 val = val | (getbit(s,startbit+i)<<(nbits-i-1));\r
48         return val;\r
49 }\r
50 \r
51 void setbits(char *s,int startbit,int nbits,int val) {\r
52         int i;\r
53 \r
54         for(i=0;i<nbits;i++)\r
55                 setbit(s,startbit+i,(val>>(nbits-i-1))&1);\r
56 }\r
57 \r
58 const char decode_table[17]=".1234567890*#...";\r
59 \r
60 void decode_number(char *msg, int length, char *no) {\r
61         \r
62         int ndigits=getbits(msg,2,8);\r
63         int j,digit;\r
64 \r
65         for(j=0;j<ndigits;j++) \r
66                 *no++=decode_table[getbits(msg,10+j*4,4)];\r
67         *no=0;\r
68 }\r
69 \r
70 int encode_digit(int d) {\r
71         int i;\r
72         for(i=0;i<16;i++)\r
73                 if(decode_table[i]==d)\r
74                         return i;\r
75         return 0;\r
76 }               \r
77 \r
78 int encode_number(char *msg, char *no) {\r
79         unsigned int i;\r
80         int digit;\r
81         \r
82         setbits(msg, 0, 2, 0);\r
83         setbits(msg, 2, 8, strlen(no));\r
84         for(i=0;i<strlen(no);i++)\r
85                 setbits(msg,10+i*4, 4, encode_digit(no[i]));\r
86         return (10+i*4+7)/8;\r
87 }\r
88 \r
89 void get_code_and_length(char *msg, int *code, int *length) {\r
90         *code=hex2int(msg[0])*16+hex2int(msg[1]);\r
91         *length=hex2int(msg[2])*16+hex2int(msg[3]);\r
92 }\r
93 \r
94 void decode_bearer_data(char *msg, int length, char *message, int *is_vm) {\r
95     int i=0,j;\r
96     int code,sublength;\r
97 \r
98     while(i<length) {\r
99         get_code_and_length(msg+i*2,&code,&sublength);\r
100         if(code==1) {\r
101             int encoding=getbits(msg+i*2+4,0,5);\r
102             int nchars=getbits(msg+i*2+4,5,8);\r
103             if(encoding==2 || encoding==3) {\r
104                for(j=0;j<nchars;j++)\r
105                    *message++=getbits(msg+i*2+4,13+7*j,7);\r
106             } else \r
107                if(encoding==8 || encoding==0) {\r
108                  for(j=0;j<nchars;j++)\r
109                  *message++=getbits(msg+i*2+4,13+8*j,8);\r
110                 } else 
111                  if(encoding==4) {
112                    for(j=0;j<nchars;j++)
113                     *message++=getbits(msg+i*2+6,13+16*j,8);
114                    } else {
115                       strcpy(message,"bad SMS encoding");
116                       LOGE("Bad encoding: %d",encoding);
117                       message+=16;
118                   }
119                 *message=0;\r
120             } else if (code == 11 && sublength == 1) {\r
121               int msgs;\r
122               if (is_vm) {\r
123                 *is_vm = 1;\r
124                 msgs = hex2int(msg[i*2+4])+16*hex2int(msg[i*2+5]);\r
125                 if (msgs)\r
126                    *is_vm |= 0x10;\r
127             }\r
128         }\r
129         i+=sublength+2;\r
130     }\r
131     \r
132 }\r
133 \r
134 int encode_bearer_data(char *msg, char *data) {\r
135         int msgid=0;\r
136         unsigned int i;\r
137         int b;\r
138         char *start=msg;\r
139         \r
140         for(i=0;i<strlen(data);i++)\r
141                 msgid+=data[i];\r
142                 \r
143         setbits(msg,0,8,0); // message id\r
144         setbits(msg,8,8,3); // 3 bytes\r
145         setbits(msg,16,4,2); // 2 means send\r
146         setbits(msg,20,16,msgid); // use message sum for id\r
147         msg+=10;\r
148         setbits(msg,0,8,01); // user data\r
149         setbits(msg,16,5,02); // set encoding\r
150         setbits(msg,21,8,strlen(data)); // length\r
151         b=29;\r
152         for(i=0;i<strlen(data);i++) {\r
153                 setbits(msg,b,7,data[i]);\r
154                 b=b+7;\r
155         }\r
156         setbits(msg,8,8,(b+7)/8-2);\r
157         msg=msg+2*((b+7)/8);\r
158         setbits(msg,0,24,0x80100);\r
159         setbits(msg,24,24,0x0D0100);\r
160         msg=msg+12;\r
161         return (msg-start)/2;\r
162 }\r
163 \r
164 void decode_cdma_sms(char *pdu, char *from, char *message, int *is_vm) {\r
165     unsigned int i=1;\r
166     int code,length;\r
167     strcpy(from,"000000"); // in case something fails\r
168     strcpy(message,"UNKNOWN"); \r
169     \r
170     if (is_vm)\r
171         *is_vm = 0;\r
172 \r
173     while(i*2<strlen(pdu)) {\r
174         get_code_and_length(pdu+i*2,&code,&length);\r
175         if(code==2) // from\r
176             decode_number(pdu+i*2+4,length,from);\r
177         if(code==8) // bearer_data\r
178             decode_bearer_data(pdu+i*2+4,length,message,is_vm);\r
179         i+=length+2;\r
180     }\r
181 }\r
182 \r
183 void encode_cdma_sms(char *pdu, char *to, char *message) {\r
184         int i;\r
185         int length;\r
186         \r
187         if(strlen(message)>160) LOGE("Error: Message String too long");\r
188         for(i=0;i<512;i++)\r
189                 pdu[i]='0';\r
190         setbits(pdu,0,16,0);\r
191         setbits(pdu,16,24,0x021002);\r
192         pdu=pdu+10;\r
193         setbits(pdu,0,8,0x04);\r
194         length=encode_number(pdu+4, to);\r
195         setbits(pdu,8,8,length);\r
196         pdu=pdu+length*2+4;\r
197         setbits(pdu,0,24,0x060100);\r
198         pdu=pdu+6;\r
199         setbits(pdu,0,8,0x08);\r
200         length=encode_bearer_data(pdu+4, message);\r
201         if(length>255) LOGE("Error: Message Hex too long");\r
202         setbits(pdu,8,8,length);\r
203         pdu=pdu+length*2+4;\r
204         *pdu=0;\r
205 }\r
206 \r
207 char **cdma_to_gsmpdu(char *msg) {\r
208         char from[256];\r
209         char message[256];\r
210         static char hexpdu[1024];\r
211         static char *hexpdus[16];\r
212         int i=0;\r
213         int is_vm=0;\r
214         decode_cdma_sms(msg,from,message,&is_vm);\r
215 //      if(strlen(message)>=160) message[159]=0;\r
216         LOGD("CDMA Message:%s From:%s\n",message,from);\r
217         SmsAddressRec smsaddr;\r
218         SmsTimeStampRec smstime;\r
219         if (is_vm) {\r
220             /* voicemail notifications must have a 4 byte address */\r
221             if (is_vm & 0x10) {\r
222                 /* set message waiting indicator */\r
223                 strcpy(from, "1100");\r
224             } else {\r
225                 /* clear message waiting indicator */\r
226                 strcpy(from, "0100");\r
227             }\r
228         }\r
229         sms_address_from_str(&smsaddr,from,strlen(from));\r
230         if (is_vm) {\r
231             /* voicemail notifications have a clear bottom nibble in toa\r
232              * and an alphanumeric address type */\r
233             smsaddr.toa = 0xd0;\r
234         }\r
235         sms_timestamp_now(&smstime);\r
236         SmsPDU *pdu=smspdu_create_deliver_utf8((const unsigned char *)message,strlen(message),&smsaddr,&smstime);\r
237         //hexpdu=malloc(512);\r
238         char *s=hexpdu;\r
239         while(*pdu) {\r
240                 smspdu_to_hex(*pdu, s,512);\r
241                 hexpdus[i]=s;\r
242                 s=s+strlen(s)+2;\r
243                 smspdu_free(*pdu);\r
244                 i++;\r
245                 pdu++;\r
246         }\r
247         hexpdus[i]=0;\r
248         return hexpdus;\r
249 }\r
250 \r
251 char *gsm_to_cdmapdu(char *msg) {\r
252         char to[256];\r
253         char message[256];\r
254         static char hexpdu[512];\r
255         SmsAddressRec smsaddr;\r
256         sms_address_from_str(&smsaddr,"000000",6);\r
257 \r
258         SmsPDU pdu=smspdu_create_from_hex( msg, strlen(msg) );\r
259         if(smspdu_get_receiver_address(pdu,&smsaddr)<0) {\r
260                 LOGE("Error: no receiver address");\r
261                 smspdu_get_sender_address(pdu,&smsaddr);\r
262         }\r
263         sms_address_to_str(&smsaddr,to,256);\r
264         if(to[0]=='+') { // convert + to 00 otherwise international sms doesn't work\r
265                 memmove(to+1,to,255);\r
266                 to[0]='0';\r
267                 to[1]='0';\r
268         }\r
269         int length=smspdu_get_text_message(pdu, message, 256);\r
270         message[length]=0;\r
271         smspdu_free(pdu);\r
272         LOGD("GSM Message:%s To:%s\n",message,to);\r
273         encode_cdma_sms(hexpdu,to,message);\r
274         return hexpdu;\r
275 }\r
276 \r