1 /*
2 
3   G N O K I I
4 
5   A Linux/Unix toolset and driver for the mobile phones.
6 
7   This file is part of gnokii.
8 
9   Gnokii is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; either version 2 of the License, or
12   (at your option) any later version.
13 
14   Gnokii is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18 
19   You should have received a copy of the GNU General Public License
20   along with gnokii; if not, write to the Free Software
21   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22 
23   Copyright (C) 2001-2011 Pawel Kot
24   Copyright (C) 2001-2002 Markus Plail, Pavel Machek <pavel@ucw.cz>
25   Copyright (C) 2002-2003 Ladis Michl
26   Copyright (C) 2003-2004 BORBELY Zoltan
27   Copyright (C) 2006      Igor Popik
28 
29   Library for parsing and creating Short Messages (SMS).
30 
31 */
32 
33 #include "config.h"
34 
35 #include <glib.h>
36 
37 #include <stdlib.h>
38 #include <string.h>
39 #include <time.h>
40 
41 #include "gnokii-internal.h"
42 #include "gnokii.h"
43 
44 #include "sms-nokia.h"
45 
46 #ifdef ENABLE_NLS
47 #  include <locale.h>
48 #endif
49 
50 #undef ERROR
51 #define ERROR() do { if (error != GN_ERR_NONE) return error; } while (0)
52 
53 struct sms_udh_data {
54 	unsigned int length;
55 	char *header;
56 };
57 
58 #define MAX_SMS_PART 140
59 
60 /* User data headers */
61 static struct sms_udh_data headers[] = {
62 	{ 0x00, "" },
63 	{ 0x05, "\x00\x03\x01\x00\x00" },     /* Concatenated messages */
64 	{ 0x06, "\x05\x04\x15\x81\x00\x00" }, /* Ringtones */
65 	{ 0x06, "\x05\x04\x15\x82\x00\x00" }, /* Operator logos */
66 	{ 0x06, "\x05\x04\x15\x83\x00\x00" }, /* Caller logos */
67 	{ 0x06, "\x05\x04\x15\x8a\x00\x00" }, /* Multipart Message */
68 	{ 0x06, "\x05\x04\x23\xf4\x00\x00" }, /* WAP vCard */
69 	{ 0x06, "\x05\x04\x23\xf5\x00\x00" }, /* WAP vCalendar */
70 	{ 0x06, "\x05\x04\x23\xf6\x00\x00" }, /* WAP vCardSecure */
71 	{ 0x06, "\x05\x04\x23\xf7\x00\x00" }, /* WAP vCalendarSecure */
72 	{ 0x04, "\x01\x02\x00\x00" },         /* Voice Messages */
73 	{ 0x04, "\x01\x02\x01\x00" },         /* Fax Messages */
74 	{ 0x04, "\x01\x02\x02\x00" },         /* Email Messages */
75 	{ 0x06, "\x05\x04\x0b\x84\x23\xf0" }, /* WAP PUSH */
76 	{ 0x06, "\x05\x04\x0b\x84\x0b\x84" },
77 	{ 0x00, "" },
78 };
79 
80 
81 /**
82  * sms_default - fills in SMS structure with the default values
83  * @sms: pointer to a structure we need to fill in
84  *
85  * Default settings:
86  *  - no delivery report
87  *  - no Class Message
88  *  - no compression
89  *  - 7 bit data
90  *  - message validity for 3 days
91  *  - unsent status
92  */
sms_default(gn_sms * sms)93 static void sms_default(gn_sms *sms)
94 {
95 	memset(sms, 0, sizeof(gn_sms));
96 
97 	sms->type = GN_SMS_MT_Deliver;
98 	sms->delivery_report = false;
99 	sms->status = GN_SMS_Unsent;
100 	sms->validity = 4320; /* 4320 minutes == 72 hours */
101 	sms->dcs.type = GN_SMS_DCS_GeneralDataCoding;
102 	sms->dcs.u.general.compressed = false;
103 	sms->dcs.u.general.alphabet = GN_SMS_DCS_DefaultAlphabet;
104 	sms->dcs.u.general.m_class = 0;
105 }
106 
gn_sms_default_submit(gn_sms * sms)107 GNOKII_API void gn_sms_default_submit(gn_sms *sms)
108 {
109 	sms_default(sms);
110 	sms->type = GN_SMS_MT_Submit;
111 	sms->memory_type = GN_MT_SM;
112 }
113 
gn_sms_default_deliver(gn_sms * sms)114 GNOKII_API void gn_sms_default_deliver(gn_sms *sms)
115 {
116 	sms_default(sms);
117 	sms->type = GN_SMS_MT_Deliver;
118 	sms->memory_type = GN_MT_ME;
119 }
120 
121 
122 /***
123  *** Util functions
124  ***/
125 
126 /**
127  * sms_timestamp_print - formats date and time in the human readable manner
128  * @number: binary coded date and time
129  *
130  * The function converts binary date time into an easily readable form.
131  * It is Y2K compliant.
132  */
sms_timestamp_print(u8 * number)133 static char *sms_timestamp_print(u8 *number)
134 {
135 #ifdef DEBUG
136 #define LOCAL_DATETIME_MAX_LENGTH 26
137 	static char buffer[LOCAL_DATETIME_MAX_LENGTH];
138 	char buf[5];
139 	int i;
140 
141 	if (!number) return NULL;
142 
143 	memset(buffer, 0, LOCAL_DATETIME_MAX_LENGTH);
144 
145 	/* Ugly hack, but according to the GSM specs, the year is stored
146 	 * as the 2 digit number. */
147 	if ((10*(number[0] & 0x0f) + (number[0] >> 4)) < 70)
148 		snprintf(buffer, sizeof(buffer), "20");
149 	else
150 		snprintf(buffer, sizeof(buffer), "19");
151 
152 	for (i = 0; i < 6; i++) {
153 		int c;
154 		char buf2[4];
155 		switch (i) {
156 		case 0:
157 		case 1:
158 			c = '-';
159 			break;
160 		case 3:
161 		case 4:
162 			c = ':';
163 			break;
164 		default:
165 			c = ' ';
166 			break;
167 		}
168 		snprintf(buf2, 4, "%d%d%c", number[i] & 0x0f, number[i] >> 4, c);
169 		strncat(buffer, buf2, sizeof(buffer) - strlen(buffer));
170 	}
171 
172 	/* The GSM spec is not clear what is the sign of the timezone when the
173 	 * 6th bit is set. Some SMSCs are compatible with our interpretation,
174 	 * some are not. If your operator does use incompatible SMSC and wrong
175 	 * sign disturbs you, change the sign here.
176 	 */
177 	if (number[6] & 0x08)
178 		strncat(buffer, "-", sizeof(buffer) - strlen(buffer));
179 	else
180 		strncat(buffer, "+", sizeof(buffer) - strlen(buffer));
181 	/* The timezone is given in quarters. The base is GMT. */
182 	snprintf(buf, sizeof(buf), "%02d00", (10 * (number[6] & 0x07) + (number[6] >> 4)) / 4);
183 	strncat(buffer, buf, sizeof(buffer) - strlen(buffer));
184 
185 	return buffer;
186 #undef LOCAL_DATETIME_MAX_LENGTH
187 #else
188 	return NULL;
189 #endif /* DEBUG */
190 }
191 
192 /**
193  * sms_timestamp_unpack - converts binary datetime to the gnokii's datetime struct
194  * @number: binary coded date and time
195  * @dt: datetime structure to be filled
196  *
197  * The function fills int gnokii datetime structure basing on the given datetime
198  * in the binary format. It is Y2K compliant.
199  */
sms_timestamp_unpack(unsigned char * number,gn_timestamp * dt)200 gn_timestamp *sms_timestamp_unpack(unsigned char *number, gn_timestamp *dt)
201 {
202 	if (!dt)
203 		return NULL;
204 	memset(dt, 0, sizeof(gn_timestamp));
205 	if (!number)
206 		return dt;
207 
208 	dt->year = 10 * (number[0] & 0x0f) + (number[0] >> 4);
209 
210 	/* Ugly hack, but according to the GSM specs, the year is stored
211 	 * as the 2 digit number. */
212 	if (dt->year < 70)
213 		dt->year += 2000;
214 	else
215 		dt->year += 1900;
216 
217 	dt->month    =  10 * (number[1] & 0x0f) + (number[1] >> 4);
218 	dt->day      =  10 * (number[2] & 0x0f) + (number[2] >> 4);
219 	dt->hour     =  10 * (number[3] & 0x0f) + (number[3] >> 4);
220 	dt->minute   =  10 * (number[4] & 0x0f) + (number[4] >> 4);
221 	dt->second   =  10 * (number[5] & 0x0f) + (number[5] >> 4);
222 
223 	/* The timezone is given in quarters. The base is GMT */
224 	dt->timezone = (10 * (number[6] & 0x07) + (number[6] >> 4)) / 4;
225 	/* The GSM spec is not clear what is the sign of the timezone when the
226 	 * 6th bit is set. Some SMSCs are compatible with our interpretation,
227 	 * some are not. If your operator does use incompatible SMSC and wrong
228 	 * sign disturbs you, change the sign here.
229 	 */
230 	if (number[6] & 0x08)
231 		dt->timezone = -dt->timezone;
232 
233 	return dt;
234 }
235 
236 /**
237  * sms_timestamp_pack - converts gnokii's datetime struct to the binary datetime
238  * @dt: datetime structure to be read
239  * @number: binary variable to be filled
240  *
241  */
sms_timestamp_pack(gn_timestamp * dt,unsigned char * number)242 unsigned char *sms_timestamp_pack(gn_timestamp *dt, unsigned char *number)
243 {
244 	if (!number)
245 		return NULL;
246 	memset(number, 0, GN_SMS_DATETIME_MAX_LENGTH);
247 	if (!dt)
248 		return number;
249 
250 	/* Ugly hack, but according to the GSM specs, the year is stored
251 	 * as the 2 digit number. */
252 	if (dt->year < 2000)
253 		dt->year -= 1900;
254 	else
255 		dt->year -= 2000;
256 
257 	number[0]    = (dt->year   / 10) | ((dt->year   % 10) << 4);
258 	number[1]    = (dt->month  / 10) | ((dt->month  % 10) << 4);
259 	number[2]    = (dt->day    / 10) | ((dt->day    % 10) << 4);
260 	number[3]    = (dt->hour   / 10) | ((dt->hour   % 10) << 4);
261 	number[4]    = (dt->minute / 10) | ((dt->minute % 10) << 4);
262 	number[5]    = (dt->second / 10) | ((dt->second % 10) << 4);
263 
264 	/* The timezone is given in quarters. The base is GMT */
265 	number[6]    = (dt->timezone / 10) | ((dt->second % 10) << 4) * 4;
266 	/* The GSM spec is not clear what is the sign of the timezone when the
267 	 * 6th bit is set. Some SMSCs are compatible with our interpretation,
268 	 * some are not. If your operator does use incompatible SMSC and wrong
269 	 * sign disturbs you, change the sign here.
270 	 */
271 	if (dt->timezone < 0)
272 		number[6] |= 0x08;
273 
274 	return number;
275 }
276 
277 /***
278  *** DECODING SMS
279  ***/
280 
281 /**
282  * sms_status - decodes the error code contained in the delivery report.
283  * @status: error code to decode
284  * @sms: SMS struct to store the result
285  *
286  * This function checks for the error (or success) code contained in the
287  * received SMS - delivery report and fills in the SMS structure with
288  * the correct message according to the GSM specification.
289  * This function only applies to the delivery reports. Delivery reports
290  * contain only one part, so it is assumed all other parts except 0th are
291  * NULL.
292  */
sms_status(unsigned char status,gn_sms * sms)293 static gn_error sms_status(unsigned char status, gn_sms *sms)
294 {
295 	sms->user_data[0].type = GN_SMS_DATA_Text;
296 	sms->user_data[1].type = GN_SMS_DATA_None;
297 	if (status < 0x03) {
298 		sms->user_data[0].dr_status = GN_SMS_DR_Status_Delivered;
299 		snprintf(sms->user_data[0].u.text, sizeof(sms->user_data[0].u.text), "%s", _("Delivered"));
300 		switch (status) {
301 		case 0x00:
302 			dprintf("SM received by the SME");
303 			break;
304 		case 0x01:
305 			dprintf("SM forwarded by the SC to the SME but the SC is unable to confirm delivery");
306 			break;
307 		case 0x02:
308 			dprintf("SM replaced by the SC");
309 			break;
310 		}
311 	} else if (status & 0x40) {
312 		snprintf(sms->user_data[0].u.text, sizeof(sms->user_data[0].u.text), "%s", _("Failed"));
313 		/* more detailed reason only for debug */
314 		if (status & 0x20) {
315 			dprintf("Temporary error, SC is not making any more transfer attempts\n");
316 			sms->user_data[0].dr_status = GN_SMS_DR_Status_Failed_Permanent;
317 			switch (status) {
318 			case 0x60:
319 				dprintf("Congestion");
320 				break;
321 			case 0x61:
322 				dprintf("SME busy");
323 				break;
324 			case 0x62:
325 				dprintf("No response from SME");
326 				break;
327 			case 0x63:
328 				dprintf("Service rejected");
329 				break;
330 			case 0x64:
331 				dprintf("Quality of service not available");
332 				break;
333 			case 0x65:
334 				dprintf("Error in SME");
335 				break;
336 			default:
337 				dprintf("Reserved/Specific to SC: %x", status);
338 				break;
339 			}
340 		} else {
341 			dprintf("Permanent error, SC is not making any more transfer attempts\n");
342 			sms->user_data[0].dr_status = GN_SMS_DR_Status_Failed_Temporary;
343 			switch (status) {
344 			case 0x40:
345 				dprintf("Remote procedure error");
346 				break;
347 			case 0x41:
348 				dprintf("Incompatibile destination");
349 				break;
350 			case 0x42:
351 				dprintf("Connection rejected by SME");
352 				break;
353 			case 0x43:
354 				dprintf("Not obtainable");
355 				break;
356 			case 0x44:
357 				dprintf("Quality of service not available");
358 				break;
359 			case 0x45:
360 				dprintf("No internetworking available");
361 				break;
362 			case 0x46:
363 				dprintf("SM Validity Period Expired");
364 				break;
365 			case 0x47:
366 				dprintf("SM deleted by originating SME");
367 				break;
368 			case 0x48:
369 				dprintf("SM Deleted by SC Administration");
370 				break;
371 			case 0x49:
372 				dprintf("SM does not exist");
373 				break;
374 			default:
375 				dprintf("Reserved/Specific to SC: 0x%02x", status);
376 				break;
377 			}
378 		}
379 	} else if (status & 0x20) {
380 		sms->user_data[0].dr_status = GN_SMS_DR_Status_Pending;
381 		snprintf(sms->user_data[0].u.text, sizeof(sms->user_data[0].u.text), "%s", _("Pending"));
382 		/* more detailed reason only for debug */
383 		dprintf("Temporary error, SC still trying to transfer SM\n");
384 		switch (status) {
385 		case 0x20:
386 			dprintf("Congestion");
387 			break;
388 		case 0x21:
389 			dprintf("SME busy");
390 			break;
391 		case 0x22:
392 			dprintf("No response from SME");
393 			break;
394 		case 0x23:
395 			dprintf("Service rejected");
396 			break;
397 		case 0x24:
398 			dprintf("Quality of service not available");
399 			break;
400 		case 0x25:
401 			dprintf("Error in SME");
402 			break;
403 		default:
404 			dprintf("Reserved/Specific to SC: 0x%02x", status);
405 			break;
406 		}
407 	} else {
408 		sms->user_data[0].dr_status = GN_SMS_DR_Status_Invalid;
409 		snprintf(sms->user_data[0].u.text, sizeof(sms->user_data[0].u.text), "%s", _("Unknown"));
410 
411 		/* more detailed reason only for debug */
412 		dprintf("Reserved/Specific to SC: 0x%02x", status);
413 	}
414 	dprintf("\n");
415 	sms->user_data[0].length = strlen(sms->user_data[0].u.text);
416 	return GN_ERR_NONE;
417 }
418 
419 /**
420  * sms_data_decode - decodes encoded text from the SMS.
421  * @message: encoded text
422  * @output: room for the encoded text
423  * @length: decoded text length
424  * @size: encoded text length
425  * @udhlen: udh length
426  * @dcs: data coding scheme
427  *
428  * This function decodes either 7bit or 8bit or Unicode text to the
429  * readable text format according to the locale set.
430  */
sms_data_decode(unsigned char * message,unsigned char * output,unsigned int length,unsigned int size,unsigned int udhlen,gn_sms_dcs dcs)431 static gn_error sms_data_decode(unsigned char *message, unsigned char *output, unsigned int length,
432 				 unsigned int size, unsigned int udhlen, gn_sms_dcs dcs)
433 {
434 	/* Unicode */
435 	if (dcs.type & 0x20) {
436 		dprintf("Compressed message\n");
437 		return GN_ERR_NOTIMPLEMENTED;
438 	}
439 	if ((dcs.type & 0x08) == 0x08) {
440 		dprintf("Unicode message\n");
441 		/*
442 		 * length is rawsms->length which is number of characters in
443 		 * the decoded text. 3rd argument of char_unicode_decode is
444 		 * number of bytes.
445 		 */
446 		char_unicode_decode(output, message, 2 * length);
447 	} else {
448 		/* 8bit SMS */
449 		if ((dcs.type & 0xf4) == 0xf4) {
450 			dprintf("8bit message\n");
451 			memcpy(output, message + udhlen, length);
452 		/* 7bit SMS */
453 		} else {
454 			char *aux;
455 
456 			dprintf("Default Alphabet\n");
457 			length = length - (udhlen * 8 + ((7-(udhlen%7))%7)) / 7;
458 			aux = calloc(length + 1, 1);
459 			char_7bit_unpack((7-udhlen)%7, size, length, message, aux);
460 			char_default_alphabet_decode(output, aux, length);
461 			free(aux);
462 		}
463 	}
464 	dprintf("%s\n", output);
465 	return GN_ERR_NONE;
466 }
467 
468 /**
469  * sms_udh_decode - interprets the User Data Header contents
470  * @message: received UDH
471  * @sms: SMS structure to fill in
472  *
473  * At this stage we already need to know that SMS has UDH.
474  * This function decodes UDH as described in:
475  *   - GSM 03.40 version 6.1.0 Release 1997, section 9.2.3.24
476  *   - Smart Messaging Specification, Revision 1.0.0, September 15, 1997
477  */
sms_udh_decode(unsigned char * message,gn_sms_udh * udh)478 static gn_error sms_udh_decode(unsigned char *message, gn_sms_udh *udh)
479 {
480 	unsigned char length, pos, nr;
481 
482 	udh->length = length = message[0];
483 	pos = 1;
484 	nr = 0;
485 	while (length > 1) {
486 		unsigned char udh_length;
487 
488 		udh_length = message[pos+1];
489 		switch (message[pos]) {
490 		case 0x00: /* Concatenated short messages */
491 			dprintf("Concatenated messages\n");
492 			udh->udh[nr].type = GN_SMS_UDH_ConcatenatedMessages;
493 			udh->udh[nr].u.concatenated_short_message.reference_number = message[pos + 2];
494 			udh->udh[nr].u.concatenated_short_message.maximum_number   = message[pos + 3];
495 			udh->udh[nr].u.concatenated_short_message.current_number   = message[pos + 4];
496 			break;
497 		case 0x08: /* Concatenated short messages, 16-bit reference number */
498 			dprintf("Concatenated messages, 16-bit reference number\n");
499 			udh->udh[nr].type = GN_SMS_UDH_ConcatenatedMessages;
500 			udh->udh[nr].u.concatenated_short_message.reference_number = 256 * message[pos + 2] + message[pos + 3];
501 			udh->udh[nr].u.concatenated_short_message.maximum_number   = message[pos + 4];
502 			udh->udh[nr].u.concatenated_short_message.current_number   = message[pos + 5];
503 			break;
504 		case 0x01: /* Special SMS Message Indication */
505 			switch (message[pos + 2] & 0x03) {
506 			case 0x00:
507 				dprintf("Voice Message\n");
508 				udh->udh[nr].type = GN_SMS_UDH_VoiceMessage;
509 				break;
510 			case 0x01:
511 				dprintf("Fax Message\n");
512 				udh->udh[nr].type = GN_SMS_UDH_FaxMessage;
513 				break;
514 			case 0x02:
515 				dprintf("Email Message\n");
516 				udh->udh[nr].type = GN_SMS_UDH_EmailMessage;
517 				break;
518 			default:
519 				dprintf("Unknown\n");
520 				udh->udh[nr].type = GN_SMS_UDH_Unknown;
521 				break;
522 			}
523 			udh->udh[nr].u.special_sms_message_indication.store = (message[pos + 2] & 0x80) >> 7;
524 			udh->udh[nr].u.special_sms_message_indication.message_count = message[pos + 3];
525 			break;
526 		case 0x05: /* Application port addressing scheme, 16 bit address */
527 			switch (((0x00ff & message[pos + 2]) << 8) | (0x00ff & message[pos + 3])) {
528 			case 0x1581:
529 				dprintf("Ringtone\n");
530 				udh->udh[nr].type = GN_SMS_UDH_Ringtone;
531 				break;
532 			case 0x1582:
533 				dprintf("Operator Logo\n");
534 				udh->udh[nr].type = GN_SMS_UDH_OpLogo;
535 				break;
536 			case 0x1583:
537 				dprintf("Caller Icon\n");
538 				udh->udh[nr].type = GN_SMS_UDH_CallerIDLogo;
539 				break;
540 			case 0x158a:
541 				dprintf("Multipart Message\n");
542 				udh->udh[nr].type = GN_SMS_UDH_MultipartMessage;
543 				break;
544 			case 0x23f4:
545 				dprintf("WAP vCard\n");
546 				udh->udh[nr].type = GN_SMS_UDH_WAPvCard;
547 				break;
548 			case 0x23f5:
549 				dprintf("WAP vCalendar\n");
550 				udh->udh[nr].type = GN_SMS_UDH_WAPvCalendar;
551 				break;
552 			case 0x23f6:
553 				dprintf("WAP vCardSecure\n");
554 				udh->udh[nr].type = GN_SMS_UDH_WAPvCardSecure;
555 				break;
556 			case 0x23f7:
557 				dprintf("WAP vCalendarSecure\n");
558 				udh->udh[nr].type = GN_SMS_UDH_WAPvCalendarSecure;
559 				break;
560 			case 0x0b84:
561 				dprintf("WAP Push\n");
562 				udh->udh[nr].type = GN_SMS_UDH_WAPPush;
563 				break;
564 			default:
565 				dprintf("Unknown\n");
566 				udh->udh[nr].type = GN_SMS_UDH_Unknown;
567 				break;
568 			}
569 			break;
570 		case 0x04: /* Application port addressing scheme, 8 bit address */
571 		case 0x06: /* SMSC Control Parameters */
572 		case 0x07: /* UDH Source Indicator */
573 		default:
574 			udh->udh[nr].type = GN_SMS_UDH_Unknown;
575 			dprintf("User Data Header type 0x%02x isn't supported\n", message[pos]);
576 			break;
577 		}
578 		length -= (udh_length + 2);
579 		pos += (udh_length + 2);
580 		nr++;
581 	}
582 	udh->number = nr;
583 
584 	/* We need to add the length field itself */
585 	udh->length++;
586 
587 	return GN_ERR_NONE;
588 }
589 
590 /**
591  * sms_header_decode - Decodes PDU SMS header
592  * @rawsms:
593  * @sms:
594  * @udh:
595  *
596  * This function parses received SMS header information and stores
597  * them in higher level SMS struct. It also checks for the UDH and when
598  * it's found calls the function to extract the UDH.
599  */
sms_header_decode(gn_sms_raw * rawsms,gn_sms * sms,gn_sms_udh * udh)600 static gn_error sms_header_decode(gn_sms_raw *rawsms, gn_sms *sms, gn_sms_udh *udh)
601 {
602 	switch (sms->type = rawsms->type) {
603 	case GN_SMS_MT_Deliver:
604 		dprintf("Mobile Terminated message:\n");
605 		break;
606 	case GN_SMS_MT_DeliveryReport:
607 		dprintf("Delivery Report:\n");
608 		break;
609 	case GN_SMS_MT_Submit:
610 		dprintf("Mobile Originated (stored) message:\n");
611 		break;
612 	case GN_SMS_MT_StatusReport:
613 		dprintf("Status Report message:\n");
614 		break;
615 	case GN_SMS_MT_Picture:
616 		dprintf("Picture Message:\n");
617 		break;
618 	case GN_SMS_MT_TextTemplate:
619 		dprintf("Text Template:\n");
620 		break;
621 	case GN_SMS_MT_PictureTemplate:
622 		dprintf("Picture Template:\n");
623 		break;
624 	case GN_SMS_MT_SubmitSent:
625 		dprintf("Mobile Originated (sent) message:\n");
626 		break;
627 	default:
628 		dprintf("SMS message type 0x%02x isn't supported\n", sms->type);
629 		return GN_ERR_NOTSUPPORTED;
630 	}
631 
632 	/* Sending date */
633 	sms_timestamp_unpack(rawsms->smsc_time, &(sms->smsc_time));
634 	dprintf("\tDate: %s\n", sms_timestamp_print(rawsms->smsc_time));
635 
636 	/* Remote number */
637 	rawsms->remote_number[0] = (rawsms->remote_number[0] + 1) / 2 + 1;
638 	snprintf(sms->remote.number, sizeof(sms->remote.number), "%s", char_bcd_number_get(rawsms->remote_number));
639 	dprintf("\tRemote number (recipient or sender): %s\n", sms->remote.number);
640 
641 	/* Short Message Center */
642 	snprintf(sms->smsc.number, sizeof(sms->smsc.number), "%s", char_bcd_number_get(rawsms->message_center));
643 	dprintf("\tSMS center number: %s\n", sms->smsc.number);
644 
645 	/* Delivery time */
646 	if (sms->type == GN_SMS_MT_StatusReport) {
647 		sms_timestamp_unpack(rawsms->time, &(sms->time));
648 		dprintf("\tDelivery date: %s\n", sms_timestamp_print(rawsms->time));
649 	}
650 
651 	/* Data Coding Scheme */
652 	sms->dcs.type = rawsms->dcs;
653 
654 	/* User Data Header */
655 	if (rawsms->udh_indicator & 0x40) { /* UDH header available */
656 		dprintf("UDH found\n");
657 		return sms_udh_decode(rawsms->user_data, udh);
658 	}
659 
660 	return GN_ERR_NONE;
661 }
662 
663 /**
664  * sms_pdu_decode - This function decodes the PDU SMS
665  * @rawsms - SMS read by the phone driver
666  * @sms - place to store the decoded message
667  *
668  * This function decodes SMS as described in GSM 03.40 version 6.1.0
669  * Release 1997, section 9
670  */
sms_pdu_decode(gn_sms_raw * rawsms,gn_sms * sms)671 static gn_error sms_pdu_decode(gn_sms_raw *rawsms, gn_sms *sms)
672 {
673 	unsigned int size = 0;
674 	gn_error error;
675 
676 	error = sms_header_decode(rawsms, sms, &sms->udh);
677 	ERROR();
678 	sms->user_data[0].dr_status = GN_SMS_DR_Status_None;
679 	switch (sms->type) {
680 	case GN_SMS_MT_DeliveryReport:
681 	case GN_SMS_MT_StatusReport:
682 		sms_status(rawsms->report_status, sms);
683 		break;
684 	case GN_SMS_MT_PictureTemplate:
685 	case GN_SMS_MT_Picture:
686 		/* This is incredible. Nokia violates it's own format in 6210 */
687 		/* Indicate that it is Multipart Message. Remove it if not needed */
688 		/* [I believe Nokia said in their manuals that any order is permitted --pavel] */
689 		sms->udh.number = 1;
690 		sms->udh.udh[0].type = GN_SMS_UDH_MultipartMessage;
691 		if ((rawsms->user_data[0] == 0x48) && (rawsms->user_data[1] == 0x1c)) {
692 
693 			dprintf("First picture then text!\n");
694 
695 			/* First part is a Picture */
696 			sms->user_data[0].type = GN_SMS_DATA_Bitmap;
697 			gn_bmp_sms_read(GN_BMP_PictureMessage, rawsms->user_data,
698 					NULL, &sms->user_data[0].u.bitmap);
699 #ifdef DEBUG
700 			gn_bmp_print(&sms->user_data[0].u.bitmap, stderr);
701 #endif
702 			size = rawsms->user_data_length - 4 - sms->user_data[0].u.bitmap.size;
703 			/* Second part is a text */
704 			sms->user_data[1].type = GN_SMS_DATA_NokiaText;
705 			sms_data_decode(rawsms->user_data + 5 + sms->user_data[0].u.bitmap.size,
706 					(unsigned char *)&(sms->user_data[1].u.text),
707 					rawsms->length - sms->user_data[0].u.bitmap.size - 4,
708 					size, 0, sms->dcs);
709 		} else {
710 
711 			dprintf("First text then picture!\n");
712 
713 			/* First part is a text */
714 			sms->user_data[1].type = GN_SMS_DATA_NokiaText;
715 			sms_data_decode(rawsms->user_data + 3,
716 					(unsigned char *)&(sms->user_data[1].u.text),
717 					rawsms->user_data[1], rawsms->user_data[0], 0, sms->dcs);
718 
719 			/* Second part is a Picture */
720 			sms->user_data[0].type = GN_SMS_DATA_Bitmap;
721 			gn_bmp_sms_read(GN_BMP_PictureMessage,
722 					rawsms->user_data + rawsms->user_data[0] + 7,
723 					NULL, &sms->user_data[0].u.bitmap);
724 #ifdef DEBUG
725 			gn_bmp_print(&sms->user_data[0].u.bitmap, stderr);
726 #endif
727 		}
728 		break;
729 	/* Plain text message */
730 	default:
731 		return sms_data_decode(rawsms->user_data + sms->udh.length, /* Skip the UDH */
732 				(unsigned char *)&sms->user_data[0].u.text, /* With a plain text message we have only 1 part */
733 				rawsms->length,                             /* Length of the decoded text */
734 				rawsms->user_data_length,                   /* Length of the encoded text (in full octets) without UDH */
735 				sms->udh.length,                            /* To skip the certain number of bits when unpacking 7bit message */
736 				sms->dcs);
737 		break;
738 	}
739 
740 	return GN_ERR_NONE;
741 }
742 
743 /**
744  * gn_sms_parse - High-level function for the SMS parsing
745  * @data: GSM data from the phone driver
746  *
747  * This function parses the SMS message from the lowlevel raw_sms to
748  * the highlevel SMS. In data->raw_sms there's SMS read by the phone
749  * driver, data->sms is the place for the parsed SMS.
750  */
gn_sms_parse(gn_data * data)751 gn_error gn_sms_parse(gn_data *data)
752 {
753 	if (!data->raw_sms || !data->sms) return GN_ERR_INTERNALERROR;
754 	/* Let's assume at the moment that all messages are PDU coded */
755 	return sms_pdu_decode(data->raw_sms, data->sms);
756 }
757 
758 /**
759  * gn_sms_pdu2raw - Copy PDU data into gn_sms_raw structure
760  * @rawsms: gn_sms_raw structure to be filled
761  * @pdu: buffer containing PDU data
762  * @pdu_len: length of buffer containing PDU data
763  * @flags: GN_SMS_PDU_* flags to control copying
764  *
765  * This function fills a gn_sms_raw structure copying raw values from
766  * a buffer containing PDU data.
767  */
gn_sms_pdu2raw(gn_sms_raw * rawsms,unsigned char * pdu,int pdu_len,int flags)768 gn_error gn_sms_pdu2raw(gn_sms_raw *rawsms, unsigned char *pdu, int pdu_len, int flags)
769 {
770 #define COPY_REMOTE_NUMBER(pdu, offset) { \
771 	l = (pdu[offset] % 2) ? pdu[offset] + 1 : pdu[offset]; \
772 	l = l / 2 + 2; \
773 	if (l + offset + extraoffset > pdu_len || l > GN_SMS_NUMBER_MAX_LENGTH) { \
774 		dprintf("Invalid remote number length (%d)\n", l); \
775 		ret = GN_ERR_INTERNALERROR; \
776 		goto out; \
777 	} \
778 	memcpy(rawsms->remote_number, pdu + offset, l); \
779 	offset += l; \
780 }
781 
782 #define COPY_USER_DATA(pdu, offset) { \
783 	rawsms->length = pdu[offset++]; \
784 	rawsms->user_data_length = rawsms->length; \
785 	if (rawsms->length > 0) { \
786 		if (rawsms->udh_indicator) \
787 			rawsms->user_data_length -= pdu[offset] + 1; \
788 		if (pdu_len - offset > GN_SMS_USER_DATA_MAX_LENGTH) { \
789 			dprintf("Phone gave as poisonous (too short?) reply, either phone went crazy or communication went out of sync\n"); \
790 			ret = GN_ERR_INTERNALERROR; \
791 			goto out; \
792 		} \
793 		memcpy(rawsms->user_data, pdu + offset, pdu_len - offset); \
794 	} \
795 }
796 
797 	gn_error ret = GN_ERR_NONE;
798 	unsigned int l, extraoffset, offset = 0;
799 	int parameter_indicator;
800 
801 	if (!flags & GN_SMS_PDU_NOSMSC) {
802 		l = pdu[offset] + 1;
803 		if (l > pdu_len || l > GN_SMS_SMSC_NUMBER_MAX_LENGTH) {
804 			dprintf("Invalid message center length (%d)\n", l);
805 			ret = GN_ERR_INTERNALERROR;
806 			goto out;
807 		}
808 		memcpy(rawsms->message_center, pdu, l);
809 		offset += l;
810 	}
811 
812 	rawsms->reject_duplicates   = 0;
813 	rawsms->report_status       = 0;
814 	rawsms->reference           = 0;
815 	rawsms->reply_via_same_smsc = 0;
816 	rawsms->report              = 0;
817 
818 	/* NOTE: offsets are taken from subclause 9.2.3 "Definition of the TPDU parameters"
819 	   of 3GPP TS 23.040 version 7.0.1 Release 7 == ETSI TS 123 040 V7.0.1 (2007-03)
820 	   *not* from the tables in subclause 9.2.2 "PDU Type repertoire at SM-TL" which ignore unused bits
821 	*/
822 
823 	/* NOTE: this function handles only short messages received by the phone.
824 	   Since the same TP-MTI value is used both for SC->MS and for MS->SC,
825 	   it can't simply shift to get the enum value: (pdu[offset] & 0x03) << 1
826 	*/
827 
828 	/* TP-MTI TP-Message-Type-Indicator 9.2.3.1 */
829 	switch (pdu[offset] & 0x03) {
830 	case 0x00:
831 		rawsms->type = GN_SMS_MT_Deliver;
832 		break;
833 	case 0x01:
834 		rawsms->type = GN_SMS_MT_Submit;
835 		break;
836 	case 0x02:
837 		rawsms->type = GN_SMS_MT_StatusReport;
838 		break;
839 	case 0x03:
840 		dprintf("Reserved TP-MTI found\n");
841 		return GN_ERR_INTERNALERROR;
842 	}
843 	switch (rawsms->type) {
844 	case GN_SMS_MT_Deliver:
845 		dprintf("SMS-DELIVER found\n");
846 		/* TP-MMS  TP-More-Messages-to-Send */
847 		rawsms->more_messages       = pdu[offset] & 0x04;
848 		/* Bits 3 and 4 of the first octet are unused */
849 		/* TP-SRI  TP-Status-Report-Indication */
850 		rawsms->report_status       = pdu[offset] & 0x20;
851 		/* TP-UDHI TP-User-Data-Header-Indication */
852 		rawsms->udh_indicator       = pdu[offset] & 0x40;
853 		/* TP-RP   TP-Reply-Path */
854 		rawsms->reply_via_same_smsc = pdu[offset] & 0x80;
855 		offset++;
856 		/* TP-OA   TP-Originating-Address */
857 		extraoffset = 10;
858 		COPY_REMOTE_NUMBER(pdu, offset);
859 		/* TP-PID  TP-Protocol-Identifier */
860 		rawsms->pid = pdu[offset++];
861 		/* TP-DCS  TP-Data-Coding-Scheme */
862 		rawsms->dcs = pdu[offset++];
863 		/* TP-SCTS TP-Service-Centre-Time-Stamp */
864 		memcpy(rawsms->smsc_time, pdu + offset, 7);
865 		offset += 7;
866 		/* TP-UDL  TP-User-Data-Length */
867 		/* TP-UD   TP-User-Data */
868 		COPY_USER_DATA(pdu, offset);
869 		break;
870 	case GN_SMS_MT_Submit:
871 		dprintf("SMS-SUBMIT found\n");
872 		/* TP-RD   TP-Reject-Duplicates */
873 		rawsms->reject_duplicates   = pdu[offset] & 0x04;
874 		/* TP-VPF  TP-Validity-Period-Format */
875 		rawsms->validity_indicator  = (pdu[offset] & 0x18) >> 3;
876 		/* TP-SRR  TP-Status-Report-Request */
877 		rawsms->report              = pdu[offset] & 0x20;
878 		/* TP-UDHI TP-User-Data-Header-Indication */
879 		rawsms->udh_indicator       = pdu[offset] & 0x40;
880 		/* TP-RP   TP-Reply-Path */
881 		rawsms->reply_via_same_smsc = pdu[offset] & 0x80;
882 		offset++;
883 		/* TP-MR   TP-Message-Reference */
884 		rawsms->reference           = pdu[offset++];
885 		/* TP-DA   TP-Destination-Address */
886 		extraoffset = 3;
887 		COPY_REMOTE_NUMBER(pdu, offset);
888 		/* TP-PID  TP-Protocol-Identifier */
889 		rawsms->pid = pdu[offset++];
890 		/* TP-DCS  TP-Data-Coding-Scheme */
891 		rawsms->dcs = pdu[offset++];
892 		/* TP-VP   TP-Validity-Period */
893 		switch (rawsms->validity_indicator) {
894 		case GN_SMS_VP_None:
895 			/* nothing to convert */
896 			break;
897 		case GN_SMS_VP_RelativeFormat:
898 			rawsms->validity[0] = pdu[offset++];
899 			break;
900 		case GN_SMS_VP_EnhancedFormat:
901 			/* FALL THROUGH */
902 		case GN_SMS_VP_AbsoluteFormat:
903 			memcpy(rawsms->validity, pdu + offset, 7);
904 			offset += 7;
905 			break;
906 		default:
907 			dprintf("Unknown validity_indicator 0x%02x\n", rawsms->validity_indicator);
908 			return GN_ERR_INTERNALERROR;
909 		}
910 		/* TP-UDL  TP-User-Data-Length */
911 		/* TP-UD   TP-User-Data */
912 		COPY_USER_DATA(pdu, offset);
913 		break;
914 	case GN_SMS_MT_StatusReport:
915 		dprintf("SMS-STATUS-REPORT found\n");
916 		/* TP-MMS  TP-More-Messages-to-Send */
917 		rawsms->more_messages       = pdu[offset] & 0x04;
918 		/* TP-SRQ  TP-Status-Report-Qualifier */
919 		rawsms->report              = pdu[offset] & 0x10;
920 		/* TP-UDHI TP-User-Data-Header-Indication */
921 		rawsms->udh_indicator       = pdu[offset] & 0x40;
922 		offset++;
923 		/* TP-MR   TP-Message-Reference */
924 		rawsms->reference           = pdu[offset++];
925 		/* TP-RA   TP-Recipient-Address */
926 		extraoffset = 0;
927 		COPY_REMOTE_NUMBER(pdu, offset);
928 		/* TP-SCTS TP-Service-Centre-Time-Stamp */
929 		memcpy(rawsms->smsc_time, pdu + offset, 7);
930 		offset += 7;
931 		/* TP-DT   TP-Discharge-Time */
932 		memcpy(rawsms->time, pdu + offset, 7);
933 		offset += 7;
934 		/* TP-ST   TP-Status */
935 		rawsms->report_status       = pdu[offset++];
936 		/* TP-PI   TP-Parameter-Indicator */
937 		parameter_indicator         = pdu[offset];
938 		/* handle the "extension bit" skipping the following octects, if any (see 9.2.3.27 TP-Parameter-Indicator):
939 		 *   The most significant bit in octet 1 and any other TP-PI octets which may be added later is reserved as an extension bit
940 		 *   which when set to a 1 shall indicate that another TP-PI octet follows immediately afterwards.
941 		 */
942 		while ((offset < pdu_len) && (pdu[offset++] & 0x80))
943 			;
944 		if ((offset < pdu_len) && (parameter_indicator & 0x01)) {
945 			/* TP-PID  TP-Protocol-Identifier */
946 			rawsms->pid = pdu[offset++];
947 		}
948 		if ((offset < pdu_len) && (parameter_indicator & 0x02)) {
949 			/* TP-DCS  TP-Data-Coding-Scheme */
950 			rawsms->dcs = pdu[offset++];
951 		}
952 		if ((offset < pdu_len) && (parameter_indicator & 0x04)) {
953 			/* TP-UDL  TP-User-Data-Length */
954 			/* TP-UD   TP-User-Data */
955 			COPY_USER_DATA(pdu, offset);
956 		}
957 		break;
958 	case GN_SMS_MT_Command:
959 #if 0
960 		dprintf("SMS-COMMAND found\n");
961 		/* TP-Message-Type-Indicator */
962 		/** decoded above **/
963 		offset = 5;
964 		/* TP-User-Data-Header-Indication */
965 		rawsms->udh_indicator       = pdu[offset] & 0x40;
966 		/* TP-Status-Report-Request */
967 		rawsms->report_status       = pdu[offset] & 0x08;
968 		offset++;
969 		/* TP-Message Reference */
970 		rawsms->reference           = pdu[offset++];
971 		/* TP-Protocol-Identifier */
972 		rawsms->pid                 = pdu[offset++];
973 		/* TP-Command-Type */
974 		dprintf("TP-Command-Type 0x%02x\n", pdu[offset++]);
975 		/* TP-Message-Number */
976 		dprintf("TP-Message-Number 0x%02x\n", pdu[offset++]);
977 		/* TP-Destination-Address */
978 	l = (pdu[offset] % 2) ? pdu[offset] + 1 : pdu[offset];
979 	l = l / 2 + 2;
980 	memcpy(rawsms->remote_number, pdu + offset, l);
981 	offset += l;
982 		/* TP-Command-Data-Length */
983 		dprintf("TP-Command-Data-Length 0x%02x\n", pdu[offset++]);
984 		/* TP-Command-Data */
985 		dprintf("TP-Command-Data 0x%02x ...\n", pdu[offset++]);
986 		goto out;
987 		break;
988 #endif
989 		/* FALL THROUGH */
990 	default:
991 		dprintf("Unknown PDU type %d\n", rawsms->type);
992 		return GN_ERR_INTERNALERROR;
993 	}
994 
995 	/*
996 	 * Unicode message has length in octets. We need length in characters: see comment in sms_pdu_decode().
997 	 */
998 	if ((rawsms->dcs & 0x08) == 0x08)
999 		rawsms->length /= 2;
1000 out:
1001 	return ret;
1002 #undef COPY_USER_DATA
1003 #undef COPY_REMOTE_NUMBER
1004 }
1005 
1006 /**
1007  * gn_sms_request - High-level function for the explicit SMS reading from the phone
1008  * @data: GSM data for the phone driver
1009  * @state: current statemachine state
1010  *
1011  * This is the function for explicit requesting the SMS from the
1012  * phone driver. Note that raw_sms field in the gn_data structure must
1013  * be initialized
1014  */
gn_sms_request(gn_data * data,struct gn_statemachine * state)1015 gn_error gn_sms_request(gn_data *data, struct gn_statemachine *state)
1016 {
1017 	if (!data->raw_sms) return GN_ERR_INTERNALERROR;
1018 	return gn_sm_functions(GN_OP_GetSMS, data, state);
1019 }
1020 
1021 /**
1022  * gn_sms_get- High-level function for reading SMS
1023  * @data: GSM data for the phone driver
1024  * @state: current statemachine state
1025  *
1026  * This function is the frontend for reading SMS. Note that SMS field
1027  * in the gn_data structure must be initialized.
1028  */
gn_sms_get(gn_data * data,struct gn_statemachine * state)1029 GNOKII_API gn_error gn_sms_get(gn_data *data, struct gn_statemachine *state)
1030 {
1031 	gn_error error;
1032 	gn_sms_raw rawsms;
1033 
1034 	if (!data->sms)
1035 		return GN_ERR_INTERNALERROR;
1036 	if (data->sms->number < 0)
1037 		return GN_ERR_EMPTYLOCATION;
1038 	if (data->sms->memory_type > GN_MT_LAST)
1039 		return GN_ERR_INVALIDMEMORYTYPE;
1040 	memset(&rawsms, 0, sizeof(gn_sms_raw));
1041 	rawsms.number = data->sms->number;
1042 	rawsms.memory_type = data->sms->memory_type;
1043 	data->raw_sms = &rawsms;
1044 	error = gn_sms_request(data, state);
1045 	ERROR();
1046 	data->sms->status = rawsms.status;
1047 	return gn_sms_parse(data);
1048 }
1049 
1050 /**
1051  * gn_sms_delete - High-level function for deleting SMS
1052  * @data: GSM data for the phone driver
1053  * @state: current statemachine state
1054  *
1055  * This function is the frontend for deleting SMS. Note that SMS field
1056  * in the gn_data structure must be initialized.
1057  */
gn_sms_delete(gn_data * data,struct gn_statemachine * state)1058 GNOKII_API gn_error gn_sms_delete(gn_data *data, struct gn_statemachine *state)
1059 {
1060 	gn_sms_raw rawsms;
1061 
1062 	if (!data->sms) return GN_ERR_INTERNALERROR;
1063 	memset(&rawsms, 0, sizeof(gn_sms_raw));
1064 	rawsms.number = data->sms->number;
1065 	rawsms.memory_type = data->sms->memory_type;
1066 	data->raw_sms = &rawsms;
1067 	return gn_sm_functions(GN_OP_DeleteSMS, data, state);
1068 }
1069 
1070 /***
1071  *** OTHER FUNCTIONS
1072  ***/
1073 
sms_request_no_validate(gn_data * data,struct gn_statemachine * state)1074 static gn_error sms_request_no_validate(gn_data *data, struct gn_statemachine *state)
1075 {
1076 	return gn_sm_functions(GN_OP_GetSMSnoValidate, data, state);
1077 }
1078 
gn_sms_get_no_validate(gn_data * data,struct gn_statemachine * state)1079 GNOKII_API gn_error gn_sms_get_no_validate(gn_data *data, struct gn_statemachine *state)
1080 {
1081 	gn_error error;
1082 	gn_sms_raw rawsms;
1083 
1084 	if (!data->sms) return GN_ERR_INTERNALERROR;
1085 	memset(&rawsms, 0, sizeof(gn_sms_raw));
1086 	rawsms.number = data->sms->number;
1087 	rawsms.memory_type = data->sms->memory_type;
1088 	data->raw_sms = &rawsms;
1089 	error = sms_request_no_validate(data, state);
1090 	ERROR();
1091 	data->sms->status = rawsms.status;
1092 	return gn_sms_parse(data);
1093 }
1094 
gn_sms_delete_no_validate(gn_data * data,struct gn_statemachine * state)1095 GNOKII_API gn_error gn_sms_delete_no_validate(gn_data *data, struct gn_statemachine *state)
1096 {
1097 	gn_sms_raw rawsms;
1098 
1099 	if (!data->sms) return GN_ERR_INTERNALERROR;
1100 	memset(&rawsms, 0, sizeof(gn_sms_raw));
1101 	rawsms.number = data->sms->number;
1102 	rawsms.memory_type = data->sms->memory_type;
1103 	data->raw_sms = &rawsms;
1104 	return gn_sm_functions(GN_OP_DeleteSMSnoValidate, data, state);
1105 }
1106 
sms_free_deleted(gn_data * data,int folder)1107 static gn_error sms_free_deleted(gn_data *data, int folder)
1108 {
1109 	int i, j;
1110 
1111 	if (!data->sms_status) return GN_ERR_INTERNALERROR;
1112 
1113 	for (i = 0; i < data->folder_stats[folder]->used; i++) {		/* for all previously found locations */
1114 		if (data->message_list[i][folder]->status == GN_SMS_FLD_ToBeRemoved) {	/* previously deleted and read message */
1115 			dprintf("Found deleted message, which will now be freed! %i , %i\n",
1116 					i, data->message_list[i][folder]->location);
1117 			for (j = i; j < data->folder_stats[folder]->used; j++) {
1118 				memcpy(data->message_list[j][folder], data->message_list[j + 1][folder],
1119 						sizeof(gn_sms_message_list));
1120 			}
1121 			data->folder_stats[folder]->used--;
1122 			i--;
1123 		}
1124 	}
1125 	return GN_ERR_NONE;
1126 }
1127 
sms_get_read(gn_data * data)1128 static gn_error sms_get_read(gn_data *data)
1129 {
1130 	int i, j, found;
1131 
1132 	if (!data->message_list || !data->folder_stats || !data->sms_folder) return GN_ERR_INTERNALERROR;
1133 
1134 	for (i = 0; i < data->sms_folder->number; i++) {		/* cycle through all messages in phone */
1135 		found = 0;
1136 		for (j = 0; j < data->folder_stats[data->sms_folder->folder_id]->used; j++) {		/* and compare them to those alread in list */
1137 			if (data->sms_folder->locations[i] == data->message_list[j][data->sms_folder->folder_id]->location) found = 1;
1138 		}
1139 		if (data->folder_stats[data->sms_folder->folder_id]->used >= GN_SMS_MESSAGE_MAX_NUMBER) {
1140 			dprintf("Max messages number in folder exceeded (%d)\n", GN_SMS_MESSAGE_MAX_NUMBER);
1141 			return GN_ERR_MEMORYFULL;
1142 		}
1143 		if (!found) {
1144 			dprintf("Found new (read) message. Will store it at #%i!\n", data->folder_stats[data->sms_folder->folder_id]->used);
1145 			dprintf("%i\n", data->sms_folder->locations[i]);
1146 			data->message_list[data->folder_stats[data->sms_folder->folder_id]->used][data->sms_folder->folder_id]->location =
1147 				data->sms_folder->locations[i];
1148 			data->message_list[data->folder_stats[data->sms_folder->folder_id]->used][data->sms_folder->folder_id]->status = GN_SMS_FLD_New;
1149 			data->folder_stats[data->sms_folder->folder_id]->used++;
1150 			data->folder_stats[data->sms_folder->folder_id]->changed++;
1151 			data->sms_status->changed++;
1152 		}
1153 	}
1154 	return GN_ERR_NONE;
1155 }
1156 
sms_get_deleted(gn_data * data)1157 static gn_error sms_get_deleted(gn_data *data)
1158 {
1159 	int i, j, found = 0;
1160 
1161 	for (i = 0; i < data->folder_stats[data->sms_folder->folder_id]->used; i++) {		/* for all previously found locations in folder */
1162 		found = 0;
1163 
1164 		for (j = 0; j < data->sms_folder->number; j++) {	/* see if there is a corresponding message in phone */
1165 			if (data->message_list[i][data->sms_folder->folder_id]->location == data->sms_folder->locations[j]) found = 1;
1166 		}
1167 		if ((found == 0) && (data->message_list[i][data->sms_folder->folder_id]->status == GN_SMS_FLD_Old)) {	/* we have found a deleted message */
1168 			dprintf("found a deleted message!!!! i: %i, loc: %i, MT: %i \n",
1169 					i, data->message_list[i][data->sms_folder->folder_id]->location, data->sms_folder->folder_id);
1170 
1171 			data->message_list[i][data->sms_folder->folder_id]->status = GN_SMS_FLD_Deleted;
1172 			data->sms_status->changed++;
1173 			data->folder_stats[data->sms_folder->folder_id]->changed++;
1174 		}
1175 	}
1176 	return GN_ERR_NONE;
1177 }
1178 
sms_verify_status(gn_data * data)1179 static gn_error sms_verify_status(gn_data *data)
1180 {
1181 	int i, j;
1182 
1183 	for (i = 0; i < data->folder_stats[data->sms_folder->folder_id]->used; i++) {		/* Cycle through all messages we know of */
1184 		if ((data->message_list[i][data->sms_folder->folder_id]->status == GN_SMS_FLD_NotRead) ||	/* if it is a unread one, i.e. not in folderstatus */
1185 				(data->message_list[i][data->sms_folder->folder_id]->status == GN_SMS_FLD_NotReadHandled)) {
1186 			for (j = 0; j < data->sms_folder->number; j++) {
1187 				if (data->message_list[i][data->sms_folder->folder_id]->location == data->sms_folder->locations[j]) {
1188 					/* We have found a formerly unread message which has been read in the meantime */
1189 					dprintf("Found a formerly unread message which has been read in the meantime: loc: %i\n",
1190 							data->message_list[i][data->sms_folder->folder_id]->location);
1191 					data->message_list[i][data->sms_folder->folder_id]->status = GN_SMS_FLD_Changed;
1192 					data->sms_status->changed++;
1193 					data->folder_stats[data->sms_folder->folder_id]->changed++;
1194 				}
1195 			}
1196 		}
1197 	}
1198 	return GN_ERR_NONE;
1199 }
1200 
1201 
gn_sms_get_folder_changes(gn_data * data,struct gn_statemachine * state,int has_folders)1202 GNOKII_API gn_error gn_sms_get_folder_changes(gn_data *data, struct gn_statemachine *state, int has_folders)
1203 {
1204 	gn_error error;
1205 	gn_sms_folder  sms_folder;
1206 	gn_sms_folder_list sms_folder_list;
1207 	int i, previous_unread, previous_total;
1208 
1209 	previous_total = data->sms_status->number;
1210 	previous_unread = data->sms_status->unread;
1211 	dprintf("GetFolderChanges: Old status: %d %d\n", data->sms_status->number, data->sms_status->unread);
1212 
1213 	error = gn_sm_functions(GN_OP_GetSMSStatus, data, state);	/* Check overall SMS Status */
1214 	ERROR();
1215 	dprintf("GetFolderChanges: Status: %d %d\n", data->sms_status->number, data->sms_status->unread);
1216 
1217 	if (!has_folders) {
1218 		if ((previous_total == data->sms_status->number) && (previous_unread == data->sms_status->unread))
1219 			data->sms_status->changed = 0;
1220 		else
1221 			data->sms_status->changed = 1;
1222 		return GN_ERR_NONE;
1223 	}
1224 
1225 	data->sms_folder_list = &sms_folder_list;
1226 	error = gn_sm_functions(GN_OP_GetSMSFolders, data, state);
1227 	ERROR();
1228 
1229 	data->sms_status->folders_count = data->sms_folder_list->number;
1230 
1231 	for (i = 0; i < data->sms_status->folders_count; i++) {
1232 		dprintf("GetFolderChanges: Freeing deleted messages for folder #%i\n", i);
1233 		error = sms_free_deleted(data, i);
1234 		ERROR();
1235 
1236 		data->sms_folder = &sms_folder;
1237 		data->sms_folder->folder_id = (gn_memory_type) i + 12;
1238 		dprintf("GetFolderChanges: Getting folder status for folder #%i\n", i);
1239 		error = gn_sm_functions(GN_OP_GetSMSFolderStatus, data, state);
1240 		ERROR();
1241 
1242 		data->sms_folder->folder_id = i;	/* so we don't need to do a modulo 8 each time */
1243 
1244 		dprintf("GetFolderChanges: Reading read messages (%i) for folder #%i\n", data->sms_folder->number, i);
1245 		error = sms_get_read(data);
1246 		ERROR();
1247 
1248 		dprintf("GetFolderChanges: Getting deleted messages for folder #%i\n", i);
1249 		error = sms_get_deleted(data);
1250 		ERROR();
1251 
1252 		dprintf("GetFolderChanges: Verifying messages for folder #%i\n", i);
1253 		error = sms_verify_status(data);
1254 		ERROR();
1255 	}
1256 	return GN_ERR_NONE;
1257 }
1258 
1259 /***
1260  *** ENCODING SMS
1261  ***/
1262 
1263 
1264 /**
1265  * sms_udh_encode - encodes User Data Header
1266  * @sms: SMS structure with the data source
1267  * @type:
1268  *
1269  * returns pointer to data it added;
1270  *
1271  * This function encodes the UserDataHeader as described in:
1272  *  o GSM 03.40 version 6.1.0 Release 1997, section 9.2.3.24
1273  *  o Smart Messaging Specification, Revision 1.0.0, September 15, 1997
1274  *  o Smart Messaging Specification, Revision 3.0.0
1275  */
sms_udh_encode(gn_sms_raw * rawsms,int type)1276 static char *sms_udh_encode(gn_sms_raw *rawsms, int type)
1277 {
1278 	unsigned char pos;
1279 	char *udh = rawsms->user_data;
1280 	char *res = NULL;
1281 
1282 	pos = udh[0];
1283 
1284 	switch (type) {
1285 	case GN_SMS_UDH_None:
1286 		break;
1287 	case GN_SMS_UDH_VoiceMessage:
1288 	case GN_SMS_UDH_FaxMessage:
1289 	case GN_SMS_UDH_EmailMessage:
1290 		return NULL;
1291 #if 0
1292 		udh[pos+4] = udhi.u.SpecialSMSMessageIndication.MessageCount;
1293 		if (udhi.u.SpecialSMSMessageIndication.Store) udh[pos+3] |= 0x80;
1294 #endif
1295 	case GN_SMS_UDH_ConcatenatedMessages:
1296 		dprintf("Adding ConcatMsg header\n");
1297 	case GN_SMS_UDH_OpLogo:
1298 	case GN_SMS_UDH_CallerIDLogo:
1299 	case GN_SMS_UDH_Ringtone:
1300 	case GN_SMS_UDH_MultipartMessage:
1301 	case GN_SMS_UDH_WAPPush:
1302 		udh[0] += headers[type].length;
1303 		res = udh+pos+1;
1304 		memcpy(res, headers[type].header, headers[type].length);
1305 		rawsms->user_data_length += headers[type].length;
1306 		rawsms->length += headers[type].length;
1307 		break;
1308 	default:
1309 		dprintf("User Data Header type 0x%02x isn't supported\n", type);
1310 		break;
1311 	}
1312 	if (!rawsms->udh_indicator) {
1313 		rawsms->udh_indicator = 1;
1314 		rawsms->length++;		/* Length takes one byte, too */
1315 		rawsms->user_data_length++;
1316 	}
1317 	return res;
1318 }
1319 
1320 /**
1321  * sms_concat_header_encode - Adds concatenated messages header
1322  * @rawsms: processed SMS
1323  * @curr: current part number
1324  * @total: total parts number
1325  *
1326  * This function adds sequent part of the concatenated messages header. Note
1327  * that this header should be the first of all headers.
1328  */
sms_concat_header_encode(gn_sms_raw * rawsms,int curr,int total)1329 static gn_error sms_concat_header_encode(gn_sms_raw *rawsms, int curr, int total)
1330 {
1331 	char *header = sms_udh_encode(rawsms, GN_SMS_UDH_ConcatenatedMessages);
1332 	if (!header) return GN_ERR_NOTSUPPORTED;
1333 	header[2] = 0xce;		/* Message serial number. Is 0xce value somehow special? -- pkot */
1334 	header[3] = total;
1335 	header[4] = curr;
1336 	return GN_ERR_NONE;
1337 }
1338 
1339 /**
1340  * sms_data_encode - Encodes the data from the SMS structure to the phone frame
1341  *
1342  * @sms: #gn_sms structure holding user provided data
1343  * @rawsms: #gn_sms_raw structure to be filled with encoded data
1344  *
1345  * This function converts values from libgnokii format to a format more similar
1346  * to the GSM standard.
1347  * This function is capable of creating only one frame at a time.
1348  */
sms_data_encode(gn_sms * sms,gn_sms_raw * rawsms)1349 static gn_error sms_data_encode(gn_sms *sms, gn_sms_raw *rawsms)
1350 {
1351 	gn_sms_dcs_alphabet_type al = GN_SMS_DCS_DefaultAlphabet;
1352 	unsigned int i, size = 0;
1353 	gn_error error;
1354 
1355 	/* Additional Headers */
1356 	switch (sms->dcs.type) {
1357 	case GN_SMS_DCS_GeneralDataCoding:
1358 		dprintf("General Data Coding\n");
1359 		switch (sms->dcs.u.general.m_class) {
1360 		case 0: break;
1361 		case 1: rawsms->dcs |= 0xf0; break; /* Class 0 */
1362 		case 2: rawsms->dcs |= 0xf1; break; /* Class 1 */
1363 		case 3: rawsms->dcs |= 0xf2; break; /* Class 2 */
1364 		case 4: rawsms->dcs |= 0xf3; break; /* Class 3 */
1365 		default: dprintf("General Data Coding class 0x%02x isn't supported\n", sms->dcs.u.general.m_class); break;
1366 		}
1367 		if (sms->dcs.u.general.compressed) {
1368 			/* Compression not supported yet */
1369 			dprintf("SMS message compression isn't supported\n");
1370 			/* dcs[0] |= 0x20; */
1371 		}
1372 		al = sms->dcs.u.general.alphabet;
1373 		break;
1374 	case GN_SMS_DCS_MessageWaiting:
1375 		al = sms->dcs.u.message_waiting.alphabet;
1376 		if (sms->dcs.u.message_waiting.discard) rawsms->dcs |= 0xc0;
1377 		else if (sms->dcs.u.message_waiting.alphabet == GN_SMS_DCS_UCS2) rawsms->dcs |= 0xe0;
1378 		else rawsms->dcs |= 0xd0;
1379 
1380 		if (sms->dcs.u.message_waiting.active) rawsms->dcs |= 0x08;
1381 		rawsms->dcs |= (sms->dcs.u.message_waiting.type & 0x03);
1382 
1383 		break;
1384 	default:
1385 		dprintf("Data Coding Scheme type 0x%02x isn't supported\n", sms->dcs.type);
1386 		return GN_ERR_WRONGDATAFORMAT;
1387 	}
1388 
1389 	for (i = 0; i < GN_SMS_PART_MAX_NUMBER; i++) {
1390 		switch (sms->user_data[i].type) {
1391 		case GN_SMS_DATA_Bitmap:
1392 			switch (sms->user_data[i].u.bitmap.type) {
1393 			case GN_BMP_PictureMessage:
1394 				size = sms_nokia_bitmap_encode(&(sms->user_data[i].u.bitmap),
1395 							       rawsms->user_data + rawsms->user_data_length,
1396 							       (i == 0));
1397 				break;
1398 			case GN_BMP_OperatorLogo:
1399 				if (!sms_udh_encode(rawsms, GN_SMS_UDH_OpLogo)) return GN_ERR_NOTSUPPORTED;
1400 				size = gn_bmp_sms_encode(&(sms->user_data[i].u.bitmap),
1401 							 rawsms->user_data + rawsms->user_data_length);
1402 				break;
1403 			case GN_BMP_CallerLogo:
1404 				if (!sms_udh_encode(rawsms, GN_SMS_UDH_CallerIDLogo)) return GN_ERR_NOTSUPPORTED;
1405 				size = gn_bmp_sms_encode(&(sms->user_data[i].u.bitmap),
1406 							 rawsms->user_data + rawsms->user_data_length);
1407 				break;
1408 			default:
1409 				size = gn_bmp_sms_encode(&(sms->user_data[i].u.bitmap),
1410 							 rawsms->user_data + rawsms->user_data_length);
1411 				break;
1412 			}
1413 			rawsms->length += size;
1414 			rawsms->user_data_length += size;
1415 			rawsms->dcs = 0xf5;
1416 			rawsms->udh_indicator = 1;
1417 			break;
1418 
1419 		case GN_SMS_DATA_Animation: {
1420 			int j;
1421 
1422 			for (j = 0; j < 4; j++) {
1423 				size = gn_bmp_sms_encode(&(sms->user_data[i].u.animation[j]), rawsms->user_data + rawsms->user_data_length);
1424 				rawsms->length += size;
1425 				rawsms->user_data_length += size;
1426 			}
1427 			rawsms->dcs = 0xf5;
1428 			rawsms->udh_indicator = 1;
1429 			break;
1430 		}
1431 
1432 		case GN_SMS_DATA_Text: {
1433 			unsigned int length, udh_length, offset = rawsms->user_data_length;
1434 
1435 			length = sms->user_data[i].length;
1436 			if (sms->udh.length)
1437 				udh_length = sms->udh.length + 1;
1438 			else
1439 				udh_length = 0;
1440 			switch (al) {
1441 			case GN_SMS_DCS_DefaultAlphabet:
1442 				dprintf("Default Alphabet\n");
1443 				size = char_7bit_pack((7 - (udh_length % 7)) % 7,
1444 						      sms->user_data[i].u.text,
1445 						      rawsms->user_data + offset,
1446 						      &length);
1447 				rawsms->length = length + (udh_length * 8 + 6) / 7;
1448 				rawsms->user_data_length = size + offset;
1449 				dprintf("\tsize: %d\n\toffset: %d\n", size, offset);
1450 				dprintf("\tencoded size: %d\n\trawsms length: %d\n\trawsms user data length: %d\n", size, rawsms->length, rawsms->user_data_length);
1451 				break;
1452 			case GN_SMS_DCS_8bit:
1453 				dprintf("8bit\n");
1454 				rawsms->dcs |= 0xf4;
1455 				memcpy(rawsms->user_data + offset, sms->user_data[i].u.text, sms->user_data[i].u.text[0]);
1456 				rawsms->user_data_length = rawsms->length = length + udh_length;
1457 				break;
1458 			case GN_SMS_DCS_UCS2:
1459 				dprintf("UCS-2\n");
1460 				rawsms->dcs |= 0x08;
1461 				length = ucs2_encode(rawsms->user_data + offset, GN_SMS_LONG_MAX_LENGTH, sms->user_data[i].u.text, length);
1462 				if (length < 0) {
1463 					dprintf("Failed to encode UCS2 message\n");
1464 					return GN_ERR_WRONGDATAFORMAT;
1465 				}
1466 				rawsms->user_data_length = rawsms->length = length + udh_length;
1467 				break;
1468 			default:
1469 				return GN_ERR_WRONGDATAFORMAT;
1470 			}
1471 			break;
1472 		}
1473 
1474 		case GN_SMS_DATA_NokiaText:
1475 			size = sms_nokia_text_encode(sms->user_data[i].u.text,
1476 						     rawsms->user_data + rawsms->user_data_length,
1477 						     (i == 0));
1478 			rawsms->length += size;
1479 			rawsms->user_data_length += size;
1480 			break;
1481 
1482 		case GN_SMS_DATA_iMelody:
1483 			size = imelody_sms_encode(sms->user_data[i].u.text, rawsms->user_data + rawsms->user_data_length);
1484 			dprintf("Imelody, size %d\n", size);
1485 			rawsms->length += size;
1486 			rawsms->user_data_length += size;
1487 			rawsms->dcs = 0xf5;
1488 			rawsms->udh_indicator = 1;
1489 			break;
1490 
1491 		case GN_SMS_DATA_Multi:
1492 			size = sms->user_data[0].length;
1493 			if (!sms_udh_encode(rawsms, GN_SMS_UDH_MultipartMessage)) return GN_ERR_NOTSUPPORTED;
1494 			error = sms_concat_header_encode(rawsms, sms->user_data[i].u.multi.curr, sms->user_data[i].u.multi.total);
1495 			ERROR();
1496 			memcpy(rawsms->user_data + rawsms->user_data_length, sms->user_data[i].u.multi.binary, MAX_SMS_PART - 6);
1497 			rawsms->length += size;
1498 			rawsms->user_data_length += size;
1499 			rawsms->dcs = 0xf5;
1500 			break;
1501 
1502 		case GN_SMS_DATA_Ringtone:
1503 			if (!sms_udh_encode(rawsms, GN_SMS_UDH_Ringtone)) return GN_ERR_NOTSUPPORTED;
1504 			size = ringtone_sms_encode(rawsms->user_data + rawsms->length, &sms->user_data[i].u.ringtone);
1505 			rawsms->length += size;
1506 			rawsms->user_data_length += size;
1507 			rawsms->dcs = 0xf5;
1508 			break;
1509 
1510 		case GN_SMS_DATA_WAPPush:
1511 			if (!sms_udh_encode(rawsms, GN_SMS_UDH_WAPPush)) return GN_ERR_NOTSUPPORTED;
1512 			size = sms->user_data[i].length;
1513 			memcpy(rawsms->user_data + rawsms->user_data_length, sms->user_data[i].u.text, size );
1514 			rawsms->length += size;
1515 			rawsms->user_data_length += size;
1516 			rawsms->dcs = 0xf5;
1517 			break;
1518 
1519 		case GN_SMS_DATA_Concat:
1520 			al = GN_SMS_DCS_8bit;
1521 			rawsms->dcs = 0xf5;
1522 			sms_concat_header_encode(rawsms, sms->user_data[i].u.concat.curr, sms->user_data[i].u.concat.total);
1523 			break;
1524 
1525 		case GN_SMS_DATA_None:
1526 			return GN_ERR_NONE;
1527 
1528 		default:
1529 			dprintf("User Data type 0x%02x isn't supported\n", sms->user_data[i].type);
1530 			break;
1531 		}
1532 	}
1533 	return GN_ERR_NONE;
1534 }
1535 
sms_prepare(gn_sms * sms,gn_sms_raw * rawsms)1536 gn_error sms_prepare(gn_sms *sms, gn_sms_raw *rawsms)
1537 {
1538 	int i;
1539 
1540 	switch (rawsms->type = sms->type) {
1541 	case GN_SMS_MT_Submit:
1542 	case GN_SMS_MT_Deliver:
1543 	case GN_SMS_MT_Picture:
1544 		break;
1545 	case GN_SMS_MT_DeliveryReport:
1546 	default:
1547 		dprintf("Raw SMS message type 0x%02x isn't supported\n", rawsms->type);
1548 		return GN_ERR_NOTSUPPORTED;
1549 	}
1550 	/* Encoding the header */
1551 	rawsms->report = sms->delivery_report;
1552 	rawsms->remote_number[0] = char_semi_octet_pack(sms->remote.number, rawsms->remote_number + 1, sms->remote.type);
1553 	if (rawsms->remote_number[0] > GN_SMS_NUMBER_MAX_LENGTH) {
1554 		dprintf("Remote number length %d > %d\n", rawsms->remote_number[0], GN_SMS_NUMBER_MAX_LENGTH);
1555 		return GN_ERR_ENTRYTOOLONG;
1556 	}
1557 	rawsms->validity_indicator = GN_SMS_VP_RelativeFormat;
1558 	rawsms->validity[0] = GN_SMS_VP_72H;
1559 
1560 	for (i = 0; i < sms->udh.number; i++)
1561 		if (sms->udh.udh[i].type == GN_SMS_UDH_ConcatenatedMessages)
1562 			sms_concat_header_encode(rawsms, sms->udh.udh[i].u.concatenated_short_message.current_number,
1563 						sms->udh.udh[i].u.concatenated_short_message.maximum_number);
1564 
1565 	return sms_data_encode(sms, rawsms);
1566 }
1567 
sms_dump_raw(gn_sms_raw * rawsms)1568 static void sms_dump_raw(gn_sms_raw *rawsms)
1569 {
1570 #ifdef DEBUG
1571 	char buf[10240];
1572 
1573 	memset(buf, 0, 10240);
1574 
1575 	dprintf("dcs: 0x%02x\n", rawsms->dcs);
1576 	dprintf("Length: 0x%02x\n", rawsms->length);
1577 	dprintf("user_data_length: 0x%02x\n", rawsms->user_data_length);
1578 	dprintf("ValidityIndicator: %d\n", rawsms->validity_indicator);
1579 	bin2hex(buf, rawsms->user_data, rawsms->user_data_length);
1580 	dprintf("user_data: %s\n", buf);
1581 #endif
1582 }
1583 
1584 
gn_sms_udh_add(gn_sms * sms,gn_sms_udh_type type)1585 GNOKII_API int gn_sms_udh_add(gn_sms *sms, gn_sms_udh_type type)
1586 {
1587 	sms->udh.length += headers[type].length;
1588 	sms->udh.udh[sms->udh.number].type = type;
1589 	sms->udh.number++;
1590 	return sms->udh.number - 1;
1591 }
1592 
1593 static gn_error sms_send_single(gn_data *data, struct gn_statemachine *state);
1594 static gn_error sms_send_long(gn_data *data, struct gn_statemachine *state, int octets);
1595 
1596 /**
1597  * gn_sms_send - The main function for the SMS sending
1598  * @data: GSM data for the phone driver
1599  * @state: current statemachine state
1600  *
1601  * The high level function to send SMS. You need to fill in data->sms
1602  * (gn_sms) in the higher level. This is converted to raw_sms here,
1603  * and then phone driver takes the fields it needs and sends it in the
1604  * phone specific way to the phone.
1605  *
1606  * In case of multipart message, sending is interrupted on the first
1607  * failure.  It means that if message got split into 3 messages, and 2nd
1608  * part fails to send, the 3rd part is not attepted to get sent.  There is
1609  * no interface to retry multipart message from the failed part.
1610  *
1611  * data->sms->parts indicates how many parts were (or supposed to be) sent.
1612  *
1613  * data->sms->reference contains data->sms->parts reference numbers from the
1614  * sent messages.  They might be used to relate the delivery reports.  If
1615  * given element has reference 0, sending this part, falied.
1616  */
gn_sms_send(gn_data * data,struct gn_statemachine * state)1617 GNOKII_API gn_error gn_sms_send(gn_data *data, struct gn_statemachine *state)
1618 {
1619 	int i, total;
1620 	int enc_chars, ext_chars;
1621 	gn_error retval;
1622 	gn_sms sms;
1623 	gn_sms *orig_sms;
1624 
1625 	dprintf("=====> ENTER gn_sms_send()\n");
1626 	/*
1627 	 * Make sure that we will not get any corruption if it was not
1628 	 * initialized properly by the app.  Issue a warning that
1629 	 * application may leak the memory
1630 	 */
1631 	if (data->sms->reference) {
1632 		dprintf("data->sms->reference was not set to NULL. The app may not initialize it\nproperly or leak memory.\n");
1633 		data->sms->reference = NULL;
1634 	}
1635 
1636 	/*
1637 	 * We need to work on data->sms->user_data; let's have a copy of the
1638 	 * original request so message could be resubmitted.
1639 	 * FIXME: use for that only additional user_data structure
1640 	 */
1641 	orig_sms = data->sms;
1642 	memcpy(&sms, data->sms, sizeof(gn_sms));
1643 	data->sms = &sms;
1644 
1645 	/* Convert all the input strings to UTF-8 */
1646 	if (data->sms->dcs.u.general.alphabet != GN_SMS_DCS_8bit) {
1647 		i = 0;
1648 		data->sms->dcs.u.general.alphabet = GN_SMS_DCS_DefaultAlphabet;
1649 		while (data->sms->user_data[i].type != GN_SMS_DATA_None) {
1650 			gchar *str;
1651 			gsize inlen, outlen;
1652 			gn_sms_dcs_alphabet_type enc;
1653 
1654 			if (data->sms->user_data[i].type == GN_SMS_DATA_Text ||
1655 			    data->sms->user_data[i].type == GN_SMS_DATA_NokiaText) {
1656 			       	str = g_locale_to_utf8(data->sms->user_data[i].u.text, -1, &inlen, &outlen, NULL);
1657 			       	data->sms->user_data[i].chars = g_utf8_strlen(str, outlen);
1658 			       	memset(data->sms->user_data[i].u.text, 0, sizeof(data->sms->user_data[i].u.text));
1659 			       	g_utf8_strncpy(data->sms->user_data[i].u.text, str, data->sms->user_data[i].chars);
1660 			       	g_free(str);
1661 				/* Let's make sure the encoding is correct */
1662 				enc = char_def_alphabet_string_stats(data->sms->user_data[i].u.text, &enc_chars, &ext_chars);
1663 				if (enc == GN_SMS_DCS_UCS2)
1664 					data->sms->dcs.u.general.alphabet = enc;
1665 				data->sms->user_data[i].chars = enc_chars;
1666 			} else {
1667 				/* FIXME: that's wrong for Nokia Multipart Picture Message, does anybody still use it? */
1668 				data->sms->dcs.u.general.alphabet = GN_SMS_DCS_8bit;
1669 			}
1670 			i++;
1671 		}
1672 	}
1673 
1674 	dprintf("enc_chars: %d\next_chars: %d\n", enc_chars, ext_chars);
1675 	/* Count the total length of the message text octets to be sent */
1676 	total = 0;
1677 	i = 0;
1678 	while (data->sms->user_data[i].type != GN_SMS_DATA_None) {
1679 		switch (data->sms->dcs.u.general.alphabet) {
1680 		case GN_SMS_DCS_DefaultAlphabet:
1681 			/*
1682 			 * Extended alphabet chars are doubled on the input.
1683 			 */
1684 			total += ((enc_chars + ext_chars) * 7 + 7) / 8;
1685 			break;
1686 		case GN_SMS_DCS_UCS2:
1687 			total += (enc_chars * 2);
1688 			break;
1689 		default:
1690 			total += data->sms->user_data[i].length;
1691 			break;
1692 		}
1693 		i++;
1694 	}
1695 
1696 	dprintf("total: %d\n", total);
1697 
1698 	/* FIXME: from now on we handle only the user_data[0] */
1699 	dprintf("size of the input string: %d bytes\n", data->sms->user_data[0].length);
1700 	dprintf("number of characters in the input string: %d chars\n", data->sms->user_data[0].chars);
1701 
1702 	/* It will eventually get overwritten in sms_send_long() */
1703 	data->sms->parts = 1;
1704 
1705 	if (total > MAX_SMS_PART)
1706 		retval = sms_send_long(data, state, total);
1707 	else
1708 		retval = sms_send_single(data, state);
1709 
1710 	data->sms = orig_sms;
1711 	/* Let's put back information about sent messages */
1712 	data->sms->reference = sms.reference;
1713 	data->sms->parts = sms.parts;
1714 
1715 	return retval;
1716 }
1717 
sms_send_single(gn_data * data,struct gn_statemachine * state)1718 static gn_error sms_send_single(gn_data *data, struct gn_statemachine *state)
1719 {
1720 	int i = 0;
1721 	gn_error error = GN_ERR_NONE;
1722 	gn_sms_raw rawsms;
1723 
1724 	data->raw_sms = &rawsms;
1725 	memset(&rawsms, 0, sizeof(rawsms));
1726 
1727 	if (!data->sms)
1728 		return GN_ERR_INTERNALERROR;
1729 
1730 	if (data->sms->remote.number[0] == 0) {
1731 		dprintf("Recipient number cannot be NULL.\n");
1732 		return GN_ERR_WRONGDATAFORMAT;
1733 	}
1734 
1735 	dprintf("=====> ENTER sms_send_single()\n");
1736 	data->raw_sms->status = GN_SMS_Sent;
1737 
1738 	data->raw_sms->message_center[0] = char_semi_octet_pack(data->sms->smsc.number, data->raw_sms->message_center + 1, data->sms->smsc.type);
1739 	if (data->raw_sms->message_center[0] % 2)
1740 		data->raw_sms->message_center[0]++;
1741 	if (data->raw_sms->message_center[0])
1742 		data->raw_sms->message_center[0] = data->raw_sms->message_center[0] / 2 + 1;
1743 
1744 	error = sms_prepare(data->sms, data->raw_sms);
1745 	if (error != GN_ERR_NONE)
1746 		return error;
1747 
1748 	sms_dump_raw(data->raw_sms);
1749 	dprintf("Input is %d bytes long\n", data->sms->user_data[0].length);
1750 	dprintf("SMS is %d octets long\n", data->raw_sms->user_data_length);
1751 
1752 	dprintf("Sending\n");
1753 	error = gn_sm_functions(GN_OP_SendSMS, data, state);
1754 
1755 	/* If there was an error, let's not put the reference into data->sms */
1756 	if (error == GN_ERR_NONE) {
1757 		/* In case of multipart message it is already allocated */
1758 		if (!data->sms->reference)
1759 			data->sms->reference = calloc(data->sms->parts, sizeof(unsigned int));
1760 
1761 		/* We send SMS parts from the first part to last. */
1762 		i = 0;
1763 		while (i < data->sms->parts-1 && data->sms->reference[i] != 0)
1764 			i++;
1765 		data->sms->reference[i] = data->raw_sms->reference;
1766 	}
1767 
1768 	return error;
1769 }
1770 
1771 /*
1772  * FIXME: we stop sending multipart message on first error. We may end up
1773  * with few messages send, and few failed.  We're not able to resend only
1774  * failed ones.
1775  */
sms_send_long(gn_data * data,struct gn_statemachine * state,int octets)1776 static gn_error sms_send_long(gn_data *data, struct gn_statemachine *state, int octets)
1777 {
1778 	int i, j, k, count, size, start, copied, refnum, is_concat = -1, max_sms_len = MAX_SMS_PART;
1779 	gn_sms_user_data ud[GN_SMS_PART_MAX_NUMBER];
1780 	gn_error error = GN_ERR_NONE;
1781 	time_t t;
1782 
1783 	start = 0;
1784 	copied = 0;
1785 	count = data->sms->parts;
1786 
1787 	dprintf("=====> ENTER sms_send_long()\n");
1788 
1789 	dprintf("count: %d\n", count);
1790 
1791 	/* If there's no concat header we need to add one */
1792 	for (i = 0; i < data->sms->number; i++) {
1793 		if (data->sms->udh.udh[i].type == GN_SMS_UDH_ConcatenatedMessages)
1794 			is_concat = i;
1795 	}
1796 	if (is_concat == -1)
1797 		is_concat = gn_sms_udh_add(data->sms, GN_SMS_UDH_ConcatenatedMessages);
1798 
1799 	/* We need to attach user data header to each part */
1800 	max_sms_len -= (data->sms->udh.length + 1);
1801 
1802 	/* Count number of SMS to be sent */
1803 	count = (octets + max_sms_len - 1) / max_sms_len;
1804 	dprintf("Will need %d sms-es\n", count);
1805 	dprintf("SMS is %d octects long but we can only send %d octects in a single SMS after adding %d octects for udh\n", octets, max_sms_len, data->sms->udh.length + 1);
1806 
1807 	data->sms->parts = count;
1808 	data->sms->reference = calloc(count, sizeof(unsigned int));
1809 
1810 	/* Generate reference number */
1811 	time(&t);
1812 	srand(t);
1813 	refnum = (int)(255.0*rand()/(RAND_MAX+1.0));
1814 
1815 	/* have a copy of the original data */
1816 	i = 0;
1817 	while (data->sms->user_data[i].type != GN_SMS_DATA_None) {
1818 		memcpy(&ud[i], &data->sms->user_data[i], sizeof(gn_sms_user_data));
1819 		i++;
1820 	}
1821 
1822 	for (i = 0; i < count; i++) {
1823 		dprintf("Sending sms #%d (refnum: %d)\n", i+1, refnum);
1824 		data->sms->udh.udh[is_concat].u.concatenated_short_message.reference_number = refnum;
1825 		data->sms->udh.udh[is_concat].u.concatenated_short_message.maximum_number = count;
1826 		data->sms->udh.udh[is_concat].u.concatenated_short_message.current_number = i+1;
1827 		switch (data->sms->dcs.u.general.alphabet) {
1828 		case GN_SMS_DCS_DefaultAlphabet:
1829 			start += copied;
1830 			memset(&data->sms->user_data[0], 0, sizeof(gn_sms_user_data));
1831 			data->sms->user_data[0].type = ud[0].type;
1832 			dprintf("%d %d %d\n", start, copied, max_sms_len);
1833 			copied = char_def_alphabet_string_copy(data->sms->user_data[0].u.text, ud[0].u.text, max_sms_len * 8 / 7, start);
1834 			dprintf("\tnumber of processed characters: %d\n", copied);
1835 			break;
1836 		case GN_SMS_DCS_UCS2:
1837 			/* We need to copy precisely not to cut character in the middle */
1838 			start += copied;
1839 			memset(&data->sms->user_data[0], 0, sizeof(gn_sms_user_data));
1840 			data->sms->user_data[0].type = ud[0].type;
1841 			/* FIXME: We assume UTF8 input */
1842 			size = 1;
1843 #define C ud[0].u.text[start + j]
1844 			for (j = 0, k = 0; start + j < ud[0].length && k < max_sms_len / 2; j++) {
1845 				size--;
1846 				if (!size) {
1847 					/* Let's detect size of UTF8 char */
1848 					if (C >= 0 && C < 128)
1849 						size = 1;
1850 					else if (C >= 192 && C < 224)
1851 						size = 2;
1852 					else if (C >= 224 && C < 240)
1853 						size = 3;
1854 					else if (C >= 240 && C < 248)
1855 						size = 4;
1856 					else if (C >= 248 && C < 252)
1857 						size = 5;
1858 					else if (C >= 252 && C < 254)
1859 						size = 6;
1860 					else
1861 						/* FIXME: handle it somehow */
1862 						dprintf("CHARACTER ENCODING ERROR\n");
1863 					k++;
1864 				}
1865 				/* Avoid cutting a character */
1866 				if (k < max_sms_len / 2)
1867 					data->sms->user_data[0].u.text[j] = ud[0].u.text[start + j];
1868 				else
1869 					j--;
1870 			}
1871 #undef C
1872 			data->sms->user_data[0].length = copied = j;
1873 			dprintf("DEBUG: copied: %d\n", copied);
1874 			break;
1875 		default:
1876 			start += copied;
1877 			if (ud[0].length - start >= max_sms_len) {
1878 				copied = max_sms_len;
1879 			} else {
1880 				copied = (ud[0].length - start) % (max_sms_len);
1881 			}
1882 			memset(&data->sms->user_data[0], 0, sizeof(gn_sms_user_data));
1883 			data->sms->user_data[0].type = ud[0].type;
1884 			data->sms->user_data[0].length = copied;
1885 			memcpy(data->sms->user_data[0].u.text, ud[0].u.text+start, copied);
1886 			switch (ud[0].type) {
1887 			case GN_SMS_DATA_Bitmap:
1888 				break;
1889 			case GN_SMS_DATA_Ringtone:
1890 				break;
1891 			default:
1892 				break;
1893 			}
1894 			break;
1895 		}
1896 		dprintf("Text to be sent in this part: %s\n", data->sms->user_data[0].u.text);
1897 		error = sms_send_single(data, state);
1898 		ERROR();
1899 	}
1900 	return GN_ERR_NONE;
1901 }
1902 
gn_sms_save(gn_data * data,struct gn_statemachine * state)1903 GNOKII_API gn_error gn_sms_save(gn_data *data, struct gn_statemachine *state)
1904 {
1905 	gn_error error = GN_ERR_NONE;
1906 	gn_sms_raw rawsms;
1907 
1908 	data->raw_sms = &rawsms;
1909 	memset(&rawsms, 0, sizeof(rawsms));
1910 
1911 	data->raw_sms->number = data->sms->number;
1912 	data->raw_sms->status = data->sms->status;
1913 	data->raw_sms->memory_type = data->sms->memory_type;
1914 
1915 	sms_timestamp_pack(&data->sms->smsc_time, data->raw_sms->smsc_time);
1916 	dprintf("\tDate: %s\n", sms_timestamp_print(data->raw_sms->smsc_time));
1917 
1918 	if (data->sms->smsc.number[0] != '\0') {
1919 		data->raw_sms->message_center[0] =
1920 			char_semi_octet_pack(data->sms->smsc.number, data->raw_sms->message_center + 1, data->sms->smsc.type);
1921 		if (data->raw_sms->message_center[0] % 2) data->raw_sms->message_center[0]++;
1922 		if (data->raw_sms->message_center[0])
1923 			data->raw_sms->message_center[0] = data->raw_sms->message_center[0] / 2 + 1;
1924 	}
1925 	error = sms_prepare(data->sms, data->raw_sms);
1926 	ERROR();
1927 
1928 	if (data->raw_sms->length > GN_SMS_MAX_LENGTH) {
1929 		dprintf("SMS is too long? %d\n", data->raw_sms->length);
1930 		goto cleanup;
1931 	}
1932 
1933 	error = gn_sm_functions(GN_OP_SaveSMS, data, state);
1934 
1935 	/* the message was perhaps not stored at the specified location,
1936 	   but the phone driver probably knows where, so copy it over */
1937 	data->sms->number = data->raw_sms->number;
1938 
1939 cleanup:
1940 	data->raw_sms = NULL;
1941 	return error;
1942 }
1943 
1944 /* WAPPush functions */
1945 
encode_attr_inline_string(char token,char * string,int * data_len)1946 char *encode_attr_inline_string(char token, char *string, int *data_len)
1947 {
1948 	char *data = NULL;
1949 
1950 	/* we need 3 extra bytes for tags */
1951 	*data_len = strlen(string) + 3;
1952 	data = malloc(*data_len);
1953 
1954 	if (!data) {
1955 	    return NULL;
1956 	}
1957 
1958 	data[0] = token;
1959 	data[1] = TAG_INLINE;
1960 	memcpy(data + 2, string, strlen(string));
1961 	data[*data_len - 1] = 0x00;
1962 
1963 	return data;
1964 }
1965 
encode_indication(gn_wap_push * wp,int * data_len)1966 char *encode_indication(gn_wap_push *wp, int *data_len)
1967 {
1968 	char *data = NULL;
1969 	char *attr = NULL;
1970 	int attr_len = 0;
1971 	int offset = 0;
1972 
1973 	/* encode tag attribute */
1974 	attr = encode_attr_inline_string(ATTR_HREF, wp->url, &attr_len);
1975 
1976 	if (!attr || !attr_len) {
1977 	    return NULL;
1978 	}
1979 
1980 	/* need 5 extra bytes for indication token & attributes */
1981 	*data_len = attr_len + strlen(wp->text) + 5;
1982 	data = malloc(*data_len);
1983 
1984 	if (!data) {
1985 		free(attr);
1986 		return NULL;
1987 	}
1988 
1989 	/* indication tag token */
1990 	data[offset++] = TOKEN_KNOWN_AC | TAG_INDICATION;
1991 
1992 	/* attribute */
1993 	memcpy(data + offset, attr, attr_len);
1994 	offset += attr_len;
1995 	data[offset++] = TAG_END;
1996 
1997 	/* wappush text */
1998 	data[offset++] = TAG_INLINE;
1999 	memcpy(data + offset, wp->text, strlen(wp->text));
2000 	offset += strlen(wp->text);
2001 	data[offset++] = 0x00;
2002 
2003 	/* tag end */
2004 	data[offset++] = TAG_END;
2005 
2006 	free(attr);
2007 
2008 	return data;
2009 }
2010 
encode_si(gn_wap_push * wp,int * data_len)2011 char *encode_si(gn_wap_push *wp, int *data_len)
2012 {
2013 	char *data = NULL;
2014 	char *child = NULL;
2015 	int child_len = 0;
2016 
2017 	child = encode_indication(wp, &child_len);
2018 
2019 	if (!child || !data_len) {
2020 	    return NULL;
2021 	}
2022 
2023 	/* we need extra 2 bytes for si token */
2024 	*data_len = child_len + 2;
2025 	data = malloc(*data_len);
2026 
2027 	if (!data) {
2028 	    free(child);
2029 	    return NULL;
2030 	}
2031 
2032 	data[0] = TOKEN_KNOWN_C | TAG_SI;
2033 	memcpy(data + 1, child, child_len);
2034 	data[*data_len - 1] = TAG_END;
2035 
2036 	free(child);
2037 
2038 	return data;
2039 }
2040 
gn_wap_push_encode(gn_wap_push * wp)2041 GNOKII_API gn_error gn_wap_push_encode(gn_wap_push *wp)
2042 {
2043 
2044 	char *data = NULL;
2045 	int data_len = 0;
2046 
2047 	data = encode_si(wp, &data_len);
2048 
2049 	if (!data || !data_len) {
2050 	    return GN_ERR_FAILED;
2051 	}
2052 
2053 	wp->data = malloc(data_len + sizeof(gn_wap_push_header));
2054 
2055 	if (!wp->data) {
2056 	    return GN_ERR_FAILED;
2057 	}
2058 
2059 	memcpy(wp->data, &wp->header, sizeof(gn_wap_push_header));
2060 	memcpy(wp->data + sizeof(gn_wap_push_header), data, data_len);
2061 
2062 	wp->data_len = data_len + sizeof(gn_wap_push_header);
2063 
2064 	return GN_ERR_NONE;
2065 }
2066 
gn_wap_push_init(gn_wap_push * wp)2067 GNOKII_API void gn_wap_push_init(gn_wap_push *wp)
2068 {
2069 
2070 	if (!wp) {
2071 	    return;
2072 	}
2073 
2074 	memset(wp, 0, sizeof(gn_wap_push));
2075 
2076 	wp->header.wsp_tid 		= 0x00;
2077 	wp->header.wsp_pdu 		= PDU_TYPE_Push;
2078 	wp->header.wsp_hlen 		= 0x01;
2079 	wp->header.wsp_content_type 	= CONTENT_TYPE;
2080 
2081 	wp->header.version 	= WBXML_VERSION;
2082 	wp->header.public_id 	= TAG_SI;
2083 	wp->header.charset 	= WAPPush_CHARSET;
2084 	wp->header.stl 		= 0x00; /* string table length */
2085 }
2086 
status2str(gn_sms_message_status status)2087 static char *status2str(gn_sms_message_status status)
2088 {
2089 	switch (status) {
2090 	case GN_SMS_Unread:
2091 		return "Unread";
2092 	case GN_SMS_Sent:
2093 		return "Sent";
2094 	case GN_SMS_Unsent:
2095 		return "Unsent";
2096 	default:
2097 		return "Read";
2098 	}
2099 }
2100 
2101 #define MAX_TEXT_SUMMARY	20
2102 #define MAX_SUBJECT_LENGTH	25
2103 #define MAX_DATE_LENGTH		255
2104 
2105 /* From snprintf(3) manual */
allocate(char * fmt,...)2106 static char *allocate(char *fmt, ...)
2107 {
2108 	char *str, *nstr;
2109 	int len, size = 100;
2110 	va_list ap;
2111 
2112 	str = calloc(100, sizeof(char));
2113 	if (!str)
2114 		return NULL;
2115 
2116 	while (1) {
2117 		va_start(ap, fmt);
2118 		len = vsnprintf(str, size, fmt, ap);
2119 		va_end(ap);
2120 		if (len >= size) /* too small buffer */
2121 			size = len + 1;
2122 		else if (len > -1) /* buffer OK */
2123 			return str;
2124 		else /* let's try with larger buffer */
2125 			size *= 2;
2126 		nstr = realloc(str, size);
2127 		if (!nstr) {
2128 			free(str);
2129 			return NULL;
2130 		}
2131 		str = nstr;
2132 	}
2133 }
2134 
2135 /* Here we allocate place for the line to append and we append it.
2136  * We free() the appended line. */
2137 #define APPEND(dst, src, size) \
2138 do { \
2139 	char *ndst; \
2140 	int old = size; \
2141 	size += strlen(src); \
2142 	ndst = realloc(dst, size + 1); \
2143 	if (!ndst) { \
2144 		free(dst); \
2145 		goto error; \
2146 	} \
2147 	dst = ndst; \
2148 	dst[old] = 0; \
2149 	strcat(dst, src); \
2150 	free(src); \
2151 } while (0)
2152 
2153 #define CONCAT(dst, src, size, pattern, ...) \
2154 do { \
2155 	src = allocate(pattern, __VA_ARGS__); \
2156 	if (!src) \
2157 		goto error; \
2158 	APPEND(dst, src, size); \
2159 } while (0);
2160 
2161 /* Returns allocated space for mbox-compatible formatted SMS */
2162 /* TODO:
2163  *   o add encoding information
2164  *   o support non-text SMS (MMS, EMS, delivery report, ...)
2165  */
gn_sms2mbox(gn_sms * sms,char * from)2166 GNOKII_API char *gn_sms2mbox(gn_sms *sms, char *from)
2167 {
2168 	struct tm t, *loctime;
2169 	time_t caltime;
2170 	int size = 0;
2171 	char *tmp;
2172 #ifdef ENABLE_NLS
2173 	char *loc;
2174 #endif
2175 	char *buf = NULL, *aux = NULL;
2176 
2177 	t.tm_sec = sms->smsc_time.second;
2178 	t.tm_min = sms->smsc_time.minute;
2179 	t.tm_hour = sms->smsc_time.hour;
2180 	t.tm_mday = sms->smsc_time.day;
2181 	t.tm_mon = sms->smsc_time.month - 1;
2182 	t.tm_year = sms->smsc_time.year - 1900;
2183 #ifdef HAVE_TM_GMTON
2184 	if (sms->smsc_time.timezone)
2185 		t.tm_gmtoff = sms->smsc_time.timezone * 3600;
2186 #endif
2187 	caltime = mktime(&t);
2188 	loctime = localtime(&caltime);
2189 
2190 #ifdef ENABLE_NLS
2191 	loc = setlocale(LC_ALL, "C");
2192 #endif
2193 	switch (sms->status) {
2194 	case GN_SMS_Sent:
2195 	case GN_SMS_Unsent:
2196 		CONCAT(buf, tmp, size, "From %s@%s %s", "+0", from, asctime(loctime));
2197 		break;
2198 	case GN_SMS_Read:
2199 	case GN_SMS_Unread:
2200 	default:
2201 		CONCAT(buf, tmp, size, "From %s@%s %s", sms->remote.number, from, asctime(loctime));
2202 		break;
2203 	}
2204 
2205 	tmp = calloc(MAX_DATE_LENGTH, sizeof(char));
2206 	if (!tmp)
2207 		goto error;
2208 	strftime(tmp, MAX_DATE_LENGTH - 1, "Date: %a, %d %b %Y %H:%M:%S %z (%Z)\n", loctime);
2209 #ifdef ENABLE_NLS
2210 	setlocale(LC_ALL, loc);
2211 #endif
2212 	APPEND(buf, tmp, size);
2213 
2214 	switch (sms->status) {
2215 	case GN_SMS_Sent:
2216 	case GN_SMS_Unsent:
2217 		CONCAT(buf, tmp, size, "To: %s@%s\n", sms->remote.number, from);
2218 		break;
2219 	case GN_SMS_Read:
2220 	case GN_SMS_Unread:
2221 	default:
2222 		CONCAT(buf, tmp, size, "From: %s@%s\n", sms->remote.number, from);
2223 		break;
2224 	}
2225 
2226 	CONCAT(buf, tmp, size, "X-GSM-SMSC: %s\n", sms->smsc.number);
2227 	CONCAT(buf, tmp, size, "X-GSM-Status: %s\n", status2str(sms->status));
2228 	CONCAT(buf, tmp, size, "X-GSM-Memory: %s\n", gn_memory_type2str(sms->memory_type));
2229 
2230 	aux = calloc(16, sizeof(char)); /* assuming location will never have more than 15 digits */
2231 	if (!aux)
2232 		goto error;
2233 	snprintf(aux, 16, "%d", sms->number);
2234 	CONCAT(buf, tmp, size, "X-GSM-Location: %s\n", aux);
2235 	free(aux);
2236 
2237 	if (strlen(sms->user_data[0].u.text) < MAX_SUBJECT_LENGTH) {
2238 		CONCAT(buf, tmp, size, "Subject: %s\n\n", sms->user_data[0].u.text);
2239 	} else {
2240 		aux = calloc(MAX_TEXT_SUMMARY + 1, sizeof(char));
2241 		if (!aux)
2242 			goto error;
2243 		snprintf(aux, MAX_TEXT_SUMMARY, "%s", sms->user_data[0].u.text);
2244 		CONCAT(buf, tmp, size, "Subject: %s...\n\n", aux);
2245 		free(aux);
2246 	}
2247 
2248 	CONCAT(buf, tmp, size, "%s\n\n", sms->user_data[0].u.text);
2249 
2250 	return buf;
2251 error:
2252 	free(buf);
2253 	free(aux);
2254 	return NULL;
2255 }
2256