Implemented GetPhonebookInfo
[gsmd2.git] / src / sim.c
blob1133f7606f11e503091e0303a31114d11bebc879
1 /*
2 * sim.c
4 * Copyright(C) 2007,2008 Ixonos Plc
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Boston, MA 02111.
22 * Written by
23 * Jukka Honkela
24 * Yi Zheng
25 * Matti Katila
26 * Vesa Pikki
27 * Heikki Paajanen
31 #include "utils.h"
32 #include "sim.h"
33 #include "gsmd-error.h"
34 #include "modem.h"
35 #include <string.h>
36 #include <stdlib.h>
38 static void gsmd_sms_handler_read_free(AtCommandContext *at);
40 static gboolean gsmd_sim_decoder_pdu (guchar* src,SmsParam* pdu);
42 static
43 AtCommandHandlerStatus gsmd_sim_handler_query_pin_status (ModemInterface *modem,
44 AtCommandContext *at,
45 GString *response);
47 static
48 AtCommandHandlerStatus gsmd_sim_handler_query_imsi( ModemInterface *modem,
49 AtCommandContext *at,
50 GString *response);
51 static
52 AtCommandHandlerStatus gsmd_sim_handler_pin(ModemInterface *modem,
53 AtCommandContext *at,
54 GString *response);
55 static
56 AtCommandHandlerStatus gsmd_sim_handler_read (ModemInterface *modem,
57 AtCommandContext *at,
58 GString *response);
59 static
60 AtCommandHandlerStatus gsmd_sim_handler_delete(ModemInterface *modem,
61 AtCommandContext *at,
62 GString *response);
64 static
65 AtCommandHandlerStatus gsmd_sim_handler_query_service_center (ModemInterface *modem,
66 AtCommandContext *at,
67 GString *response);
69 static
70 AtCommandHandlerStatus gsmd_sim_handler_set_service_center (ModemInterface *modem,
71 AtCommandContext *at,
72 GString *response);
74 static
75 AtCommandHandlerStatus gsmd_sim_handler_get_subscriber_numbers (ModemInterface *modem,
76 AtCommandContext *at,
77 GString *response);
79 static
80 AtCommandHandlerStatus gsmd_sim_handler_list_messages (ModemInterface *modem,
81 AtCommandContext *at,
82 GString *response);
84 static
85 AtCommandHandlerStatus gsmd_sim_handler_send_message (ModemInterface *modem,
86 AtCommandContext *at,
87 GString *response);
89 static
90 void gsmd_sim_list_messages_free (AtCommandContext *at);
93 /* static */
94 /* void gsmd_sim_storage_spaces_free(AtCommandContext *at); */
96 /* AtCommandHandlerStatus gsmd_sim_handler_get_storage_spaces( */
97 /* ModemInterface *modem, */
98 /* AtCommandContext *at, */
99 /* GString *response); */
101 AtCommandHandlerStatus gsmd_sim_handler_get_phonebook_status(
102 ModemInterface *modem,
103 AtCommandContext *at,
104 GString *response);
106 /* AtCommandHandlerStatus gsmd_sim_handler_set_default_storage_space( */
107 /* ModemInterface *modem, */
108 /* AtCommandContext *at, */
109 /* GString *response); */
111 AtCommandHandlerStatus gsmd_sim_handler_store_entry(
112 ModemInterface *modem,
113 AtCommandContext *at,
114 GString *response);
116 AtCommandHandlerStatus gsmd_sim_handler_delete_entry(
117 ModemInterface *modem,
118 AtCommandContext *at,
119 GString *response);
121 static
122 AtCommandHandlerStatus gsmd_sim_handler_get_index_boundaries(
123 ModemInterface *modem,
124 AtCommandContext *at,
125 GString *response);
127 AtCommandHandlerStatus gsmd_sim_handler_retrieve_entry(
128 ModemInterface *modem,
129 AtCommandContext *at,
130 GString *response);
133 static const AtCommand
134 sim_commands[]
136 //Query pin status
137 { PIN_QUERY, "AT+CPIN?\r\n", 20000,
138 TRUE, 0,
139 gsmd_sim_handler_query_pin_status, NULL, SIM_UNKNOWN, NULL},
140 //Query subscriber numbers
141 { QUERY_SUBSCRIBER_NUMBERS, "AT+CNUM\r\n", 20000,
142 TRUE, 0,
143 gsmd_sim_handler_get_subscriber_numbers, NULL, SIM_UNKNOWN, NULL},
145 //Setup pin
146 { PIN_SETUP, "AT+CPIN=\"%s\"\r\n", 20000,
147 FALSE, 0,
148 gsmd_sim_handler_pin, NULL, SIM_UNKNOWN, NULL},
150 //Change pin
151 { PIN_CHANGE, "AT+CPIN=%s\r\n", 20000,
152 FALSE, 0,
153 gsmd_sim_handler_pin, NULL, SIM_UNKNOWN, NULL},
155 //Setup puk
156 { PUK_SETUP, "AT+CPIN=%s\r\n", 20000,
157 FALSE, 0,
158 gsmd_sim_handler_pin, NULL, SIM_UNKNOWN, NULL},
160 //Get IMSI
161 { IMSI_QUERY, "AT+CIMI\r\n", 5000,
162 FALSE, 0,
163 gsmd_sim_handler_query_imsi, NULL, SIM_READY},
164 //Read sms
165 { SMS_READ, "AT+CMGR=%s\r\n", 5000,
166 FALSE, 0,
167 gsmd_sim_handler_read, NULL, SIM_READY, gsmd_sms_handler_read_free},
169 //Delete sms
170 { SMS_DELETE, "AT+CMGD=%s\r\n", 5000,
171 FALSE, 0,
172 gsmd_sim_handler_delete, NULL, SIM_READY, NULL},
174 //Query sms service center
175 { SMS_CENTER_QUERY, "AT+CSCA?\r\n", 20000,
176 TRUE, 0,
177 gsmd_sim_handler_query_service_center, NULL, SIM_READY, NULL},
179 //Set sms service center
180 { SMS_SET_CENTER, "AT+CSCA=%s\r\n", 20000,
181 TRUE, 0,
182 gsmd_sim_handler_set_service_center, NULL, SIM_READY, NULL},
184 //List messages
185 { SMS_LIST, "AT+CMGL=%s\r\n", 30000,
186 FALSE, 0, gsmd_sim_handler_list_messages,
187 NULL, SIM_READY,gsmd_sim_list_messages_free},
189 //Send message from storage
190 { SIM_SEND, "AT+CMSS=%s\r\n", 30000,
191 FALSE, 0, gsmd_sim_handler_send_message,
192 NULL, SIM_READY,NULL},
194 //Get available storage space
195 /* { PHONEBOOK_SPACES_QUERY, "AT+CPBS=?\r\n", 100, */
196 /* FALSE, 0, */
197 /* gsmd_sim_handler_get_storage_spaces, NULL, SIM_READY, */
198 /* gsmd_sim_storage_spaces_free}, */
200 //Get current storage space status
201 { PHONEBOOK_STATUS_QUERY, "AT+CPBS?\r\n", 100,
202 FALSE, 0,
203 gsmd_sim_handler_get_phonebook_status, NULL, SIM_READY,
204 NULL},
206 //Set storage space
207 /* { PHONEBOOK_SPACE_SET, "AT+CPBS=%s\r\n", 100, */
208 /* FALSE, 0, */
209 /* gsmd_sim_handler_set_default_storage_space, NULL, SIM_READY, */
210 /* NULL}, */
212 //Get storage item's index boundaries
213 { PHONEBOOK_GET_INDEX_BOUNDARIES, "AT+CPBR=?\r\n", 100,
214 FALSE, 0,
215 gsmd_sim_handler_get_index_boundaries, NULL, SIM_READY, NULL},
217 //Get entry from storage
218 { PHONEBOOK_ENTRY_GET, "AT+CPBR=%s\r\n", 100,
219 FALSE, 0,
220 gsmd_sim_handler_retrieve_entry, NULL, SIM_READY, NULL},
222 //Set storage entry
223 { PHONEBOOK_ENTRY_SET, "AT+CPBW=%s\r\n", 100,
224 FALSE, 0,
225 gsmd_sim_handler_store_entry, NULL, SIM_READY, NULL},
227 //Delete storage entry
228 { PHONEBOOK_ENTRY_DELETE, "AT+CPBW=%s\r\n", 100,
229 FALSE, 0,
230 gsmd_sim_handler_delete_entry, NULL, SIM_READY, NULL},
232 { 0, NULL, 100, TRUE, 1,
233 NULL, NULL, SIM_UNKNOWN },
235 }, *sim_command_p = sim_commands;
237 static const SymbolTable
238 sim_symbols[] = {
239 { "SIM", SYMBOL_SIM, },
240 { NULL, 0, },
241 }, *sim_symbol_p = sim_symbols;
242 void gsmd_sim_init_at_handler(ModemInterface* modem)
244 g_debug("%s", __func__);
246 while (sim_symbol_p->symbol_name) {
247 g_scanner_add_symbol (modem->scanner, sim_symbol_p->symbol_name,
248 GINT_TO_POINTER(sim_symbol_p->symbol_token));
249 sim_symbol_p++;
251 while (sim_command_p->command) {
252 gsmd_modem_register_command (modem,sim_command_p);
253 sim_command_p++;
257 * @brief Changes auth (pin) status, sends auth_status signal if
258 * status was changed.
260 * @param modem modem whose auth status to change
261 * @param status new pin status
262 * @param send_reply should reply to get_auth_status ipc method
263 * be sent aswll
265 void gsmd_sim_change_auth_status( ModemInterface *modem,
266 gpointer ipc_data,
267 SIMStatus status,
268 const gchar *message,
269 gboolean send_reply)
271 if ( status != modem->sim_status ) {
272 g_debug("Changing auth status from %d to %d.",modem->sim_status, status);
276 gsmd_utils_table_insert_string(modem->caches[INTERFACE_SIM],
277 GSMD_SIM_KEY_AUTH_STATUS,
278 message);
282 //Send a reply to get auth_status ipc method if necessary
283 if (send_reply && modem->sim_ipc->get_auth_status_reply && ipc_data)
284 modem->sim_ipc->get_auth_status_reply(modem->sim_ipc,
285 ipc_data,
286 message);
288 //If sim status has changed, send a signal
289 if (modem->sim_ipc->auth_status && status != modem->sim_status) {
290 modem->sim_ipc->auth_status(modem->sim_ipc,
291 message);
294 //finally change modem's sim status
295 gsmd_modem_change_sim_status(modem,status);
301 * Sends a reply to all pin related ipc method calls
303 * @param modem modem pointer
304 * @param cmd_id command/method call id
306 void gsmd_sim_send_pin_reply(ModemInterface *modem, AtCommandContext *at)
308 switch (at->command->cmd_id) {
309 case PIN_SETUP:
310 modem->sim_ipc->send_auth_code_reply(modem->sim_ipc,at->ipc_data);
311 break;
312 case PIN_CHANGE:
313 modem->sim_ipc->change_auth_code_reply(modem->sim_ipc,at->ipc_data);
314 break;
315 case PUK_SETUP:
316 modem->sim_ipc->unlock_reply(modem->sim_ipc,at->ipc_data);
317 break;
321 void gsmd_sim_list_messages_free (AtCommandContext *at)
323 GValue *val = g_hash_table_lookup(at->handler_data,
324 GSMD_SIM_KEY_MESSAGE_LIST);
325 GArray *list = g_value_get_pointer(val);
326 if (list)
327 g_array_free(list,TRUE);
330 static gboolean gsmd_sim_handler_list_messages_remove_last(GHashTable *table)
332 g_debug("%s",__func__);
333 GValue *val = g_hash_table_lookup(table,GSMD_SIM_KEY_MESSAGE_LIST);
334 if (!val)
335 return FALSE;
337 GArray *list = g_value_get_pointer(val);
339 if (!list)
340 return FALSE;
342 g_array_remove_index(list,list->len-1);
344 return TRUE;
347 AtCommandHandlerStatus gsmd_sim_handler_list_messages (ModemInterface *modem,
348 AtCommandContext *at,
349 GString *response)
352 at+cmgl=1
353 +CMGL: 1,1,"",145
354 <pdu>
355 +CMGL: 2,1,"",148
356 <pdu>
357 +CMGL: 3,1,"",158
359 Regular expression:
360 \+CMGL:\s(\d+),.*
363 AtCommandHandlerStatus status = AT_HANDLER_DONT_UNDERSTAND;
364 gint cms_code = 0;
365 if( gsmd_utils_parse_cms_error(modem, response,&cms_code) ) {
366 switch( cms_code ) {
367 case CMS_ERROR_INVALID_MESSAGE_INDEX: {
369 * At least on Neo 1973 this means that there
370 * are no message with given status
372 GValue *val = g_hash_table_lookup(at->handler_data,
373 GSMD_SIM_KEY_MESSAGE_LIST);
374 modem->sim_ipc->list_messages_reply(modem->sim_ipc,
375 at->ipc_data,
376 g_value_get_pointer(val));
377 return AT_HANDLER_DONE;
379 default:
380 g_warning("%s : CMS ERROR: %d", __func__, cms_code);
381 gsmd_utils_send_error(at,
382 GSMD_ERROR_UNKNOWN,
383 "UNABLE TO LIST MESSAGES");
384 return AT_HANDLER_DONE_ERROR;
387 GError **error = NULL;
388 GRegex *regex = g_regex_new ("\\+CMGL:\\s(?<id>\\d+),.*|(?<error>ERROR)|(?<ok>OK)|(?<pdu>[0-9A-F]+)", 0, 0, error);
390 GMatchInfo *match_info;
393 if (g_regex_match (regex, response->str, 0, &match_info)) {
397 if (gsmd_utils_match_exists(match_info,"id")) {
398 gchar *match = g_match_info_fetch_named(match_info,"id");
400 GValue *val = g_hash_table_lookup(at->handler_data,
401 GSMD_SIM_KEY_MESSAGE_LIST);
402 if (!val) {
403 gsmd_utils_send_error(at,
404 GSMD_ERROR_UNKNOWN,
405 "INVALID HANDLER DATA");
406 status = AT_HANDLER_DONE_ERROR;
409 GArray *list = g_value_get_pointer(val);
410 gint id = atoi(match);
411 g_array_append_val(list,id);
412 g_free(match);
414 status = AT_HANDLER_NEED_MORE;
417 if (gsmd_utils_match_exists(match_info,"error")) {
418 gsmd_utils_send_error(at,
419 GSMD_ERROR_UNKNOWN,
420 "UNABLE TO LIST MESSAGES");
421 status = AT_HANDLER_DONE_ERROR;
422 } else if (gsmd_utils_match_exists(match_info,"ok")) {
423 GValue *val = g_hash_table_lookup(at->handler_data,
424 GSMD_SIM_KEY_MESSAGE_LIST);
425 if (!val) {
426 gsmd_utils_send_error(at,
427 GSMD_ERROR_UNKNOWN,
428 "INVALID HANDLER DATA");
429 status = AT_HANDLER_DONE_ERROR;
430 } else {
431 modem->sim_ipc->list_messages_reply(modem->sim_ipc,
432 at->ipc_data,
433 g_value_get_pointer(val));
437 status = AT_HANDLER_DONE;
438 } else
439 //Check pdu, if this pdu is from a multipart message, but it's
440 //not the first part, then remove it from the list
441 if (gsmd_utils_match_exists(match_info,"pdu")) {
442 gchar *match = g_match_info_fetch_named(match_info,"pdu");
443 SmsParam *sms = g_try_new0(SmsParam,1);
444 if (gsmd_sim_decoder_pdu((guchar*)match,sms)) {
445 if (sms->multipart && sms->multipart_index != 1)
446 gsmd_sim_handler_list_messages_remove_last(at->handler_data);
448 gsmd_sms_sms_param_free(sms);
450 status = AT_HANDLER_NEED_MORE;
451 g_free(match);
457 g_free(error);
458 g_match_info_free (match_info);
459 g_regex_unref (regex);
462 return status;
465 static
466 AtCommandHandlerStatus gsmd_sim_handler_send_message (ModemInterface *modem,
467 AtCommandContext *at,
468 GString *response)
470 g_debug("%s",__func__);
472 AtCommandHandlerStatus status = AT_HANDLER_DONT_UNDERSTAND;
473 if (gsmd_utils_send_error_from_response(at,
474 modem->scanner,
475 "UNKNOWN ERROR OCCURRED WHEN SENDING MESSAGE",
476 "TIMEOUT OCCURRED WHEN SENDING MESSAGE"))
477 return AT_HANDLER_DONE_ERROR;
480 GError **error = NULL;
481 GRegex *regex = g_regex_new ("\\+CMSS:\\s(?<id>\\d+)|(?<cms>\\+CMS\\sERROR).*|(?<ok>OK)", 0, 0, error);
483 GMatchInfo *match_info;
486 if (g_regex_match (regex, response->str, 0, &match_info)) {
487 //Got +CMSS <id>
488 if (gsmd_utils_match_exists(match_info,"id")) {
489 gsmd_utils_table_insert_int(at->handler_data,
490 GSMD_SIM_KEY_CMSS_ID,
491 gsmd_utils_fetch_match_int(match_info,
492 "id",0));
493 status = AT_HANDLER_NEED_MORE;
494 } else
495 //Got ok
496 if (gsmd_utils_match_exists(match_info,"ok")) {
497 GValue *val = g_hash_table_lookup(at->handler_data,GSMD_SIM_KEY_CMSS_ID);
499 if (!val) {
500 g_warning("%s : Invalid handler data. Didn't get CMSS id",
501 __func__);
503 gsmd_utils_send_error(at,
504 GSMD_ERROR_UNKNOWN,
505 "INVALID HANDLER DATA");
506 status = AT_HANDLER_DONE_ERROR;
507 } else {
508 modem->sim_ipc->send_message_reply(modem->sim_ipc,at->ipc_data);
509 if (modem->sms_ipc->message_sent) {
510 modem->sms_ipc->message_sent(modem->sms_ipc,TRUE,NULL);
512 status = AT_HANDLER_DONE;
514 } else
515 //Got +CMS ERROR
516 if (gsmd_utils_match_exists(match_info,"cms")) {
517 status = gsmd_sms_process_sms_error_response (modem,
519 modem->scanner);
524 g_free(error);
525 g_match_info_free (match_info);
526 g_regex_unref (regex);
529 return status;
533 * @brief Handler to modems response from setupPin command
535 * @param modem modem whose response to handle
536 * @return true if responses were recognized
538 static
539 AtCommandHandlerStatus gsmd_sim_handler_pin(ModemInterface *modem,
540 AtCommandContext *at,
541 GString *response)
544 AtCommandHandlerStatus ret = AT_HANDLER_DONT_UNDERSTAND;
546 GScanner* scanner = modem->scanner;
548 if (scanner != 0)
549 g_debug("gsmd_sim_handler_setup_pin %d", scanner->token);
550 else {
551 g_debug("gsmd_sim_handler_setup_pin error - no scanner");
552 return AT_HANDLER_DONE;
557 switch (scanner->token) {
558 case SYMBOL_OK:
559 gsmd_sim_send_pin_reply(modem, at);
560 gsmd_sim_change_auth_status(modem,NULL,SIM_READY,"READY",FALSE);
562 ret = AT_HANDLER_DONE;
563 break;
564 case SYMBOL_ERROR:
565 gsmd_utils_send_error(at,
566 GSMD_ERROR_UNKNOWN,
567 "FAILED TO CHANGE AUTH CODE");
569 if (modem->sim_status == SIM_NEED_PUK)
570 gsmd_sim_change_auth_status(modem,NULL,SIM_READY,"READY",FALSE);
573 /* What should be done on each status
574 SIM_UNKNOWN=0 -> we're still at unknown state
575 SIM_MISSING_SIM -> we still don't have a sim card
576 SIM_NEED_PIN -> pin was wrong, we still need pin
577 SIM_NEED_PUK -> puk code was wrong, we still need puk
578 SIM_READY -> we never needed any code so nothing changed
580 ret = AT_HANDLER_DONE_ERROR;
581 break;
582 default:
583 g_warning("%s : No match to setupPin handler", __func__);
584 break;
586 return ret;
590 void gsmd_sim_cache_auth_status(ModemInterface *modem,
591 AtCommandContext *at,
592 SIMStatus status,
593 const gchar *message)
595 g_debug("%s: status: %d, message: %s",__func__,status,message);
596 gsmd_utils_table_insert_string(at->handler_data,GSMD_SIM_KEY_AUTH_MESSAGE,message);
597 gsmd_utils_table_insert_int(at->handler_data,GSMD_SIM_KEY_AUTH_STATUS,status);
601 * @brief Handler to modems response from queryPinStatus command
603 * @param modem modem whose response to handle
604 * @return true if responses were recognized
606 static
607 AtCommandHandlerStatus gsmd_sim_handler_query_pin_status (ModemInterface *modem,
608 AtCommandContext *at,
609 GString *response)
611 g_debug("%s",__func__);
612 GScanner* scanner = modem->scanner;
616 if (scanner->token == SYMBOL_OK) {
618 GValue *status = g_hash_table_lookup(at->handler_data,GSMD_SIM_KEY_AUTH_STATUS);
619 GValue *message = g_hash_table_lookup(at->handler_data,GSMD_SIM_KEY_AUTH_MESSAGE);
621 if (!status || !message) {
622 g_warning("%s : Invalid handler data. status: %p, message: %p",
623 __func__,
624 status,
625 message);
626 gsmd_utils_send_error(at,GSMD_ERROR_UNKNOWN,"INVALID HANDLER DATA");
627 return AT_HANDLER_DONE_ERROR;
630 gsmd_sim_change_auth_status(modem,
631 at->ipc_data,
632 g_value_get_int(status),
633 g_value_get_string(message),
634 TRUE);
636 return AT_HANDLER_DONE;
639 if (gsmd_utils_send_error_from_response(at,
640 scanner,
641 "ERROR READING PIN STATUS",
642 "TIMEOUT READING PIN STATUS"))
643 return AT_HANDLER_DONE_ERROR;
645 if (scanner->token != '+') {
646 return AT_HANDLER_DONT_UNDERSTAND;
649 g_scanner_get_next_token (scanner);
650 switch (scanner->token) {
652 case SYMBOL_CME:
653 g_scanner_get_next_token (scanner);
654 //g_scanner_get_next_token (scanner);
655 if (scanner->token == SYMBOL_ERROR) {
656 g_scanner_peek_next_token(scanner);
657 if (scanner->next_token == ':') {
658 g_scanner_get_next_token (scanner);
659 g_scanner_get_next_token(scanner);//arrive error value
660 if ( ERR_NO_SIM_CARD == scanner->value.v_int ) {
661 gsmd_sim_change_auth_status(modem,
662 at->ipc_data,
663 SIM_MISSING,
664 "SIM MISSING",
665 TRUE);
666 } else {
667 gsmd_sim_change_auth_status(modem,
668 at->ipc_data,
669 SIM_ERROR,
670 "SIM ERROR",
671 TRUE);
674 return AT_HANDLER_DONE;
675 } else {
676 g_scanner_unexp_token (scanner, ':', NULL, "symbol",
677 NULL, NULL, TRUE);
680 } else {
681 g_scanner_unexp_token (scanner, SYMBOL_ERROR, NULL, "symbol",
682 NULL, NULL, TRUE);
684 break;
685 case SYMBOL_CPIN:
686 g_scanner_get_next_token (scanner);//get ':'
687 g_scanner_get_next_token (scanner);
688 if (scanner->token == SYMBOL_READY) {
689 gsmd_sim_cache_auth_status(modem,
691 SIM_READY,
692 "READY");
695 return AT_HANDLER_NEED_MORE;
697 } else if (scanner->token == SYMBOL_SIM) {
699 g_scanner_get_next_token (scanner);
700 g_scanner_peek_next_token(scanner);
701 if (scanner->token == SYMBOL_PIN) {
702 gsmd_sim_cache_auth_status(modem,
704 SIM_NEED_PIN,
705 "SIM PIN");
708 } else if (scanner->token == SYMBOL_PUK) {
709 gsmd_sim_cache_auth_status(modem,
711 SIM_NEED_PUK,
712 "SIM PUK");
715 return AT_HANDLER_NEED_MORE;
716 } else {
717 g_scanner_unexp_token (scanner, SYMBOL_READY, NULL, "symbol",
718 NULL, NULL, TRUE);
720 break;
721 default:
722 g_warning("No match after getting + \n");
723 break;
728 return AT_HANDLER_DONT_UNDERSTAND;
734 * @brief AtCommand to setup pin value(s)
736 * @param modem modem whose response to handle
737 * @param pin_code pin code(s) to set
739 static void gsmd_sim_command_setup_pin (SIMInterface *sim,
740 gpointer ipc_data,
741 const char* pin_code)
743 ModemInterface *modem = (ModemInterface*)sim->priv;
744 gsmd_modem_post_at_command_id( modem,
745 PIN_SETUP,
746 pin_code,
747 ipc_data,
748 (ErrorFunction)modem->sim_ipc->send_auth_code_error,
749 (gpointer)modem->sim_ipc,
750 INTERFACE_SIM,
751 NULL);
756 * @brief AtCommand to query pin status
758 * @param modem modem whose response to handle
760 static void gsmd_sim_command_query_pin_status (SIMInterface *sim,
761 gpointer ipc_data)
763 ModemInterface *modem = (ModemInterface*)sim->priv;
764 GValue *val = g_hash_table_lookup(modem->caches[INTERFACE_SIM],GSMD_SIM_KEY_AUTH_STATUS);
765 if (!modem->no_cache && val) {
766 modem->sim_ipc->get_auth_status_reply(modem->sim_ipc,
767 ipc_data,
768 g_value_get_string(val));
769 } else {
770 gsmd_modem_post_at_command_id( modem,
771 PIN_QUERY,
772 NULL,
773 ipc_data,
774 (ErrorFunction)modem->sim_ipc->get_auth_status_error,
775 (gpointer)modem->sim_ipc,
776 INTERFACE_SIM,
777 NULL);
783 void gsmd_sim_command_unlock(SIMInterface *sim,
784 gpointer ipc_data,
785 const char* puk,
786 const char* new_pin)
788 g_debug("%s",__func__);
789 ModemInterface *modem = (ModemInterface*)sim->priv;
790 GString* param = g_string_new ("");
791 g_string_printf(param, "\"%s\",\"%s\"",puk,new_pin);
793 gsmd_modem_post_at_command_id( modem,
794 PUK_SETUP,
795 param->str,
796 ipc_data,
797 (ErrorFunction)modem->sim_ipc->unlock_error,
798 (gpointer)modem->sim_ipc,
799 INTERFACE_SIM,
800 NULL);
801 g_string_free(param,TRUE);
805 void gsmd_sim_command_change_auth_code(SIMInterface *sim,
806 gpointer ipc_data,
807 const char* old_pin,
808 const char* new_pin)
810 ModemInterface *modem = (ModemInterface*)sim->priv;
811 GString* param = g_string_new ("");
812 g_string_printf(param, "\"%s\",\"%s\"",old_pin,new_pin);
814 gsmd_modem_post_at_command_id( modem,
815 PIN_CHANGE,
816 param->str,
817 ipc_data,
818 (ErrorFunction)modem->sim_ipc->change_auth_code_error,
819 (gpointer)modem->sim_ipc,
820 INTERFACE_SIM,
821 NULL);
822 g_string_free(param,TRUE);
827 * Handler for reply to query_imsi command.
829 * @param modem pointer to modem struct
830 * @param response response sent by gsm modem
831 * @return AT_HANDLER_DONE when response is recognized
833 static
834 AtCommandHandlerStatus gsmd_sim_handler_query_imsi( ModemInterface *modem,
835 AtCommandContext *at,
836 GString *response)
839 at+cimi
840 +CIMI: 244917070350971
845 AtCommandHandlerStatus status = AT_HANDLER_DONT_UNDERSTAND;
846 GError *error = NULL;
847 GRegex *regex = g_regex_new ("^\\+CIMI:\\s(?<imsi>\\d+)$|^(?<imsi2>\\d+)$|^(?<error>ERROR)$|^(?<ok>OK)$",
848 0, 0, &error);
849 if ( error ) {
850 g_debug("%s : '%s'", __func__, error->message);
851 g_error_free( error );
852 return AT_HANDLER_ERROR;
854 GMatchInfo *match_info;
855 GValue *val = NULL;
858 if (g_regex_match (regex, response->str, 0, &match_info)) {
859 if (gsmd_utils_match_exists(match_info,"imsi")) {
860 gchar *match = g_match_info_fetch_named(match_info,
861 "imsi");
862 g_debug("%s : imsi : %s", __func__, match);
864 gsmd_utils_table_insert_string(at->handler_data,
865 GSMD_SIM_KEY_IMSI,
866 match);
868 g_free(match);
869 status = AT_HANDLER_NEED_MORE;
870 } else if (gsmd_utils_match_exists(match_info,"imsi2")) {
871 gchar *match = g_match_info_fetch_named(match_info,
872 "imsi2");
874 g_debug("%s : imsi2 : %s", __func__, match);
875 gsmd_utils_table_insert_string(at->handler_data,
876 GSMD_SIM_KEY_IMSI,
877 match);
879 g_free(match);
880 status = AT_HANDLER_NEED_MORE;
881 } else if (gsmd_utils_match_exists(match_info,"error")) {
882 gsmd_utils_send_error(at,
883 GSMD_ERROR_UNKNOWN,
884 "FAILED TO READ IMSI");
885 status = AT_HANDLER_DONE_ERROR;
886 } else if (gsmd_utils_match_exists(match_info,"ok")) {
887 val = g_hash_table_lookup(at->handler_data,GSMD_SIM_KEY_IMSI);
888 g_debug("%s : ok : %p", __func__, val);
889 if (val) {
890 status = AT_HANDLER_DONE;
891 } else {
892 // If we didn't get the response,
893 // then this OK is not for us
894 status = AT_HANDLER_DONT_UNDERSTAND;
900 g_match_info_free (match_info);
901 g_regex_unref (regex);
904 return status;
907 static
908 gboolean gsmd_sim_command_get_sim_info_reply(ModemInterface *modem,
909 gpointer ipc_data,
910 GHashTable *info)
912 g_debug("%s", __func__);
913 if( !modem->no_cache ) {
914 GValue *imsi = g_hash_table_lookup(info,GSMD_SIM_KEY_IMSI);
915 if( imsi ) {
916 gsmd_utils_table_insert_copy(modem->caches[INTERFACE_SIM],GSMD_SIM_KEY_IMSI,imsi);
919 modem->sim_ipc->get_sim_info_reply( modem->sim_ipc,
920 ipc_data,
921 info);
922 return TRUE;
924 static
925 AtCommandHandlerStatus gsmd_sim_handler_get_sim_info( ModemInterface *modem,
926 AtCommandContext *at,
927 GString *response)
929 AtCommandHandlerStatus status = AT_HANDLER_DONT_UNDERSTAND;
930 switch (at->command->cmd_id) {
931 case IMSI_QUERY:
932 g_debug("%s : IMSI_QUERY", __func__);
933 status = at->command->handler(modem,at,response);
934 switch (status) {
935 case AT_HANDLER_DONE_ERROR:
936 case AT_HANDLER_ERROR:
937 return AT_HANDLER_DONE_ERROR;
938 break;
939 case AT_HANDLER_DONE:
940 if ( !g_hash_table_lookup(at->handler_data,GSMD_SIM_KEY_IMSI) ) {
941 gsmd_utils_send_error(at,GSMD_ERROR_UNKNOWN,"UNABLE TO READ IMSI");
942 return AT_HANDLER_DONE_ERROR;
944 gsmd_sim_command_get_sim_info_reply(modem, at->ipc_data, at->handler_data);
945 /* gsmd_modem_post_at_command_id( modem, */
946 /* QUERY_SUBSCRIBER_NUMBERS, */
947 /* NULL, */
948 /* ipc_data, */
949 /* (ErrorFunction)modem->sim_ipc->get_subscriber_numbers_error, */
950 /* (gpointer)modem->sim_ipc, */
951 /* INTERFACE_SIM, */
952 /* NULL); */
953 break;
954 case AT_HANDLER_DONT_UNDERSTAND:
955 case AT_HANDLER_NEED_MORE:
956 case AT_HANDLER_RETRY:
957 return status;
959 break;
961 return status;
964 void gsmd_sim_command_get_sim_info(SIMInterface *sim,
965 gpointer ipc_data)
967 ModemInterface *modem = (ModemInterface*)sim->priv;
968 GValue *imsi = NULL;
969 GValue *subs_num = NULL;
970 GValue *dialcode = NULL;
971 if (!modem->no_cache ) {
972 imsi = g_hash_table_lookup(modem->caches[INTERFACE_SIM],GSMD_SIM_KEY_IMSI);
973 subs_num = g_hash_table_lookup(modem->caches[INTERFACE_SIM],GSMD_SIM_KEY_SUBSCRIBER_NUMBER);
974 dialcode = g_hash_table_lookup(modem->caches[INTERFACE_SIM],GSMD_SIM_KEY_DIAL_CODE);
977 if (imsi && subs_num && dialcode) {
978 g_debug("%s: sim info is cached",__func__);
979 GHashTable *info = gsmd_utils_create_hash_table();
980 gsmd_utils_table_insert_copy(info,GSMD_SIM_KEY_IMSI,imsi);
981 gsmd_utils_table_insert_copy(info,GSMD_SIM_KEY_SUBSCRIBER_NUMBER,subs_num);
982 gsmd_utils_table_insert_copy(info,GSMD_SIM_KEY_DIAL_CODE, dialcode);
983 modem->sim_ipc->get_sim_info_reply(modem->sim_ipc,
984 ipc_data,
985 info);
986 g_hash_table_destroy(info);
987 } else {
988 AtCommandContext *cmd = NULL;
989 cmd = gsmd_at_command_context_new_from_id( modem,
990 IMSI_QUERY,
991 NULL,
992 ipc_data,
993 (ErrorFunction)modem->sim_ipc->get_sim_info_error,
994 (gpointer)modem->sim_ipc,
995 NULL);
996 cmd->handler = &gsmd_sim_handler_get_sim_info;
997 gsmd_modem_post_at_command(modem,cmd,INTERFACE_SIM);
1002 static
1003 gboolean gsmd_sim_command_get_phonebook_info_reply(ModemInterface *modem,
1004 gpointer ipc_data,
1005 GHashTable *info)
1007 g_debug("%s", __func__);
1008 if( !modem->no_cache ) {
1009 GValue *slots = g_hash_table_lookup(info,GSMD_SIM_KEY_PHONEBOOK_SLOTS);
1010 GValue *used = g_hash_table_lookup(info,GSMD_SIM_KEY_PHONEBOOK_SLOTS_USED);
1011 GValue *number_len = g_hash_table_lookup(info,GSMD_SIM_KEY_PHONEBOOK_NUMBER_LEN);
1012 GValue *name_len = g_hash_table_lookup(info,GSMD_SIM_KEY_PHONEBOOK_NAME_LEN);
1013 if( slots ) {
1014 gsmd_utils_table_insert_copy(info,GSMD_SIM_KEY_PHONEBOOK_SLOTS,slots);
1016 if( used ) {
1017 gsmd_utils_table_insert_copy(info,GSMD_SIM_KEY_PHONEBOOK_SLOTS_USED, used);
1019 if( number_len ) {
1020 gsmd_utils_table_insert_copy(info,GSMD_SIM_KEY_PHONEBOOK_NUMBER_LEN,number_len);
1022 if( name_len ) {
1023 gsmd_utils_table_insert_copy(info,GSMD_SIM_KEY_PHONEBOOK_NAME_LEN,name_len);
1026 modem->sim_ipc->get_sim_info_reply( modem->sim_ipc,
1027 ipc_data,
1028 info);
1029 return TRUE;
1032 static
1033 AtCommandHandlerStatus gsmd_sim_handler_get_phonebook_info( ModemInterface *modem,
1034 AtCommandContext *at,
1035 GString *response)
1037 AtCommandHandlerStatus status = AT_HANDLER_DONT_UNDERSTAND;
1038 AtCommandContext *cmd = NULL;
1039 switch (at->command->cmd_id) {
1040 case PHONEBOOK_GET_INDEX_BOUNDARIES:
1041 g_debug("%s : PHONEBOOK_GET_INDEX_BOUNDARIES", __func__);
1042 status = at->command->handler(modem,at,response);
1043 switch (status) {
1044 case AT_HANDLER_DONE_ERROR:
1045 case AT_HANDLER_ERROR:
1046 return AT_HANDLER_DONE_ERROR;
1047 break;
1048 case AT_HANDLER_DONE:
1049 cmd = gsmd_at_command_context_new_from_id( modem,
1050 PHONEBOOK_STATUS_QUERY,
1051 NULL,
1052 at->ipc_data,
1053 (ErrorFunction)modem->sim_ipc->get_phonebook_info_error,
1054 (gpointer)modem->sim_ipc,
1055 at->handler_data);
1056 at->handler_data = NULL;
1057 cmd->handler = &gsmd_sim_handler_get_phonebook_info;
1058 gsmd_modem_post_at_command(modem,cmd,INTERFACE_SIM);
1059 break;
1060 case AT_HANDLER_DONT_UNDERSTAND:
1061 case AT_HANDLER_NEED_MORE:
1062 case AT_HANDLER_RETRY:
1063 return status;
1065 break;
1066 case PHONEBOOK_STATUS_QUERY:
1067 g_debug("%s : PHONEBOOK_STATUS_QUERY", __func__);
1068 status = at->command->handler(modem,at,response);
1069 switch (status) {
1070 case AT_HANDLER_DONE_ERROR:
1071 case AT_HANDLER_ERROR:
1072 return AT_HANDLER_DONE_ERROR;
1073 break;
1074 case AT_HANDLER_DONE:
1075 gsmd_sim_command_get_phonebook_info_reply(modem, at->ipc_data, at->handler_data);
1076 break;
1077 case AT_HANDLER_DONT_UNDERSTAND:
1078 case AT_HANDLER_NEED_MORE:
1079 case AT_HANDLER_RETRY:
1080 return status;
1082 break;
1084 return status;
1086 /**
1087 * @brief Requests phonebook info
1089 * @param sim SIM interface
1090 * @param ipc_data IPC method context data
1092 void gsmd_sim_command_get_phonebook_info(SIMInterface *sim,
1093 gpointer ipc_data)
1095 ModemInterface *modem = (ModemInterface*)sim->priv;
1096 GValue *slots = NULL;
1097 GValue *used = NULL;
1098 GValue *number_len = NULL;
1099 GValue *name_len = NULL;
1100 if (!modem->no_cache ) {
1101 slots = g_hash_table_lookup(modem->caches[INTERFACE_SIM],GSMD_SIM_KEY_PHONEBOOK_SLOTS);
1102 used = g_hash_table_lookup(modem->caches[INTERFACE_SIM],GSMD_SIM_KEY_PHONEBOOK_SLOTS_USED);
1103 number_len = g_hash_table_lookup(modem->caches[INTERFACE_SIM],GSMD_SIM_KEY_PHONEBOOK_NUMBER_LEN);
1104 name_len = g_hash_table_lookup(modem->caches[INTERFACE_SIM],GSMD_SIM_KEY_PHONEBOOK_NAME_LEN);
1107 if (slots && used && number_len && name_len) {
1108 g_debug("%s: info is cached",__func__);
1109 GHashTable *info = gsmd_utils_create_hash_table();
1110 gsmd_utils_table_insert_copy(info,GSMD_SIM_KEY_PHONEBOOK_SLOTS,slots);
1111 gsmd_utils_table_insert_copy(info,GSMD_SIM_KEY_PHONEBOOK_SLOTS_USED, used);
1112 gsmd_utils_table_insert_copy(info,GSMD_SIM_KEY_PHONEBOOK_NUMBER_LEN,number_len);
1113 gsmd_utils_table_insert_copy(info,GSMD_SIM_KEY_PHONEBOOK_NAME_LEN,name_len);
1114 modem->sim_ipc->get_phonebook_info_reply(modem->sim_ipc,
1115 ipc_data,
1116 info);
1117 g_hash_table_destroy(info);
1118 } else {
1119 AtCommandContext *cmd = NULL;
1120 cmd = gsmd_at_command_context_new_from_id( modem,
1121 PHONEBOOK_GET_INDEX_BOUNDARIES,
1122 NULL,
1123 ipc_data,
1124 (ErrorFunction)modem->sim_ipc->get_phonebook_info_error,
1125 (gpointer)modem->sim_ipc,
1126 NULL);
1127 cmd->handler = &gsmd_sim_handler_get_phonebook_info;
1128 gsmd_modem_post_at_command(modem,cmd,INTERFACE_SIM);
1134 * @brief Creates at command to set service center
1136 * @param modem modem to send command to
1137 * @param centerNo center number
1139 void gsmd_sim_command_set_service_center (SIMInterface *sim,
1140 gpointer ipc_data,
1141 const char* centerNo)
1143 ModemInterface *modem = (ModemInterface*)sim->priv;
1144 GString* command= g_string_new ("");
1145 gint format=0;
1146 if (g_strrstr (centerNo, "+")) {
1147 //Internation format
1148 format = 145;
1149 } else {
1150 //national format
1151 format = 129;
1153 g_string_printf (command, "%s,%d", centerNo, format);
1154 gsmd_modem_post_at_command_id( modem,
1155 SMS_SET_CENTER,
1156 command->str,
1157 ipc_data,
1158 (ErrorFunction)modem->sim_ipc->set_service_center_number_error,
1159 (gpointer)modem->sim_ipc,
1160 INTERFACE_SIM,
1161 NULL);
1162 g_string_free(command,TRUE);
1166 * @brief Handler for replies sent by the gsm modem when a service center query
1167 * command is sent
1169 * @param modem modem whose replies to interpret
1170 * @return true if replies were correct
1172 AtCommandHandlerStatus gsmd_sim_handler_query_service_center (ModemInterface *modem,
1173 AtCommandContext *at,
1174 GString *response)
1176 //input is +CSCA: "+393359609600", 145
1177 GScanner* scanner = modem->scanner;
1178 if (scanner->token == SYMBOL_OK) {
1179 if (modem->sim_ipc->get_service_center_number_reply) {
1180 GValue *val = g_hash_table_lookup(at->handler_data,GSMD_SIM_KEY_SERVICE_CENTER);
1181 if (!val) {
1182 g_warning("%s : Invalid handler data. service center: %p",
1183 __func__,
1184 val);
1186 gsmd_utils_send_error(at,
1187 GSMD_ERROR_UNKNOWN,
1188 "INVALID HANDLER DATA");
1190 modem->sim_ipc->get_service_center_number_reply(modem->sim_ipc,
1191 at->ipc_data,
1192 g_value_get_string(val));
1195 return AT_HANDLER_DONE;
1197 if (scanner->token == '+') {
1198 g_scanner_get_next_token (scanner);
1199 if (scanner->token == SYMBOL_CSCA) {
1200 g_scanner_get_next_token (scanner);//get :
1201 if (scanner->token == ':') {
1202 g_scanner_get_next_token (scanner);
1203 gsmd_utils_table_insert_string(at->handler_data,GSMD_SIM_KEY_SERVICE_CENTER,scanner->value.v_string);
1206 return AT_HANDLER_NEED_MORE;
1210 return AT_HANDLER_DONT_UNDERSTAND;
1215 * @brief Creates at command to query service center
1217 * @param modem modem to send command to
1219 void gsmd_sim_command_query_service_center (SIMInterface *sim,
1220 gpointer ipc_data)
1222 ModemInterface *modem = (ModemInterface*)sim->priv;
1223 GValue *val = g_hash_table_lookup(modem->caches[INTERFACE_SIM],GSMD_SIM_KEY_SERVICE_CENTER);
1224 if (val && modem->no_cache) {
1225 modem->sim_ipc->get_service_center_number_reply(modem->sim_ipc,
1226 ipc_data,
1227 g_value_get_string(val));
1228 } else {
1229 gsmd_modem_post_at_command_id( modem,
1230 SMS_CENTER_QUERY,
1231 NULL,
1232 ipc_data,
1233 (ErrorFunction)modem->sim_ipc->get_service_center_number_error,
1234 (gpointer)modem->sim_ipc,
1235 INTERFACE_SIM,
1236 NULL);
1243 * @brief Handler for replies sent by the gsm modem when a service center query
1244 * command is sent
1246 * @param modem modem whose replies to interpret
1247 * @return true if replies were correct
1249 static
1250 AtCommandHandlerStatus gsmd_sim_handler_get_subscriber_numbers (ModemInterface *modem,
1251 AtCommandContext *at,
1252 GString *response)
1255 at+cnum
1257 +CNUM: "","",129
1262 return AT_HANDLER_DONE;
1267 * @brief Handler for replies sent by the gsm modem when a set service centre
1268 * command is sent
1270 * @param modem modem whose replies to interpret
1271 * @return true if replies were correct
1273 AtCommandHandlerStatus gsmd_sim_handler_set_service_center (ModemInterface *modem,
1274 AtCommandContext *at,
1275 GString *response)
1277 GScanner* scanner = modem->scanner;
1278 g_assert( at );
1279 switch (scanner->token) {
1280 case SYMBOL_OK:
1281 modem->sim_ipc->set_service_center_number_reply(modem->sim_ipc,
1282 at->ipc_data);
1283 return AT_HANDLER_DONE;
1284 break;
1285 case SYMBOL_ERROR:
1286 gsmd_utils_send_error(at,
1287 GSMD_ERROR_UNKNOWN,
1288 "FAILED TO SET SERVICE CENTER");
1289 return AT_HANDLER_DONE_ERROR;
1290 break;
1291 default:
1292 break;
1294 return AT_HANDLER_DONT_UNDERSTAND;
1297 static void gsmd_sim_command_store_message (SIMInterface *sim,
1298 gpointer ipc_data,
1299 const gchar *message,
1300 const gchar *number)
1303 at+cmgw=48
1305 > 0011000C915348500496870000AA0AE8329BFD4697D9EC37
1308 g_debug("%s : Storing message %s to %s",__func__,message,number);
1309 ModemInterface *modem = (ModemInterface*)sim->priv;
1310 gsmd_sms_send_pdu (modem,
1311 ipc_data,
1312 message,
1313 number,
1314 SMS_STORE,
1315 INTERFACE_SIM,
1316 (ErrorFunction)modem->sim_ipc->store_message_error,
1317 modem->sim_ipc,
1318 TRUE);
1324 * @brief 7 bit decode
1326 * @param src source message
1327 * @param dst destination message
1328 * @param src_length length of the source string
1329 * @return resulting destination's string
1331 static int gsmd_sim_decode_7bits(const guchar*src, guchar* dst, gint src_length)
1333 //divide bytes into groups, each group has 7 bytes, decode it
1334 //to 8 bytes
1335 gint src_p=0;//processed bytes in source gourp
1336 gint dst_p=0;//processed bytes in dest group
1337 gint cur_index=0;// char index of current processing group
1338 gint cur_left=0;// the left bits from last byte
1339 while (src_p < src_length) {
1340 *dst = ((*src << cur_index) | cur_left) & 0x7f;
1341 cur_left = *src >> (7 - cur_index);
1342 dst++;
1343 dst_p++;
1344 cur_index++;
1345 if (cur_index == 7) {
1346 *dst = cur_left;
1347 dst++;
1348 dst_p++;
1349 cur_left = 0;
1350 cur_index = 0;
1352 src++;
1353 src_p++;
1354 g_assert(dst_p < 512);
1356 *dst=0;
1357 return dst_p;
1361 * @brief Normalizes received telephonenumber.
1363 * Adds + to the beginning of
1364 * phone number if the phonenumber is in international format.
1366 * @param pdu sms parameters
1368 static void gsmd_sim_normalize_received_telnumber (SmsParam* pdu)
1370 gint i=0;
1371 gint len = strlen ((const char*)pdu->TPA);
1372 if (pdu->TOA == 0x91) {
1373 //international format
1374 //add +before the number
1375 for (i=len; i>0; i--) {
1376 pdu->TPA[i] = pdu->TPA[i-1];
1378 pdu->TPA[0] = '+';
1379 pdu->TPA[len+1] = '\0';
1389 //method call handler
1391 * @brief Handler for delete sms command's replies.
1393 * @param modem whose replies to handle
1394 * @return true if response was recognized
1396 AtCommandHandlerStatus gsmd_sim_handler_delete(ModemInterface *modem,
1397 AtCommandContext *at,
1398 GString *response)
1400 GScanner* scanner = modem->scanner;
1401 guint symbol;
1402 symbol = scanner->token;
1403 if (scanner->token == SYMBOL_OK) {
1404 if (modem->sim_ipc->delete_message_reply) {
1405 modem->sim_ipc->delete_message_reply(modem->sim_ipc,at->ipc_data);
1407 return AT_HANDLER_DONE;
1410 if (gsmd_utils_send_error_from_response(at,
1411 scanner,
1412 "UNKNOWN ERROR OCCURRED WHEN DELETING A MESSAGE",
1413 "TIMOUT OCCURRED WHEN DELETING A MESSAGE")) {
1414 return AT_HANDLER_DONE_ERROR;
1418 return AT_HANDLER_DONT_UNDERSTAND;
1424 static gboolean gsmd_sim_convert(guchar** src,
1425 guchar* dst,
1426 int src_length,
1427 int *dst_length,
1428 int move)
1430 if (strlen((char*)*src) < src_length + move)
1431 return FALSE;
1432 if (!gsmd_sms_string_to_bytes(*src,dst,src_length,dst_length))
1433 return FALSE;
1435 *src+=move;
1436 return TRUE;
1439 static gboolean gsmd_sim_convert_number(guchar** src,
1440 guchar* dst,
1441 int src_length,
1442 gboolean is_encode,
1443 int move)
1445 if (!gsmd_sms_invert_number(*src,dst,src_length,is_encode))
1446 return FALSE;
1447 if (strlen((char*)*src) < move)
1448 return FALSE;
1449 *src+=move;
1450 return TRUE;
1453 static gboolean sim_decoder_pdu_header( guchar **src, SmsParam *pdu)
1455 guchar tmp;
1457 //the SMSC Number length
1458 if (!gsmd_sim_convert(src,&tmp,2,NULL,4))
1459 return FALSE;
1461 tmp = (tmp-1)*2;
1463 //SMSC number
1464 if (!gsmd_sim_convert_number(src,pdu->SCA,tmp,FALSE,tmp))
1465 return FALSE;
1467 return TRUE;
1471 static gboolean sim_decoder_pdu_type( guchar **src, SmsParam *pdu)
1473 guchar tmp;
1475 if (!gsmd_sim_convert(src,&tmp,2,NULL,2))
1476 return FALSE;
1478 //check if it is send or receive
1479 pdu->storing = (tmp & 1);
1480 //check if it's multipart
1481 pdu->multipart = (tmp&64);
1483 if (pdu->storing) //if encoding submitted message, ignore reference number
1484 *src+=2;
1487 return TRUE;
1490 static gboolean sim_decoder_pdu_sender_num( guchar **src, SmsParam *pdu)
1492 guchar tmp;
1496 //the real status does not match the spec, in spec the 7bits should be 1 to
1497 //include the reply path. but the real value is 04H
1498 //include reply info
1500 //length of sender number
1501 if (!gsmd_sim_convert(src,&tmp,2,NULL,2))
1502 return FALSE;
1504 if (tmp & 1)
1505 tmp += 1;
1507 //length of sender number
1508 if (!gsmd_sim_convert(src,&pdu->TOA,2,NULL,2))
1509 return FALSE;
1511 if (!gsmd_sim_convert_number(src,pdu->TPA,tmp,FALSE,tmp))
1512 return FALSE;
1514 gsmd_sim_normalize_received_telnumber (pdu);
1516 return TRUE;
1519 static gboolean sim_decoder_pdu_protocol( guchar **src, SmsParam *pdu)
1521 return gsmd_sim_convert(src,&pdu->TP_PID,2,NULL,2);
1524 static gboolean sim_decoder_pdu_coding_scheme( guchar **src, SmsParam *pdu)
1526 return gsmd_sim_convert(src,&pdu->TP_DCS,2,NULL,2);
1529 static gboolean sim_decoder_pdu_validity_period( guchar **src, SmsParam *pdu)
1531 if (pdu->storing) {
1532 *src+=2; //if submit format, skip validity period
1535 return TRUE;
1539 static gboolean sim_decoder_pdu_timestamp( guchar **src, SmsParam *pdu)
1541 if (!pdu->storing) {
1542 if (!gsmd_sim_convert_number(src,pdu->TP_SCTS,14,FALSE,14))
1543 return FALSE;
1544 } else {
1545 memset(pdu->TP_SCTS,0,14);
1548 return TRUE;
1552 static gboolean sim_decoder_pdu_userdata( guchar **src, SmsParam *pdu)
1554 int dst_length;
1555 guchar tmp;
1556 gint len;
1557 guchar buf[256];
1558 guchar div = 0;
1560 if (!gsmd_sim_convert(src,&tmp,2,NULL,2))
1561 return FALSE;
1564 if (pdu->multipart) {
1565 if (!gsmd_sim_convert(src,&div,2,NULL,6))
1566 return FALSE;
1567 if (!gsmd_sim_convert(src,&pdu->multipart_ref,2,NULL,2))
1568 return FALSE;
1569 if (!gsmd_sim_convert(src,&pdu->multipart_count,2,NULL,2))
1570 return FALSE;
1571 if (!gsmd_sim_convert(src,&pdu->multipart_index,2,NULL,2))
1572 return FALSE;
1575 div+=1;
1578 //if header doesn't stop at the edge of septet, skip fill bytes
1579 if (pdu->TP_DCS == GSM_7BIT && (div % 7) != 0) {
1580 div += (7-((div)%7));
1582 //skip back userdata header
1583 *src-=12;
1585 } else {
1586 pdu->multipart_ref = 0;
1587 pdu->multipart_count = 0;
1588 pdu->multipart_index = 0;
1591 if (pdu->TP_DCS == GSM_7BIT) {
1592 // 7-bit
1593 len = (tmp - tmp/8)*2;
1594 if (!gsmd_sim_convert(src,buf,len,&dst_length,0))
1595 return FALSE;
1597 gsmd_sim_decode_7bits (buf, pdu->TP_UD, dst_length); //TP-DU
1599 //If it's multipart, remove its header
1600 if (div > 0) {
1601 memmove(pdu->TP_UD,&pdu->TP_UD[div],tmp-div);
1602 memset(&pdu->TP_UD[tmp-div],0,div);
1605 dst_length = tmp;
1606 pdu->TP_UD_LEN = dst_length;
1607 return TRUE;
1609 } else if (pdu->TP_DCS == GSM_UCS2) {
1610 // UCS2
1611 len = tmp*2;
1612 if (!gsmd_sim_convert(src,buf,len,&dst_length,0))
1613 return FALSE;
1614 memset (pdu->TP_UD, 0, sizeof(pdu->TP_UD));
1615 memcpy (pdu->TP_UD, buf, dst_length);
1616 pdu->TP_UD_LEN = dst_length;
1617 return TRUE;
1619 } else {
1620 // 8-bit
1621 g_warning("Not supported format");
1622 return FALSE;
1625 return FALSE;
1628 static gboolean sim_decoder_pdu_userdata_normalize( guchar **src, SmsParam *pdu)
1630 gchar code_buffer[161];
1631 guchar* q;
1632 gint i;
1633 gchar temp;
1634 glong write_bytes;
1635 GError* error;
1636 glong read_words;
1638 pdu->number = g_strdup((gchar*)pdu->TPA);
1640 if (!pdu->storing) {
1641 pdu->timestamp = gsmd_utils_convert_to_timestamp((gchar*)pdu->TP_SCTS);
1642 } else {
1643 pdu->timestamp = 0;
1647 if (pdu->TP_DCS == GSM_7BIT) {
1648 pdu->message = g_strdup((gchar*)pdu->TP_UD);
1649 } else if (pdu->TP_DCS == GSM_UCS2) {
1650 //covert it to UTF8
1651 memset (code_buffer, 0, sizeof(code_buffer));
1653 * The intel CPU is little-endian, but the ucs2 in sms
1654 * is big-endian, so the usc_string byte order need to
1655 * be converted
1656 * For example chinese hello in utf16 is 4F60 597D
1657 * but usc_string is 604F 7D59
1658 * Following while() is to convert the byte order
1660 q = pdu->TP_UD;
1661 for (i=0; i < pdu->TP_UD_LEN; i += 2) {
1662 temp = *q;
1663 *q = *(q+1);
1664 *(q+1) = temp;
1665 q += 2;
1668 pdu->message = g_strdup(g_utf16_to_utf8 ((gunichar2*)pdu->TP_UD,
1670 ,&read_words,
1671 &write_bytes,
1672 &error));
1673 } else {
1674 return FALSE;
1677 return TRUE;
1681 * @brief Pdu decoder
1683 * @param src string to decode
1684 * @param pdu sms parameters
1685 * @return true if pdu was succesfully decoded
1687 static gboolean gsmd_sim_decoder_pdu (guchar* src,SmsParam* pdu)
1689 g_debug("%s : %s",__func__,src);
1692 if (!sim_decoder_pdu_header(&src,pdu))
1693 return FALSE;
1694 if (!sim_decoder_pdu_type(&src,pdu))
1695 return FALSE;
1696 if (!sim_decoder_pdu_sender_num(&src,pdu))
1697 return FALSE;
1698 if (!sim_decoder_pdu_protocol(&src,pdu))
1699 return FALSE;
1700 if (!sim_decoder_pdu_coding_scheme(&src,pdu))
1701 return FALSE;
1702 if (!sim_decoder_pdu_validity_period(&src,pdu))
1703 return FALSE;
1704 if (!sim_decoder_pdu_timestamp(&src,pdu))
1705 return FALSE;
1706 if (!sim_decoder_pdu_userdata(&src,pdu))
1707 return FALSE;
1708 return sim_decoder_pdu_userdata_normalize(&src,pdu);
1712 * @brief Removes the trailing \r\n from input stream
1714 * @param input input to modify
1715 * @return modified string
1717 static guchar* gsmd_sim_get_sms_body (GString* input)
1719 gchar *s = g_strdup(input->str);
1720 g_strstrip(s);
1721 g_string_truncate(input, 0);
1722 g_string_append(input,s);
1723 g_free( s );
1724 return (guchar*)input->str;
1729 static void gsmd_sim_command_list_messages (SIMInterface *sim,
1730 gpointer ipc_data,
1731 const gchar *status)
1733 ModemInterface *modem = (ModemInterface*)sim->priv;
1734 g_debug("%s: Listing messages with status %s",__func__,status);
1735 gchar *valid[] = {"new","read","sending","sent","all"};
1736 gint i=0;
1737 GHashTable *data = gsmd_utils_create_hash_table();
1739 GArray *list = g_array_new(FALSE,TRUE,sizeof(int));
1740 gsmd_utils_table_insert_pointer(data,GSMD_SIM_KEY_MESSAGE_LIST,list);
1741 GString *param = g_string_new("");
1744 for (i=0;i<5;i++) {
1745 if (g_str_equal(status,valid[i])) {
1746 g_string_printf(param,"%d",i);
1747 gsmd_modem_post_at_command_id( modem,
1748 SMS_LIST,
1749 param->str,
1750 ipc_data,
1751 (ErrorFunction)modem->sim_ipc->list_messages_error,
1752 (gpointer)modem->sim_ipc,
1753 INTERFACE_SIM,
1754 data);
1755 g_string_free(param,TRUE);
1756 return;
1760 g_string_free(param,TRUE);
1761 g_array_free(list,TRUE);
1762 g_hash_table_destroy(data);
1763 GError *error = g_error_new(GSMD_ERROR,
1764 GSMD_ERROR_UNKNOWN,
1765 "INVALID SMS STATUS");
1767 modem->sim_ipc->list_messages_error(ipc_data,
1768 modem->sim_ipc,
1769 error);
1771 g_error_free(error);
1775 * @brief Creates the at command to delete a sms message.
1777 * @param modem modem whose sms to delete
1778 * @param pos sms message's index
1780 static void gsmd_sim_command_delete (SIMInterface *sim,
1781 gpointer ipc_data,
1782 gint pos)
1784 ModemInterface *modem = (ModemInterface*)sim->priv;
1785 gchar *pos_str = g_strdup_printf ("%d", pos);
1786 gsmd_modem_post_at_command_id( modem,
1787 SMS_DELETE,
1788 pos_str,
1789 ipc_data,
1790 (ErrorFunction)modem->sim_ipc->delete_message_error,
1791 (gpointer)modem->sim_ipc,
1792 INTERFACE_SIM,
1793 NULL);
1794 g_free (pos_str);
1798 * @brief Sends a sms from database
1800 * Fetches specified sms from the database, prepares it for sending and
1801 * calls gsmd_sms_command_send to actually send the message.
1803 * @param modem modem whose message to send
1804 * @param msgid id of the mssage to send
1806 void gsmd_sim_command_send_message (SIMInterface *sim,
1807 gpointer ipc_data,
1808 gint index,
1809 gboolean want_report)
1811 //TODO want_report is currently ignored
1812 ModemInterface *modem = (ModemInterface*)sim->priv;
1813 GString* message = g_string_new ("");
1814 g_string_printf(message, "%d",index);
1816 gsmd_modem_post_at_command_id( modem,
1817 SIM_SEND,
1818 message->str,
1819 ipc_data,
1820 (ErrorFunction)modem->sim_ipc->send_message_error,
1821 (gpointer)modem->sim_ipc,
1822 INTERFACE_SIM,
1823 NULL);
1824 g_string_free(message,TRUE);
1828 * @brief Free function for retrieve_message method
1830 * @param at at command context which contents should be freed
1832 static void gsmd_sms_handler_read_free(AtCommandContext *at)
1834 g_debug("%s",__func__);
1835 GValue *val = g_hash_table_lookup(at->handler_data,
1836 GSMD_SIM_KEY_PDU_MULTIPART_LIST);
1838 if (!val)
1839 return;
1841 GList *list = g_value_get_pointer(val);
1842 if (!list)
1843 return;
1845 GList *iter = list;
1846 while (iter) {
1847 multipart_sms *sms = iter->data;
1848 if (sms) {
1849 g_free(sms->message);
1850 g_free(sms);
1852 iter = g_list_next(iter);
1855 g_hash_table_remove(at->handler_data,
1856 GSMD_SIM_KEY_PDU_MULTIPART_LIST);
1858 g_list_free(list);
1864 * @brief Gets message part's contents from given index
1866 * Finds given index in glist containing multipart_sms and
1867 * returns it's message, NULL if not found.
1869 * @param list list containing multipart_sms
1870 * @param index index to find
1871 * @return message contents or null if not found
1873 gchar *gsmd_sim_handler_read_assemble_get_index(GList *list,gint index)
1875 while (list) {
1876 multipart_sms *sms = list->data;
1877 if (sms && sms->multipart_index == index)
1878 return sms->message;
1879 list = g_list_next(list);
1882 return NULL;
1886 * @brief Gets the count of messages to assemble
1888 * Gets the first multipart_sms from glist and returns it's
1889 * multipart_count
1890 * @param list GList containing multipart_sms
1891 * @return messages in to assemble
1893 gint gsmd_sim_handler_read_assemble_get_count(GList *list)
1895 if (!list)
1896 return -1;
1898 multipart_sms *sms = list->data;
1899 if (!sms)
1900 return -1;
1902 return sms->multipart_count;
1907 * @brief Assemble multipart messages
1909 * Once all multipart messages are retrieved with AT+CMGL=4
1910 * this function assembles those messages together and sends
1911 * ipc reply
1912 * @param modem pointer to modem interface
1913 * @param at at command context
1914 * @return handler status
1916 AtCommandHandlerStatus gsmd_sim_handler_read_assemble(ModemInterface *modem,
1917 AtCommandContext *at)
1919 GList *list = gsmd_utils_table_get_pointer(at->handler_data,
1920 GSMD_SIM_KEY_PDU_MULTIPART_LIST,
1921 NULL);
1923 if (!list) {
1924 gsmd_utils_send_error(at,
1925 GSMD_ERROR_UNKNOWN,
1926 "INVALID HANDLER DATA");
1927 return AT_HANDLER_DONE_ERROR;
1930 gint count = gsmd_sim_handler_read_assemble_get_count(list);
1932 if (count < 2) {
1933 gsmd_utils_send_error(at,
1934 GSMD_ERROR_UNKNOWN,
1935 "INVALID HANDLER DATA");
1936 return AT_HANDLER_DONE_ERROR;
1939 GString *result = g_string_new("");
1940 gint i=1;
1942 for (i=1;i<=count;i++) {
1943 gchar *part = gsmd_sim_handler_read_assemble_get_index(list,i);
1944 if (part) {
1945 g_string_append(result,part);
1946 } else {
1947 g_string_append_printf(result,"<Message %d/%d missing>",i,count);
1951 g_debug("%s : Assembled message is '%s'",__func__,result->str);
1953 modem->sim_ipc->retrieve_message_reply(modem->sim_ipc,
1954 at->ipc_data,
1955 gsmd_utils_table_get_string(at->handler_data,
1956 GSMD_SIM_KEY_NUMBER,
1957 ""),
1958 result->str,
1959 gsmd_utils_table_get_int(at->handler_data,
1960 GSMD_SIM_KEY_TIMESTAMP,
1961 0));
1963 g_string_free(result,TRUE);
1965 return AT_HANDLER_DONE;
1970 * @brief Checks if given pdu is multipart and part of message we are assembling
1971 * and adds it to at->handler_data if it is.
1973 * @param modem pointer to modem interface
1974 * @param at at command context
1975 * @param pdu of the message to check
1976 * @return handler status
1978 AtCommandHandlerStatus gsmd_sim_handler_read_check_pdu(ModemInterface *modem,
1979 AtCommandContext *at,
1980 gchar *pdu)
1982 g_debug("%s",__func__);
1983 SmsParam *sms = g_try_new0(SmsParam,1);
1985 if (!gsmd_sim_decoder_pdu((guchar*)pdu,sms)) {
1986 gsmd_sms_sms_param_free(sms);
1987 return AT_HANDLER_DONT_UNDERSTAND;
1990 if (!sms->multipart) {
1991 gsmd_sms_sms_param_free(sms);
1992 return AT_HANDLER_NEED_MORE;
1996 gint ref = gsmd_utils_table_get_int(at->handler_data,
1997 GSMD_SIM_KEY_PDU_MULTIPART_REF,
2000 if (sms->multipart_ref != ref) {
2001 g_debug("%s : got multipart ref %d, wanted %d",
2002 __func__,
2003 sms->multipart_ref,
2004 ref);
2006 gsmd_sms_sms_param_free(sms);
2007 return AT_HANDLER_NEED_MORE;
2012 GList *list = gsmd_utils_table_get_pointer(at->handler_data,
2013 GSMD_SIM_KEY_PDU_MULTIPART_LIST,
2014 NULL);
2016 multipart_sms *part = g_try_new0(multipart_sms,1);
2017 part->multipart_count = sms->multipart_count;
2018 part->multipart_index = sms->multipart_index;
2019 part->multipart_ref = sms->multipart_ref;
2020 part->message = g_strdup(sms->message);
2022 g_debug("%s : Got part %d/%d of multipart message : '%s'",
2023 __func__,
2024 part->multipart_index,
2025 part->multipart_count,
2026 part->message);
2028 list = g_list_append(list,part);
2030 gsmd_utils_table_insert_pointer(at->handler_data,
2031 GSMD_SIM_KEY_PDU_MULTIPART_LIST,
2032 list);
2033 gsmd_sms_sms_param_free(sms);
2034 return AT_HANDLER_NEED_MORE;
2038 * @brief Handler to find multipart message's each part
2040 * When retrieving a multipart message, all parts must be retrieved
2041 * so at+cmgl=4 is sent to modem to list all messages. This function
2042 * Finds all of the messages parts, assembles then and sends the
2043 * ipc response.
2045 * @param modem pointer to modem interface
2046 * @param at command context
2047 * @param response from modem
2048 * @return handler status
2050 AtCommandHandlerStatus gsmd_sim_handler_read_list (ModemInterface *modem,
2051 AtCommandContext *at,
2052 GString *response)
2054 g_debug("%s",__func__);
2056 at+cmgl=1
2057 +CMGL: 1,1,"",145
2058 <pdu>
2059 +CMGL: 2,1,"",148
2060 <pdu>
2061 +CMGL: 3,1,"",158
2063 Regular expression:
2064 \+CMGL:\s(\d+),.*
2067 AtCommandHandlerStatus status = AT_HANDLER_DONT_UNDERSTAND;
2068 GError **error = NULL;
2069 GRegex *regex = g_regex_new ("\\+CMGL:\\s(?<id>\\d+),.*|(?<error>ERROR)|(?<ok>OK)|(?<pdu>[0-9A-F]+)", 0, 0, error);
2071 GMatchInfo *match_info;
2074 if (g_regex_match (regex, response->str, 0, &match_info)) {
2075 //Ignore +CMGL line
2076 if (gsmd_utils_match_exists(match_info,"id")) {
2077 status = AT_HANDLER_NEED_MORE;
2078 } else //If error occurs, then return error
2079 if (gsmd_utils_match_exists(match_info,"error")) {
2080 gsmd_utils_send_error(at,
2081 GSMD_ERROR_UNKNOWN,
2082 "UNABLE TO READ MESSAGE");
2083 status = AT_HANDLER_DONE_ERROR;
2084 //If we get ok, then we'll assemble the pieces
2085 //and send reply
2086 } else if (gsmd_utils_match_exists(match_info,"ok")) {
2087 status = gsmd_sim_handler_read_assemble(modem,at);
2088 } else //when we have a pdu, then check it and add to
2089 //list
2090 if (gsmd_utils_match_exists(match_info,"pdu")) {
2091 status = gsmd_sim_handler_read_check_pdu(modem,
2093 response->str);
2097 g_free(error);
2098 g_match_info_free (match_info);
2099 g_regex_unref (regex);
2102 return status;
2106 * @brief Handler for replies sent by the gsm modem when a read command is sent.
2108 * First message's pdu is returned and decoded. If it isn't a multipart message
2109 * then message's contents are sent through ipc. Otherwise the message is
2110 * assembled from it's parts.
2112 * To assemble a message all it's parts have to be found. Message has a
2113 * reference to identify it from other multipart messages. This is stored
2114 * to at->handler_data. Then AT+CMGL=4
2115 * is sent to gsm modem to list all messages. Replies to them are handled
2116 * by gsmd_sim_handler_read_list which uses gsmd_sim_handler_read_check_pdu
2117 * to check if listed message has proper reference code. If it has proper
2118 * reference code then it is added to a list in at->handler_data.
2119 * once AT+CMGL=4 is done (OK is returned) then gsmd_sim_handler_read_assemble
2120 * is called to assemble the message from list within at->handler_data.
2121 * Once message is assembled, it is sent to ipc.
2124 * @param modem pointer to modem interface
2125 * @param at at command context
2126 * @param response modem's response
2127 * @return handler status
2129 AtCommandHandlerStatus gsmd_sim_handler_read (ModemInterface *modem,
2130 AtCommandContext *at,
2131 GString *response)
2133 g_debug("%s",__func__);
2134 //Do we have pdu to parse?
2135 gboolean pdu_ready = gsmd_utils_table_get_boolean(at->handler_data,
2136 GSMD_SIM_KEY_PDU_READY,
2137 FALSE);
2139 //Is it a multipart message? Then let gsmd_sim_handler_read_list
2140 //handle AT+CMGL=4's responses
2141 if (gsmd_utils_table_get_boolean(at->handler_data,
2142 GSMD_SIM_KEY_PDU_MULTIPART_LISTING,
2143 FALSE))
2144 return gsmd_sim_handler_read_list(modem,at,response);
2147 GScanner* scanner = modem->scanner;
2148 guchar* src;
2149 GString* input_data;
2151 guint symbol;
2152 g_assert( at );
2153 symbol = scanner->token;
2155 //pdu_ready will be set when there is +CMGR
2156 if (pdu_ready) {
2159 SmsParam *pdu = g_try_new0(SmsParam,1);
2160 //decode the pdu;
2161 input_data = g_string_new (response->str);
2162 src = gsmd_sim_get_sms_body (input_data);
2164 if (!gsmd_sim_decoder_pdu (src, pdu)) {
2165 gsmd_sms_sms_param_free(pdu);
2166 return AT_HANDLER_DONT_UNDERSTAND;
2169 if (pdu->multipart) { //if it's multipart then only the first part
2170 //is a valid one from ipc's perspective
2171 //and others are invalid
2172 g_debug("%s : Got first sms of multipart message"
2173 ,__func__);
2176 if (pdu->multipart_index != 1) {
2177 gsmd_utils_send_error(at,
2178 GSMD_ERROR_UNKNOWN, //TODO change better error code
2179 "INVALID MESSAGE INDEX");
2180 gsmd_sms_sms_param_free(pdu);
2181 return AT_HANDLER_DONE_ERROR;
2182 } else {
2183 //mark handler_data that we are dealing with
2184 //multipart message and store messages reference
2185 //code
2186 gsmd_utils_table_insert_boolean(at->handler_data,
2187 GSMD_SIM_KEY_PDU_MULTIPART,
2188 TRUE);
2189 gsmd_utils_table_insert_int(at->handler_data,
2190 GSMD_SIM_KEY_PDU_MULTIPART_REF,
2191 pdu->multipart_ref);
2193 } else {
2195 //If it's normal (single) message, store the message
2196 gsmd_utils_table_insert_string(at->handler_data,
2197 GSMD_SIM_KEY_MESSAGE,
2198 pdu->message);
2201 //and store phone number and timestamp
2202 gsmd_utils_table_insert_string(at->handler_data,
2203 GSMD_SIM_KEY_NUMBER,
2204 pdu->number);
2206 gsmd_utils_table_insert_int(at->handler_data,
2207 GSMD_SIM_KEY_TIMESTAMP,
2208 pdu->timestamp);
2211 g_string_free (input_data, TRUE);
2213 gsmd_utils_table_insert_boolean(at->handler_data,
2214 GSMD_SIM_KEY_PDU_READY,
2215 FALSE);
2216 gsmd_sms_sms_param_free(pdu);
2217 return AT_HANDLER_NEED_MORE;
2220 switch (symbol) {
2221 case SYMBOL_OK: {
2222 //once we've got ok, check if the message is a multipart one
2223 //then we'll need to find the rest
2224 if (gsmd_utils_table_get_boolean(at->handler_data,
2225 GSMD_SIM_KEY_PDU_MULTIPART,
2226 FALSE)) {
2228 gsmd_utils_table_insert_boolean(at->handler_data,
2229 GSMD_SIM_KEY_PDU_MULTIPART_LISTING,
2230 TRUE);
2232 gsmd_modem_serial_write_simple( modem,
2233 "AT+CMGL=4\r\n",
2234 INTERFACE_SMS);
2235 return AT_HANDLER_NEED_MORE;
2238 GValue *msg = g_hash_table_lookup(at->handler_data,GSMD_SIM_KEY_MESSAGE);
2239 GValue *num = g_hash_table_lookup(at->handler_data,GSMD_SIM_KEY_NUMBER);
2240 GValue *time = g_hash_table_lookup(at->handler_data,GSMD_SIM_KEY_TIMESTAMP);
2241 if (!msg || !num || !time) {
2242 gsmd_utils_send_error(at,
2243 GSMD_ERROR_UNKNOWN,
2244 "INVALID HANDLER DATA");
2245 g_warning("%s : Invalid handler data, number or message missing",__func__);
2246 return AT_HANDLER_ERROR;
2249 if (modem->sim_ipc->retrieve_message_reply) {
2250 modem->sim_ipc->retrieve_message_reply(modem->sim_ipc,
2251 at->ipc_data,
2252 g_value_get_string(num),
2253 g_value_get_string(msg),
2254 g_value_get_int(time));
2257 return AT_HANDLER_DONE;
2258 case '+':
2259 g_scanner_get_next_token (scanner);
2260 if (scanner->token == SYMBOL_CMS) {
2261 g_warning ("read sms from simcard error\n");
2262 gsmd_utils_send_error(at,
2263 GSMD_ERROR_UNKNOWN,
2264 "FAILED TO READ FROM SIM CARD");
2265 return AT_HANDLER_DONE_ERROR;
2266 } else if (scanner->token == SYMBOL_CMGR) {
2268 g_scanner_get_next_token (scanner);//get :
2269 g_scanner_get_next_token (scanner);//get status
2270 //sms_status = scanner->value.v_int;
2271 gsmd_utils_table_insert_boolean(at->handler_data,
2272 GSMD_SIM_KEY_PDU_READY,
2273 TRUE);
2276 return AT_HANDLER_NEED_MORE;
2279 return AT_HANDLER_DONT_UNDERSTAND;
2285 * @brief Creates the at command to read a sms message
2287 * @param modem modem where to read from
2288 * @param pos index of the message to read
2290 void gsmd_sim_command_read (SIMInterface *sim,
2291 gpointer ipc_data,
2292 gint pos)
2294 gchar *pos_str = g_strdup_printf ("%d", pos);
2295 ModemInterface *modem = (ModemInterface*)sim->priv;
2296 GHashTable *data = gsmd_utils_create_hash_table();
2298 gsmd_utils_table_insert_boolean(data,
2299 GSMD_SIM_KEY_PDU_READY,
2300 FALSE);
2302 gsmd_modem_post_at_command_id( modem,
2303 SMS_READ,
2304 pos_str,
2305 ipc_data,
2306 (ErrorFunction)modem->sim_ipc->retrieve_message_error,
2307 (gpointer)modem->sim_ipc,
2308 INTERFACE_SIM,
2309 data);
2310 g_free (pos_str);
2313 /* void gsmd_sim_free_storage_spaces_array(GHashTable *table) */
2314 /* { */
2315 /* int i=0; */
2316 /* GValue *val = g_hash_table_lookup(table,GSMD_SIM_KEY_STORAGE_SPACES); */
2317 /* if (val) { */
2318 /* GArray *array = g_value_get_pointer(val); */
2320 /* for (i=0;i<array->len;i++) { */
2321 /* g_string_free(g_array_index(array, */
2322 /* GString*, */
2323 /* i), */
2324 /* TRUE); */
2325 /* } */
2326 /* g_array_free(array,TRUE); */
2329 /* } */
2330 /* } */
2332 /* static void gsmd_sim_storage_spaces_free(AtCommandContext *at) */
2333 /* { */
2334 /* gsmd_sim_free_storage_spaces_array(at->handler_data); */
2335 /* } */
2337 /* AtCommandHandlerStatus */
2338 /* gsmd_sim_handler_get_storage_spaces(ModemInterface *modem, */
2339 /* AtCommandContext *at, */
2340 /* GString *response) */
2341 /* { */
2342 /* /\* */
2343 /* AT+CPBS=? */
2345 /* +CPBS: ("SM","FD","LD","MC","RC") */
2347 /* OK */
2348 /* *\/ */
2351 /* AtCommandHandlerStatus status = AT_HANDLER_DONT_UNDERSTAND; */
2352 /* GError *error = NULL; */
2353 /* GRegex *regex = g_regex_new ("(?<cpbs>\\+CPBS:\\s\\((\"\\w+\",?)+\\))|(?<error>ERROR)|(?<ok>OK)", 0, 0, NULL); */
2354 /* GMatchInfo *match_info; */
2356 /* if (g_regex_match (regex, response->str, 0, &match_info)) { */
2357 /* if (gsmd_utils_match_exists(match_info,"cpbs")) { */
2358 /* g_free(error); */
2359 /* g_match_info_free (match_info); */
2360 /* g_regex_unref (regex); */
2361 /* error = NULL; */
2362 /* match_info = NULL; */
2365 /* regex = g_regex_new ("\"(?<id>\\w+)\"", 0, 0, NULL); */
2367 /* if (g_regex_match (regex, response->str, 0, &match_info)) { */
2368 /* GString *line = NULL; */
2371 /* GArray *array = g_array_new(FALSE, */
2372 /* TRUE, */
2373 /* sizeof(GString*)); */
2374 /* gchar *match = NULL; */
2376 /* while (g_match_info_matches (match_info)) { */
2377 /* match = g_match_info_fetch_named(match_info,"id"); */
2378 /* line = g_string_new(match); */
2379 /* g_free(match); */
2380 /* g_array_append_val(array,line); */
2381 /* g_match_info_next (match_info, NULL); */
2382 /* } */
2384 /* gsmd_utils_table_insert_pointer(at->handler_data, */
2385 /* GSMD_SIM_KEY_STORAGE_SPACES, */
2386 /* array); */
2388 /* } */
2390 /* status = AT_HANDLER_NEED_MORE; */
2392 /* } else if (gsmd_utils_match_exists(match_info,"error")) { */
2393 /* gsmd_utils_send_error(at, */
2394 /* GSMD_ERROR_UNKNOWN, */
2395 /* "FAILED TO GET STORAGE SPACES"); */
2397 /* status = AT_HANDLER_DONE_ERROR; */
2398 /* } else if (gsmd_utils_match_exists(match_info,"ok")) { */
2399 /* GValue *val = g_hash_table_lookup(at->handler_data, */
2400 /* GSMD_SIM_KEY_STORAGE_SPACES); */
2402 /* if (!val) { */
2403 /* g_warning("%s : Invalid handler data. storage spaces: %p", */
2404 /* __func__, */
2405 /* val); */
2407 /* gsmd_utils_send_error(at, */
2408 /* GSMD_ERROR_UNKNOWN, */
2409 /* "INVALID HANDLER DATA"); */
2410 /* status = AT_HANDLER_DONE_ERROR; */
2411 /* } else { */
2412 /* gsmd_sim_free_storage_spaces_array(modem->caches[INTERFACE_SIM]); */
2413 /* g_hash_table_remove(modem->caches[INTERFACE_SIM],GSMD_SIM_KEY_STORAGE_SPACES); */
2415 /* /\* modem->sim_ipc->get_storage_spaces_reply(modem->sim_ipc, *\/ */
2416 /* /\* at->ipc_data, *\/ */
2417 /* /\* g_value_get_pointer(val)); *\/ */
2418 /* gsmd_utils_table_insert_pointer(modem->caches[INTERFACE_SIM], */
2419 /* GSMD_SIM_KEY_STORAGE_SPACES, */
2420 /* g_value_get_pointer(val)); */
2421 /* g_hash_table_remove(at->handler_data,GSMD_SIM_KEY_STORAGE_SPACES); */
2422 /* status = AT_HANDLER_DONE; */
2423 /* } */
2424 /* } */
2427 /* } */
2429 /* g_free(error); */
2430 /* g_match_info_free (match_info); */
2431 /* g_regex_unref (regex); */
2434 /* return status; */
2435 /* } */
2438 /* void gsmd_sim_command_get_storage_spaces(SIMInterface *sim, */
2439 /* gpointer ipc_data) */
2440 /* { */
2441 /* ModemInterface *modem = (ModemInterface*)sim->priv; */
2442 /* GValue *val = g_hash_table_lookup(modem->caches[INTERFACE_SIM],GSMD_SIM_KEY_STORAGE_SPACES); */
2444 /* if (!modem->no_cache && val) { */
2445 /* /\* modem->sim_ipc->get_storage_spaces_reply(modem->sim_ipc, *\/ */
2446 /* /\* ipc_data, *\/ */
2447 /* /\* g_value_get_pointer(val)); *\/ */
2448 /* } else { */
2450 /* gsmd_modem_post_at_command_id( modem, */
2451 /* PHONEBOOK_SPACES_QUERY, */
2452 /* NULL, */
2453 /* ipc_data, */
2454 /* (ErrorFunction)modem->sim_ipc->get_storage_spaces_error, */
2455 /* (gpointer)modem->sim_ipc, */
2456 /* INTERFACE_SIM, */
2457 /* NULL); */
2458 /* } */
2459 /* } */
2461 AtCommandHandlerStatus gsmd_sim_handler_get_phonebook_status(ModemInterface *modem,
2462 AtCommandContext *at,
2463 GString *response)
2466 AT+CPBS?
2468 +CPBS: "SM",2,250
2472 \+CPBS:\s"(\w+)",\d+,\d+
2474 AtCommandHandlerStatus status = AT_HANDLER_DONT_UNDERSTAND;
2475 GError *error = NULL;
2476 GRegex *regex = g_regex_new ("\\+CPBS:\\s\"(?<space>\\w+)\",(?<used>\\d+),(?<total>\\d+)|"
2477 "(?<error>ERROR)|(?<ok>OK)", 0, 0, &error);
2478 GMatchInfo *match_info;
2481 if (g_regex_match (regex, response->str, 0, &match_info)) {
2482 if (gsmd_utils_match_exists(match_info,"used")) {
2483 gchar *match = g_match_info_fetch_named(match_info,"used");
2484 gint used = atoi(match);
2485 gsmd_utils_table_insert_int(at->handler_data,GSMD_SIM_KEY_PHONEBOOK_SLOTS_USED,used);
2486 g_free(match);
2488 status = AT_HANDLER_NEED_MORE;
2491 if (gsmd_utils_match_exists(match_info,"error")) {
2492 gsmd_utils_send_error(at,
2493 GSMD_ERROR_UNKNOWN,
2494 "FAILED TO GET DEFAULT PHONEBOOK STORAGE SPACE");
2495 status = AT_HANDLER_DONE_ERROR;
2498 if (gsmd_utils_match_exists(match_info,"ok")) {
2499 GValue *val = g_hash_table_lookup(at->handler_data,
2500 GSMD_SIM_KEY_PHONEBOOK_SLOTS_USED);
2501 if (!val) {
2502 g_warning("%s : Invalid handler data.", __func__);
2504 gsmd_utils_send_error(at,
2505 GSMD_ERROR_UNKNOWN,
2506 "INVALID HANDLER DATA");
2508 status = AT_HANDLER_DONE;
2513 if( error ) {
2514 g_error_free(error);
2516 g_match_info_free (match_info);
2517 g_regex_unref (regex);
2520 return status;
2524 /* AtCommandHandlerStatus gsmd_sim_handler_set_default_storage_space(ModemInterface *modem, */
2525 /* AtCommandContext *at, */
2526 /* GString *response) */
2527 /* { */
2528 /* AtCommandHandlerStatus status = AT_HANDLER_DONT_UNDERSTAND; */
2529 /* GError **error = NULL; */
2530 /* GRegex *regex = g_regex_new ("(?<error>ERROR)|(?<ok>OK)", 0, 0, error); */
2531 /* GMatchInfo *match_info; */
2534 /* if (g_regex_match (regex, response->str, 0, &match_info)) { */
2535 /* if (gsmd_utils_match_exists(match_info,"error")) { */
2536 /* gsmd_utils_send_error(at, */
2537 /* GSMD_ERROR_UNKNOWN, */
2538 /* "FAILED TO SET DEFAULT PHONEBOOK STORAGE SPACE"); */
2539 /* status = AT_HANDLER_DONE_ERROR; */
2540 /* } */
2542 /* if (gsmd_utils_match_exists(match_info,"ok")) { */
2543 /* //Since storage space changed, it's index boundaries */
2544 /* //might have changed aswell */
2545 /* gsmd_utils_table_insert_int(modem->caches[INTERFACE_SIM], */
2546 /* GSMD_SIM_KEY_LOWEST_INDEX, */
2547 /* 9999); */
2549 /* gsmd_utils_table_insert_int(modem->caches[INTERFACE_SIM], */
2550 /* GSMD_SIM_KEY_HIGHEST_INDEX, */
2551 /* -9999); */
2553 /* GValue *val = g_hash_table_lookup(at->handler_data,GSMD_SIM_KEY_DEFAULT_STORAGE_SPACE); */
2555 /* if (!val) { */
2556 /* g_warning("%s : Invalid handler data. default storage space: %p", */
2557 /* __func__, */
2558 /* val); */
2560 /* gsmd_utils_send_error(at, */
2561 /* GSMD_ERROR_UNKNOWN, */
2562 /* "INVALID HANDLER DATA"); */
2563 /* } */
2565 /* gsmd_utils_table_insert_copy(modem->caches[INTERFACE_SIM], */
2566 /* GSMD_SIM_KEY_DEFAULT_STORAGE_SPACE, */
2567 /* val); */
2569 /* modem->sim_ipc->set_default_storage_space_reply(modem->sim_ipc, */
2570 /* at->ipc_data); */
2572 /* status = AT_HANDLER_DONE; */
2573 /* } */
2575 /* } */
2577 /* g_free(error); */
2578 /* g_match_info_free (match_info); */
2579 /* g_regex_unref (regex); */
2582 /* return status; */
2583 /* } */
2586 /* void gsmd_sim_command_set_default_storage_space(SIMInterface *sim, */
2587 /* gpointer ipc_data, */
2588 /* const char *space) */
2589 /* { */
2590 /* ModemInterface *modem = (ModemInterface*)sim->priv; */
2592 /* GHashTable *data = gsmd_utils_create_hash_table(); */
2593 /* gsmd_utils_table_insert_string(data, */
2594 /* GSMD_SIM_KEY_DEFAULT_STORAGE_SPACE, */
2595 /* space); */
2597 /* gsmd_modem_post_at_command_id( modem, */
2598 /* PHONEBOOK_SPACE_SET, */
2599 /* space, */
2600 /* ipc_data, */
2601 /* (ErrorFunction)modem->sim_ipc->set_default_storage_space_error, */
2602 /* (gpointer)modem->sim_ipc, */
2603 /* INTERFACE_SIM, */
2604 /* data); */
2605 /* } */
2607 static
2608 AtCommandHandlerStatus gsmd_sim_handler_get_index_boundaries(
2609 ModemInterface *modem,
2610 AtCommandContext *at,
2611 GString *response)
2614 AT+CPBR=?
2616 +CPBR: (1-250),20,20
2620 Regular expression: \+CPBR:\s\((\d+)-(\d+)\)
2622 AtCommandHandlerStatus status = AT_HANDLER_DONT_UNDERSTAND;
2623 GError *error = NULL;
2624 GRegex *regex = g_regex_new ("\\+CPBR:\\s\\((?<min>\\d+)-(?<max>\\d+)\\),(?<number_len>\\d+),(?<name_len>\\d+)|"
2625 "(?<error>ERROR)|(?<ok>OK)", 0, 0, &error);
2626 GMatchInfo *match_info;
2627 gchar *match = NULL;
2631 if (g_regex_match (regex, response->str, 0, &match_info)) {
2632 if (gsmd_utils_match_exists(match_info,"min")) {
2633 match = g_match_info_fetch_named(match_info,"min");
2634 gint min = atoi(match);
2635 g_free(match);
2637 match = g_match_info_fetch_named(match_info,"max");
2638 gint max = atoi(match);
2639 gsmd_utils_table_insert_int(at->handler_data,GSMD_SIM_KEY_PHONEBOOK_SLOTS, max-min+1);
2640 g_free(match);
2642 match = g_match_info_fetch_named(match_info,"number_len");
2643 gint number_len = atoi(match);
2644 gsmd_utils_table_insert_int(at->handler_data,GSMD_SIM_KEY_PHONEBOOK_NUMBER_LEN, number_len);
2645 g_free(match);
2647 match = g_match_info_fetch_named(match_info,"name_len");
2648 gint name_len = atoi(match);
2649 gsmd_utils_table_insert_int(at->handler_data,GSMD_SIM_KEY_PHONEBOOK_NAME_LEN, name_len);
2650 g_free(match);
2652 status = AT_HANDLER_NEED_MORE;
2653 } else if (gsmd_utils_match_exists(match_info,"error")) {
2654 //TODO should empty string be sent as a reply instead?
2655 gsmd_utils_send_error(at,
2656 GSMD_ERROR_UNKNOWN,
2657 "UNABLE TO READ PHONEBOOK INFO");
2658 status = AT_HANDLER_DONE_ERROR;
2659 } else if (gsmd_utils_match_exists(match_info,"ok")) {
2660 GValue *slots = g_hash_table_lookup(at->handler_data,GSMD_SIM_KEY_PHONEBOOK_SLOTS);
2661 GValue *number_len = g_hash_table_lookup(at->handler_data,GSMD_SIM_KEY_PHONEBOOK_NUMBER_LEN);
2662 GValue *name_len = g_hash_table_lookup(at->handler_data,GSMD_SIM_KEY_PHONEBOOK_NAME_LEN);
2664 if (!slots || !number_len || !name_len) {
2665 g_warning("%s : Invalid handler data. slots: %p, number_len: %p, name_len: %p",
2666 __func__, slots, number_len, name_len);
2668 gsmd_utils_send_error(at,
2669 GSMD_ERROR_UNKNOWN,
2670 "INVALID HANDLER DATA");
2671 status = AT_HANDLER_DONE_ERROR;
2672 } else {
2673 status = AT_HANDLER_DONE;
2679 if( error ) {
2680 g_error_free(error);
2682 g_match_info_free (match_info);
2683 g_regex_unref (regex);
2686 return status;
2690 AtCommandHandlerStatus gsmd_sim_handler_delete_entry(ModemInterface *modem,
2691 AtCommandContext *at,
2692 GString *response)
2694 AtCommandHandlerStatus status = AT_HANDLER_DONT_UNDERSTAND;
2695 GError **error = NULL;
2696 GRegex *regex = g_regex_new ("(?<error>ERROR)|(?<ok>OK)", 0, 0, error);
2697 GMatchInfo *match_info;
2700 if (g_regex_match (regex, response->str, 0, &match_info)) {
2701 if (gsmd_utils_match_exists(match_info,"error")) {
2702 gsmd_utils_send_error(at,
2703 GSMD_ERROR_UNKNOWN,
2704 "FAILED TO DELETE PHONEBOOK ENTRY");
2705 status = AT_HANDLER_DONE_ERROR;
2708 if (gsmd_utils_match_exists(match_info,"ok")) {
2709 modem->sim_ipc->delete_entry_reply(modem->sim_ipc,
2710 at->ipc_data);
2711 status = AT_HANDLER_DONE;
2716 g_free(error);
2717 g_match_info_free (match_info);
2718 g_regex_unref (regex);
2721 return status;
2724 void gsmd_sim_command_delete_entry(SIMInterface *sim,
2725 gpointer ipc_data,
2726 const int index)
2728 GString* message = g_string_new ("");
2729 g_string_printf(message, "%d",index);
2731 ModemInterface *modem = (ModemInterface*)sim->priv;
2732 gsmd_modem_post_at_command_id( modem,
2733 PHONEBOOK_ENTRY_DELETE,
2734 message->str,
2735 ipc_data,
2736 (ErrorFunction)modem->sim_ipc->delete_entry_error,
2737 (gpointer)modem->sim_ipc,
2738 INTERFACE_SIM,
2739 NULL);
2740 g_string_free(message,TRUE);
2745 AtCommandHandlerStatus gsmd_sim_handler_store_entry(
2746 ModemInterface *modem,
2747 AtCommandContext *at,
2748 GString *response)
2751 AT+CPBW=2,+35844123456789,145,Name
2756 AtCommandHandlerStatus status = AT_HANDLER_DONT_UNDERSTAND;
2757 GError **error = NULL;
2758 GRegex *regex = g_regex_new ("(?<error>ERROR)|(?<ok>OK)", 0, 0, error);
2759 GMatchInfo *match_info;
2762 if (g_regex_match (regex, response->str, 0, &match_info)) {
2763 if (gsmd_utils_match_exists(match_info,"error")) {
2764 gsmd_utils_send_error(at,
2765 GSMD_ERROR_UNKNOWN,
2766 "FAILED TO STORE PHONEBOOK ENTRY");
2767 status = AT_HANDLER_DONE_ERROR;
2770 if (gsmd_utils_match_exists(match_info,"ok")) {
2771 modem->sim_ipc->store_entry_reply(modem->sim_ipc,
2772 at->ipc_data);
2773 status = AT_HANDLER_DONE;
2778 g_free(error);
2779 g_match_info_free (match_info);
2780 g_regex_unref (regex);
2783 return status;
2789 void gsmd_sim_command_store_entry(SIMInterface *sim,
2790 gpointer ipc_data,
2791 const int index,
2792 const char *name,
2793 const char *number)
2795 GString* message = g_string_new ("");
2796 // TODO Better number checks
2797 if(*number == '+') {
2798 g_string_printf(message, "%d,%s,145,%s",index,number,name);
2799 } else {
2800 g_string_printf(message, "%d,%s,129,%s",index,number,name);
2803 ModemInterface *modem = (ModemInterface*)sim->priv;
2804 gsmd_modem_post_at_command_id( modem,
2805 PHONEBOOK_ENTRY_SET,
2806 message->str,
2807 ipc_data,
2808 (ErrorFunction)modem->sim_ipc->store_entry_error,
2809 (gpointer)modem->sim_ipc,
2810 INTERFACE_SIM,
2811 NULL);
2812 g_string_free(message,TRUE);
2816 AtCommandHandlerStatus gsmd_sim_handler_retrieve_entry(ModemInterface *modem,
2817 AtCommandContext *at,
2818 GString *response)
2821 AT+CPBR=1
2823 +CPBR: 1,"040123456789",129,"Name"
2827 Regular expression: \+CPBR:\s(\d+),"(\w+)",(\d+),"(\w+)"
2829 AtCommandHandlerStatus status = AT_HANDLER_DONT_UNDERSTAND;
2830 GError **error = NULL;
2831 GRegex *regex = g_regex_new ("\\+CPBR:\\s(?<id>\\d)+,\"(?<number>\\+?\\w+)\",(?<type>\\d+),\"(?<text>\\w+)\"|(?<error>ERROR)|(?<ok>OK)", 0, 0, error);
2833 GMatchInfo *match_info;
2836 if (g_regex_match (regex, response->str, 0, &match_info)) {
2837 if (gsmd_utils_match_exists(match_info,"id")) {
2839 gchar *type = g_match_info_fetch_named(match_info,"type");
2840 gchar *name = g_match_info_fetch_named(match_info,"text");
2841 gchar *number = g_match_info_fetch_named(match_info,"number");
2843 //TODO only send this once we have ok
2844 modem->sim_ipc->retrieve_entry_reply(modem->sim_ipc,
2845 at->ipc_data,
2846 name,
2847 number);
2848 g_free(type);
2849 g_free(name);
2850 g_free(number);
2852 status = AT_HANDLER_NEED_MORE;
2855 if (gsmd_utils_match_exists(match_info,"error")) {
2856 //TODO should empty string be sent as a reply instead?
2857 gsmd_utils_send_error(at,
2858 GSMD_ERROR_UNKNOWN,
2859 "UNABLE TO READ PHONEBOOK INDEX BOUNDARIES");
2860 status = AT_HANDLER_DONE_ERROR;
2863 if (gsmd_utils_match_exists(match_info,"ok")) {
2864 status = AT_HANDLER_DONE;
2869 g_free(error);
2870 g_match_info_free (match_info);
2871 g_regex_unref (regex);
2874 return status;
2879 void gsmd_sim_command_retrieve_entry(SIMInterface *sim,
2880 gpointer ipc_data,
2881 const int index)
2883 GString* message = g_string_new ("");
2884 g_string_printf(message, "%d",index);
2886 ModemInterface *modem = (ModemInterface*)sim->priv;
2887 gsmd_modem_post_at_command_id( modem,
2888 PHONEBOOK_ENTRY_GET,
2889 message->str,
2890 ipc_data,
2891 (ErrorFunction)modem->sim_ipc->retrieve_entry_error,
2892 (gpointer)modem->sim_ipc,
2893 INTERFACE_SIM,
2894 NULL);
2895 g_string_free(message,TRUE);
2899 void gsmd_sim_init(ModemInterface *modem)
2901 modem->sim->priv = (gpointer)modem;
2902 modem->sim->send_auth_code = &gsmd_sim_command_setup_pin;
2903 modem->sim->get_auth_status = &gsmd_sim_command_query_pin_status;
2904 modem->sim->get_sim_info = &gsmd_sim_command_get_sim_info;
2905 modem->sim->change_auth_code = &gsmd_sim_command_change_auth_code;
2906 modem->sim->unlock = &gsmd_sim_command_unlock;
2907 modem->sim->list_messages = &gsmd_sim_command_list_messages;
2908 modem->sim->send_message = &gsmd_sim_command_send_message;
2909 modem->sim->delete_message = &gsmd_sim_command_delete;
2910 modem->sim->set_service_center_number = &gsmd_sim_command_set_service_center;
2911 modem->sim->get_service_center_number = &gsmd_sim_command_query_service_center;
2912 modem->sim->store_message = &gsmd_sim_command_store_message;
2913 modem->sim->retrieve_message = &gsmd_sim_command_read;
2914 modem->sim->retrieve_entry = &gsmd_sim_command_retrieve_entry;
2915 modem->sim->store_entry = &gsmd_sim_command_store_entry;
2916 modem->sim->delete_entry = &gsmd_sim_command_delete_entry;
2917 modem->sim->get_phonebook_info = &gsmd_sim_command_get_phonebook_info;
2918 gsmd_sim_init_at_handler(modem);
2922 void gsmd_sim_deinitialize(ModemInterface *modem)