1 /***************************************************************************
2 * copyright : (C) 2002 by Hendrik Sattler *
3 * mail : post@hendrik-sattler.de *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 ***************************************************************************/
11
12 #ifndef _GNU_SOURCE
13 # define _GNU_SOURCE
14 #endif
15 #ifndef _REENTRANT
16 # define _REENTRANT
17 #endif
18
19 #include <smspdu.h>
20 #include "smscoding.h"
21 #include "smsudh.h"
22
23 #include <charsets.h>
24 #include <helper.h>
25 #include <gtincl.h>
26 #include <intincl.h>
27
28 #include <stdlib.h>
29 #include <string.h>
30 #include <ctype.h>
31
32 static
sms_pdu_create_submit_frame(char * number,unsigned long options,int header_present)33 struct sms_pdu_raw* sms_pdu_create_submit_frame (char* number,
34 unsigned long options,
35 int header_present)
36 {
37 uint8_t sca_len = 0;
38 struct gsm_number sca; //short message service center address
39 uint8_t pdutype; //PDU type
40 uint8_t mr; //message reference
41 uint8_t da_len = 0;
42 struct gsm_number da; //destination address
43 uint8_t pid = 0; //protocol identifier (normally 0)
44 uint8_t dcs; //data coding scheme
45 uint8_t vp_rel = 0xff; //validity period (0xff = max = 63 weeks)
46 //char vp_abs[15]; //validity period (YYMMDDhhmmssTZ)
47
48 struct sms_pdu_raw* frame = mem_alloc(sizeof(*frame),0);
49 char* temp;
50 uint8_t* ptr;
51
52 sms_pdu_raw_init(frame);
53
54 /* not yet supported
55 * zero length means that the phone will use its default
56 */
57 gsm_number_init(&sca);
58 sca_len = 0;
59
60 /* set PDU type to standard values
61 */
62 pdutype = 1; //message type SMS-SUBMIT
63 pdutype |= (1<<4); //validity period format: relative
64 if (options&SMS_CREATE_OPT_REPORT) {
65 pdutype |= (1<<5); //status report request;
66 }
67 if (header_present) {
68 pdutype |= (1<<6); //user data header indication
69 }
70
71 /* message reference must be zero for Siemens phones!
72 */
73 mr = 0;
74
75 /* destination number
76 */
77 if (is_telephone_number(number) == 0) {
78 fprintf(stderr,"%s: %s\n",_("Error"),_("No valid number specified."));
79 return NULL;
80 }
81 gsm_number_init(&da);
82 gsm_number_set_toa(&da,numtype(number));
83 gsm_number_set(&da,number,str_len(number));
84 temp = gsm_number_get(&da);
85 if (temp == NULL || strcmp(temp,number) != 0) {
86 fprintf(stderr,_("%s: sms number cannot have more than %lu digits.\n"),_("Error"),(unsigned long)sizeof(da.digits)-1);
87 return NULL;
88 }
89 mem_realloc(temp,0);
90 da_len = strlen(da.digits);
91
92 /* support "flash-SMS" and unicode here
93 */
94 dcs = 0;
95 if (options&SMS_CREATE_OPT_FLASH) {
96 dcs &= 0xec; //clear all affected bits
97 dcs |= 0x10; //set class 0 message (immediate display)
98 }
99 if (options&SMS_CREATE_OPT_UNICODE) {
100 dcs &= 0xf3; //clear all affected bits
101 dcs |= 0x08; //set unicode charset
102 }
103
104 //leave pid and vp_rel as is
105
106 //create PDU frame
107 ptr = frame->data;
108 ptr[0] = sca_len;
109 ++ptr;
110 if (sca_len) {
111 ptr[0] = gsm_number_get_toa(&sca);
112 ptr += gsm_number_get_semioctets(&sca,ptr)+1;
113 }
114
115 ptr[0] = pdutype;
116 ptr[1] = mr;
117 ptr += 2;
118
119 ptr[0] = da_len;
120 ptr[1] = gsm_number_get_toa(&da);
121 ptr += 2;
122 if (da_len) ptr += gsm_number_get_semioctets(&da,ptr);
123
124 ptr[0] = pid;
125 ptr[1] = dcs;
126 ptr[2] = vp_rel;
127 ptr += 3;
128 frame->size = ptr-frame->data;
129
130 gsm_number_delete(&sca);
131 gsm_number_delete(&da);
132
133 return frame;
134 }
135
sms_pdu_create_submit(char * text,char * number,unsigned long options)136 struct sms_pdu_raw** sms_pdu_create_submit (char* text,
137 char* number,
138 unsigned long options)
139 {
140 ucs4char_t* wide_str = convert_from_system(text);
141 struct sms_pdu_raw** tpdu = NULL;
142 unsigned int i = 0;
143 struct sms_pdu_raw* frame;
144 enum sms_encoding charset = SMS_CHARSET_GSM;
145 gsmchar_t* g1 = NULL;
146 ucs2char_t* g2 = NULL;
147
148 if (options&SMS_CREATE_OPT_UNICODE) charset = SMS_CHARSET_UCS2;
149 if (charset == SMS_CHARSET_GSM &&
150 options&SMS_CREATE_OPT_AUTOCHAR)
151 {
152 g1 = convert_to_gsm(wide_str);
153 if (gsmwidth(g1) < ucs4len(wide_str)) {
154 g2 = convert_to_ucs2(wide_str);
155 if (ucs2len(g2) == ucs4len(wide_str) ||
156 ucs2len(g2) > gsmwidth(g1))
157 {
158 /* more characters from the original string can be
159 * encoded if UCS-2 is used instead of the default GSM character set
160 */
161 fprintf(stderr,"%s: %s\n",_("Notice"),_("Selecting UCS-2 character set."));
162 charset = SMS_CHARSET_UCS2;
163 } else {
164 /* we do not want error messages from convert_to_gsm
165 * being printed twice
166 */
167 mem_realloc(wide_str,0);
168 wide_str = convert_from_gsm(g1);
169 }
170 mem_realloc(g2,0);
171 }
172 mem_realloc(g1,0);
173 }
174 tpdu = sms_data_encode(charset,NULL, wide_str);
175 mem_realloc(wide_str,0);
176
177 if (tpdu == NULL) return NULL;
178
179 frame = sms_pdu_create_submit_frame(number,options,
180 (tpdu[1] == NULL)? 0 : 1);
181 if (frame == NULL) return NULL;
182
183 for (; tpdu[i] != NULL; ++i) {
184 memmove(tpdu[i]->data+frame->size,tpdu[i]->data,tpdu[i]->size);
185 memcpy(tpdu[i]->data,frame->data,frame->size);
186 tpdu[i]->size += frame->size;
187 }
188 mem_realloc(frame,0);
189
190 return tpdu;
191 }
192