Fixed typo in error message.
[gsmd2.git] / src / sim.c
blobf162b25a398feef247ceffab7d8b3615d2eb63f3
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_retrieve_messagebook (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_handler_retrieve_messagebook_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[]
137 //Query pin status
138 { PIN_QUERY, "AT+CPIN?\r\n", 20000,
139 TRUE, 0,
140 gsmd_sim_handler_query_pin_status, NULL, SIM_UNKNOWN, NULL},
141 //Query subscriber numbers
142 { QUERY_SUBSCRIBER_NUMBERS, "AT+CNUM\r\n", 20000,
143 TRUE, 0,
144 gsmd_sim_handler_get_subscriber_numbers, NULL, SIM_UNKNOWN, NULL},
146 //Setup pin
147 { PIN_SETUP, "AT+CPIN=\"%s\"\r\n", 20000,
148 FALSE, 0,
149 gsmd_sim_handler_pin, NULL, SIM_UNKNOWN, NULL},
151 //Change pin
152 { PIN_CHANGE, "AT+CPIN=%s\r\n", 20000,
153 FALSE, 0,
154 gsmd_sim_handler_pin, NULL, SIM_UNKNOWN, NULL},
156 //Setup puk
157 { PUK_SETUP, "AT+CPIN=%s\r\n", 20000,
158 FALSE, 0,
159 gsmd_sim_handler_pin, NULL, SIM_UNKNOWN, NULL},
161 //Get IMSI
162 { IMSI_QUERY, "AT+CIMI\r\n", 5000,
163 FALSE, 0,
164 gsmd_sim_handler_query_imsi, NULL, SIM_READY},
165 //Read sms
166 { SMS_READ, "AT+CMGR=%s\r\n", 5000,
167 FALSE, 0,
168 gsmd_sim_handler_read, NULL, SIM_READY, gsmd_sms_handler_read_free},
170 //Delete sms
171 { SMS_DELETE, "AT+CMGD=%s\r\n", 5000,
172 FALSE, 0,
173 gsmd_sim_handler_delete, NULL, SIM_READY, NULL},
175 //Query sms service center
176 { SMS_CENTER_QUERY, "AT+CSCA?\r\n", 20000,
177 TRUE, 0,
178 gsmd_sim_handler_query_service_center, NULL, SIM_READY, NULL},
180 //Set sms service center
181 { SMS_SET_CENTER, "AT+CSCA=%s\r\n", 20000,
182 TRUE, 0,
183 gsmd_sim_handler_set_service_center, NULL, SIM_READY, NULL},
185 //List messages
186 { SMS_LIST, "AT+CMGL=%s\r\n", 30000,
187 FALSE, 0, gsmd_sim_handler_retrieve_messagebook,
188 NULL, SIM_READY,gsmd_sim_handler_retrieve_messagebook_free},
190 //Send message from storage
191 { SIM_SEND, "AT+CMSS=%s\r\n", 30000,
192 FALSE, 0, gsmd_sim_handler_send_message,
193 NULL, SIM_READY,NULL},
195 //Get available storage space
196 /* { PHONEBOOK_SPACES_QUERY, "AT+CPBS=?\r\n", 100, */
197 /* FALSE, 0, */
198 /* gsmd_sim_handler_get_storage_spaces, NULL, SIM_READY, */
199 /* gsmd_sim_storage_spaces_free}, */
201 //Get current storage space status
202 { PHONEBOOK_STATUS_QUERY, "AT+CPBS?\r\n", 100,
203 FALSE, 0,
204 gsmd_sim_handler_get_phonebook_status, NULL, SIM_READY,
205 NULL},
207 //Set storage space
208 /* { PHONEBOOK_SPACE_SET, "AT+CPBS=%s\r\n", 100, */
209 /* FALSE, 0, */
210 /* gsmd_sim_handler_set_default_storage_space, NULL, SIM_READY, */
211 /* NULL}, */
213 //Get storage item's index boundaries
214 { PHONEBOOK_GET_INDEX_BOUNDARIES, "AT+CPBR=?\r\n", 100,
215 FALSE, 0,
216 gsmd_sim_handler_get_index_boundaries, NULL, SIM_READY, NULL},
218 //Get entry from storage
219 { PHONEBOOK_ENTRY_GET, "AT+CPBR=%s\r\n", 100,
220 FALSE, 0,
221 gsmd_sim_handler_retrieve_entry, NULL, SIM_READY, NULL},
223 //Set storage entry
224 { PHONEBOOK_ENTRY_SET, "AT+CPBW=%s\r\n", 100,
225 FALSE, 0,
226 gsmd_sim_handler_store_entry, NULL, SIM_READY, NULL},
228 //Delete storage entry
229 { PHONEBOOK_ENTRY_DELETE, "AT+CPBW=%s\r\n", 100,
230 FALSE, 0,
231 gsmd_sim_handler_delete_entry, NULL, SIM_READY, NULL},
233 { 0, NULL, 100, TRUE, 1,
234 NULL, NULL, SIM_UNKNOWN },
236 }, *sim_command_p = sim_commands;
238 static const SymbolTable
239 sim_symbols[] =
241 { "SIM", SYMBOL_SIM, },
242 { NULL, 0, },
243 }, *sim_symbol_p = sim_symbols;
244 void gsmd_sim_init_at_handler(ModemInterface* modem)
246 while (sim_symbol_p->symbol_name)
248 g_scanner_add_symbol (modem->scanner, sim_symbol_p->symbol_name,
249 GINT_TO_POINTER(sim_symbol_p->symbol_token));
250 sim_symbol_p++;
252 while (sim_command_p->command)
254 gsmd_modem_register_command (modem,sim_command_p);
255 sim_command_p++;
259 * @brief Changes auth (pin) status, sends auth_status signal if
260 * status was changed.
262 * @param modem modem whose auth status to change
263 * @param status new pin status
264 * @param send_reply should reply to get_auth_status ipc method
265 * be sent aswll
267 void gsmd_sim_change_auth_status( ModemInterface *modem,
268 gpointer ipc_data,
269 SIMStatus status,
270 const gchar *message,
271 gboolean send_reply)
273 if ( status != modem->sim_status )
275 g_debug("Changing auth status from %d to %d.",modem->sim_status, status);
279 gsmd_utils_table_insert_string(modem->caches[INTERFACE_SIM],
280 GSMD_SIM_KEY_AUTH_STATUS,
281 message);
285 //Send a reply to get auth_status ipc method if necessary
286 if (send_reply && modem->sim_ipc->get_auth_status_reply && ipc_data)
287 modem->sim_ipc->get_auth_status_reply(modem->sim_ipc,
288 ipc_data,
289 message);
291 //If sim status has changed, send a signal
292 if (modem->sim_ipc->auth_status && status != modem->sim_status)
294 modem->sim_ipc->auth_status(modem->sim_ipc,
295 message);
298 //finally change modem's sim status
299 gsmd_modem_change_sim_status(modem,status);
305 * Sends a reply to all pin related ipc method calls
307 * @param modem modem pointer
308 * @param cmd_id command/method call id
310 void gsmd_sim_send_pin_reply(ModemInterface *modem, AtCommandContext *at)
312 switch (at->command->cmd_id)
314 case PIN_SETUP:
315 modem->sim_ipc->send_auth_code_reply(modem->sim_ipc,at->ipc_data);
316 break;
317 case PIN_CHANGE:
318 modem->sim_ipc->change_auth_code_reply(modem->sim_ipc,at->ipc_data);
319 break;
320 case PUK_SETUP:
321 modem->sim_ipc->unlock_reply(modem->sim_ipc,at->ipc_data);
322 break;
327 * @brief Free's messagebook entry
328 * @param msg entry to free
330 void gsmd_sim_handler_retrieve_messagebook_free_entry(messagebook_msg *msg)
332 if (msg->status)
333 g_string_free(msg->status,TRUE);
334 if (msg->number)
335 g_string_free(msg->number,TRUE);
336 if (msg->content)
337 g_string_free(msg->content,TRUE);
338 g_free(msg);
342 * @brief Free's the whole messagebook
343 * @param at AtCommandContext context containing the messagebook to free
345 void gsmd_sim_handler_retrieve_messagebook_free (AtCommandContext *at)
347 GValue *val = g_hash_table_lookup(at->handler_data,
348 GSMD_SIM_KEY_MESSAGE_BOOK);
349 GArray *list = g_value_get_pointer(val);
350 if (list)
352 gint i=0;
354 for (i=0;i<list->len;i++)
356 messagebook_msg *msg = g_array_index(list,messagebook_msg*,i);
357 gsmd_sim_handler_retrieve_messagebook_free_entry(msg);
359 g_array_free(list,TRUE);
364 * @brief Removes last message from the list
365 * @param table table containing a list of messages
367 static gboolean gsmd_sim_handler_retrieve_messagebook_remove_last(GHashTable *table)
369 g_debug("%s",__func__);
370 GValue *val = g_hash_table_lookup(table,GSMD_SIM_KEY_MESSAGE_BOOK);
371 if (!val)
372 return FALSE;
374 GArray *list = g_value_get_pointer(val);
376 if (!list)
377 return FALSE;
379 messagebook_msg *msg = g_array_index(list,messagebook_msg*,list->len-1);
380 gsmd_sim_handler_retrieve_messagebook_free_entry(msg);
381 g_array_remove_index(list,list->len-1);
383 return TRUE;
387 * @brief Fills details from SMSParam to last entry in messagebook list in garray
388 * When parsing output from cmgl (list sms messages command) messages are listed
389 * index first, contents second. Parser function that collects all messages
390 * first adds a new entry to a list with the index. When parser receives message's
391 * contents (pdu) it calls this function to add (or append) contents to the message.
393 * @param sms parsed pdu to set as last message's contents
394 * @param handler_data GHashTable that contains a list of messages
395 * @param append should this message's contents be only applied to last message
397 static gboolean gsmd_sim_handler_retrieve_messagebook_fill_last_message(SmsParam *sms,
398 GHashTable *handler_data,
399 gboolean append)
401 if (!sms || !handler_data)
402 return FALSE;
404 g_debug("%s",__func__);
405 GValue *val = g_hash_table_lookup(handler_data,GSMD_SIM_KEY_MESSAGE_BOOK);
406 if (!val)
407 return FALSE;
409 GArray *list = g_value_get_pointer(val);
411 if (!list)
412 return FALSE;
414 messagebook_msg *msg = g_array_index(list,messagebook_msg*,list->len-1);
416 if (append)
418 g_string_append_len(msg->content,(gchar*)sms->TP_UD, (gint)sms->TP_UD_LEN);
419 return TRUE;
422 msg->status = g_string_new(gsmd_utils_table_get_string(handler_data,
423 GSMD_SIM_KEY_MESSAGE_BOOK_TYPE,
424 NULL));
426 msg->number = g_string_new((gchar*)sms->TPA);
427 msg->content = g_string_new_len((gchar*)sms->TPA,sms->TP_UD_LEN);
429 return TRUE;
433 AtCommandHandlerStatus gsmd_sim_handler_retrieve_messagebook (ModemInterface *modem,
434 AtCommandContext *at,
435 GString *response)
438 at+cmgl=1
439 +CMGL: 1,1,"",145
440 <pdu>
441 +CMGL: 2,1,"",148
442 <pdu>
443 +CMGL: 3,1,"",158
445 Regular expression:
446 \+CMGL:\s(\d+),.*
449 AtCommandHandlerStatus status = AT_HANDLER_DONT_UNDERSTAND;
450 gint cms_code = 0;
451 if ( gsmd_utils_parse_cms_error(response,&cms_code) )
453 switch ( cms_code )
455 case CMS_ERROR_INVALID_MESSAGE_INDEX:
458 * At least on Neo 1973 this means that there
459 * are no message with given status
461 GValue *val = g_hash_table_lookup(at->handler_data,
462 GSMD_SIM_KEY_MESSAGE_BOOK);
463 modem->sim_ipc->retrieve_messagebook_reply(modem->sim_ipc,
464 at->ipc_data,
465 g_value_get_pointer(val));
466 return AT_HANDLER_DONE;
468 default:
469 g_warning("%s : CMS ERROR: %d", __func__, cms_code);
470 gsmd_utils_send_error(at,
471 GSMD_ERROR_UNKNOWN,
472 "UNABLE TO LIST MESSAGES");
473 return AT_HANDLER_DONE_ERROR;
476 GError **error = NULL;
477 GRegex *regex = g_regex_new ("\\+CMGL:\\s(?<id>\\d+),.*|(?<error>ERROR)|(?<ok>OK)|(?<pdu>[0-9A-F]+)", 0, 0, error);
479 GMatchInfo *match_info;
482 if (g_regex_match (regex, response->str, 0, &match_info))
487 if (gsmd_utils_match_exists(match_info,"id"))
489 gchar *match = g_match_info_fetch_named(match_info,"id");
491 GValue *val = g_hash_table_lookup(at->handler_data,
492 GSMD_SIM_KEY_MESSAGE_BOOK);
493 if (!val)
495 gsmd_utils_send_error(at,
496 GSMD_ERROR_UNKNOWN,
497 "INVALID HANDLER DATA");
498 status = AT_HANDLER_DONE_ERROR;
501 GArray *list = g_value_get_pointer(val);
502 messagebook_msg *msg = g_try_new0(messagebook_msg,1);
503 msg->index = atoi(match);
504 g_free(match);
505 g_array_append_val(list,msg);
507 status = AT_HANDLER_NEED_MORE;
510 if (gsmd_utils_match_exists(match_info,"error"))
512 gsmd_utils_send_error(at,
513 GSMD_ERROR_UNKNOWN,
514 "UNABLE TO LIST MESSAGES");
515 status = AT_HANDLER_DONE_ERROR;
517 else if (gsmd_utils_match_exists(match_info,"ok"))
519 GValue *val = g_hash_table_lookup(at->handler_data,
520 GSMD_SIM_KEY_MESSAGE_BOOK);
521 if (!val)
523 gsmd_utils_send_error(at,
524 GSMD_ERROR_UNKNOWN,
525 "OK WITHOUT RESPONSE");
526 status = AT_HANDLER_DONE_ERROR;
528 else
530 modem->sim_ipc->retrieve_messagebook_reply(modem->sim_ipc,
531 at->ipc_data,
532 g_value_get_pointer(val));
535 status = AT_HANDLER_DONE;
537 else
538 //Check pdu, if this pdu is from a multipart message, but it's
539 //not the first part, then remove it from the list
540 if (gsmd_utils_match_exists(match_info,"pdu"))
542 gchar *match = g_match_info_fetch_named(match_info,"pdu");
543 SmsParam *sms = g_try_new0(SmsParam,1);
544 if (gsmd_sim_decoder_pdu((guchar*)match,sms))
547 if (sms->multipart && sms->multipart_index != 1)
549 //If it's multipart message and we have any of the
550 //latter parts, then remove their indexes
551 //and append their texts to the previous message
553 gsmd_sim_handler_retrieve_messagebook_remove_last(at->handler_data);
554 gsmd_sim_handler_retrieve_messagebook_fill_last_message(sms,
555 at->handler_data,
556 TRUE);
559 else //Otherwise create a new entry
560 gsmd_sim_handler_retrieve_messagebook_fill_last_message(sms,
561 at->handler_data,
562 FALSE);
567 gsmd_sms_sms_param_free(sms);
569 status = AT_HANDLER_NEED_MORE;
570 g_free(match);
576 g_free(error);
577 g_match_info_free (match_info);
578 g_regex_unref (regex);
581 return status;
584 static
585 AtCommandHandlerStatus gsmd_sim_handler_send_message (ModemInterface *modem,
586 AtCommandContext *at,
587 GString *response)
589 g_debug("%s",__func__);
591 AtCommandHandlerStatus status = AT_HANDLER_DONT_UNDERSTAND;
592 if (gsmd_utils_send_error_from_response(at,
593 response,
594 "UNKNOWN ERROR OCCURRED WHEN SENDING MESSAGE",
595 "TIMEOUT OCCURRED WHEN SENDING MESSAGE"))
596 return AT_HANDLER_DONE_ERROR;
599 GError **error = NULL;
600 GRegex *regex = g_regex_new ("\\+CMSS:\\s(?<id>\\d+)|(?<cms>\\+CMS\\sERROR).*|(?<ok>OK)", 0, 0, error);
602 GMatchInfo *match_info;
605 if (g_regex_match (regex, response->str, 0, &match_info))
607 //Got +CMSS <id>
608 if (gsmd_utils_match_exists(match_info,"id"))
610 gsmd_utils_table_insert_int(at->handler_data,
611 GSMD_SIM_KEY_CMSS_ID,
612 gsmd_utils_fetch_match_int(match_info,
613 "id",0));
614 status = AT_HANDLER_NEED_MORE;
616 else
617 //Got ok
618 if (gsmd_utils_match_exists(match_info,"ok"))
620 GValue *val = g_hash_table_lookup(at->handler_data,GSMD_SIM_KEY_CMSS_ID);
622 if (!val)
624 g_warning("%s : Invalid handler data. Didn't get CMSS id",
625 __func__);
627 gsmd_utils_send_error(at,
628 GSMD_ERROR_UNKNOWN,
629 "OK WITHOUT RESPONSE");
630 status = AT_HANDLER_DONE_ERROR;
632 else
634 modem->sim_ipc->send_stored_message_reply(modem->sim_ipc,at->ipc_data,0);
635 if (modem->sms_ipc->message_sent)
637 modem->sms_ipc->message_sent(modem->sms_ipc,TRUE,NULL);
639 status = AT_HANDLER_DONE;
642 else
643 //Got +CMS ERROR
644 if (gsmd_utils_match_exists(match_info,"cms"))
646 status = gsmd_sms_process_sms_error_response (modem,
648 modem->scanner);
653 g_free(error);
654 g_match_info_free (match_info);
655 g_regex_unref (regex);
658 return status;
662 * @brief Handler to modems response from setupPin command
664 * @param modem modem whose response to handle
665 * @return true if responses were recognized
667 static
668 AtCommandHandlerStatus gsmd_sim_handler_pin(ModemInterface *modem,
669 AtCommandContext *at,
670 GString *response)
673 AtCommandHandlerStatus ret = AT_HANDLER_DONT_UNDERSTAND;
675 GScanner* scanner = modem->scanner;
677 if (scanner != 0)
678 g_debug("gsmd_sim_handler_setup_pin %d", scanner->token);
679 else
681 g_debug("gsmd_sim_handler_setup_pin error - no scanner");
682 return AT_HANDLER_DONE;
687 switch (scanner->token)
689 case SYMBOL_OK:
690 gsmd_sim_send_pin_reply(modem, at);
691 gsmd_sim_change_auth_status(modem,NULL,SIM_READY,"READY",FALSE);
693 ret = AT_HANDLER_DONE;
694 break;
695 case SYMBOL_ERROR:
696 gsmd_utils_send_error(at,
697 GSMD_ERROR_UNKNOWN,
698 "FAILED TO CHANGE AUTH CODE");
700 if (modem->sim_status == SIM_NEED_PUK)
701 gsmd_sim_change_auth_status(modem,NULL,SIM_READY,"READY",FALSE);
704 /* What should be done on each status
705 SIM_UNKNOWN=0 -> we're still at unknown state
706 SIM_MISSING_SIM -> we still don't have a sim card
707 SIM_NEED_PIN -> pin was wrong, we still need pin
708 SIM_NEED_PUK -> puk code was wrong, we still need puk
709 SIM_READY -> we never needed any code so nothing changed
711 ret = AT_HANDLER_DONE_ERROR;
712 break;
713 default:
714 g_warning("%s : No match to setupPin handler", __func__);
715 break;
717 return ret;
721 void gsmd_sim_cache_auth_status(ModemInterface *modem,
722 AtCommandContext *at,
723 SIMStatus status,
724 const gchar *message)
726 g_debug("%s: status: %d, message: %s",__func__,status,message);
727 gsmd_utils_table_insert_string(at->handler_data,GSMD_SIM_KEY_AUTH_MESSAGE,message);
728 gsmd_utils_table_insert_int(at->handler_data,GSMD_SIM_KEY_AUTH_STATUS,status);
732 * @brief Handler to modems response from queryPinStatus command
734 * @param modem modem whose response to handle
735 * @return true if responses were recognized
737 static
738 AtCommandHandlerStatus gsmd_sim_handler_query_pin_status (ModemInterface *modem,
739 AtCommandContext *at,
740 GString *response)
742 g_debug("%s",__func__);
743 GScanner* scanner = modem->scanner;
747 if (scanner->token == SYMBOL_OK)
750 GValue *status = g_hash_table_lookup(at->handler_data,GSMD_SIM_KEY_AUTH_STATUS);
751 GValue *message = g_hash_table_lookup(at->handler_data,GSMD_SIM_KEY_AUTH_MESSAGE);
753 if (!status || !message)
755 g_warning("%s : Invalid handler data. status: %p, message: %p",
756 __func__,
757 status,
758 message);
759 gsmd_utils_send_error(at,GSMD_ERROR_UNKNOWN,"INVALID HANDLER DATA");
760 return AT_HANDLER_DONE_ERROR;
763 gsmd_sim_change_auth_status(modem,
764 at->ipc_data,
765 g_value_get_int(status),
766 g_value_get_string(message),
767 TRUE);
769 return AT_HANDLER_DONE;
772 if (scanner->token == SYMBOL_ERROR)
774 gsmd_utils_send_error(at,
775 GSMD_ERROR_UNKNOWN,
776 "ERROR READING PIN STATUS");
777 return AT_HANDLER_DONE_ERROR;
779 else if ( scanner->token == SYMBOL_TIME_OUT)
781 gsmd_utils_send_error(at,
782 GSMD_ERROR_DEVICE_TIMEOUT,
783 "TIMEOUT READING PIN STATUS");
784 return AT_HANDLER_DONE_ERROR;
787 if (scanner->token != '+')
789 return AT_HANDLER_DONT_UNDERSTAND;
792 g_scanner_get_next_token (scanner);
793 switch (scanner->token)
796 case SYMBOL_CME:
797 g_scanner_get_next_token (scanner);
798 //g_scanner_get_next_token (scanner);
799 if (scanner->token == SYMBOL_ERROR)
801 g_scanner_peek_next_token(scanner);
802 if (scanner->next_token == ':')
804 g_scanner_get_next_token (scanner);
805 g_scanner_get_next_token(scanner);//arrive error value
806 if ( ERR_NO_SIM_CARD == scanner->value.v_int )
808 gsmd_sim_change_auth_status(modem,
809 at->ipc_data,
810 SIM_MISSING,
811 "SIM MISSING",
812 TRUE);
814 else
816 gsmd_sim_change_auth_status(modem,
817 at->ipc_data,
818 SIM_ERROR,
819 "SIM ERROR",
820 TRUE);
823 return AT_HANDLER_DONE;
825 else
827 g_scanner_unexp_token (scanner, ':', NULL, "symbol",
828 NULL, NULL, TRUE);
832 else
834 g_scanner_unexp_token (scanner, SYMBOL_ERROR, NULL, "symbol",
835 NULL, NULL, TRUE);
837 break;
838 case SYMBOL_CPIN:
839 g_scanner_get_next_token (scanner);//get ':'
840 g_scanner_get_next_token (scanner);
841 if (scanner->token == SYMBOL_READY)
843 gsmd_sim_cache_auth_status(modem,
845 SIM_READY,
846 "READY");
849 return AT_HANDLER_NEED_MORE;
852 else if (scanner->token == SYMBOL_SIM)
855 g_scanner_get_next_token (scanner);
856 g_scanner_peek_next_token(scanner);
857 if (scanner->token == SYMBOL_PIN)
859 gsmd_sim_cache_auth_status(modem,
861 SIM_NEED_PIN,
862 "SIM PIN");
866 else if (scanner->token == SYMBOL_PUK)
868 gsmd_sim_cache_auth_status(modem,
870 SIM_NEED_PUK,
871 "SIM PUK");
874 return AT_HANDLER_NEED_MORE;
876 else
878 g_scanner_unexp_token (scanner, SYMBOL_READY, NULL, "symbol",
879 NULL, NULL, TRUE);
881 break;
882 default:
883 g_warning("No match after getting + \n");
884 break;
889 return AT_HANDLER_DONT_UNDERSTAND;
895 * @brief AtCommand to setup pin value(s)
897 * @param modem modem whose response to handle
898 * @param pin_code pin code(s) to set
900 static void gsmd_sim_command_setup_pin (SIMInterface *sim,
901 gpointer ipc_data,
902 const char* pin_code)
904 ModemInterface *modem = (ModemInterface*)sim->priv;
905 gsmd_modem_post_at_command_id( modem,
906 PIN_SETUP,
907 pin_code,
908 ipc_data,
909 (ErrorFunction)modem->sim_ipc->send_auth_code_error,
910 (gpointer)modem->sim_ipc,
911 INTERFACE_SIM,
912 NULL);
917 * @brief AtCommand to query pin status
919 * @param modem modem whose response to handle
921 static void gsmd_sim_command_query_pin_status (SIMInterface *sim,
922 gpointer ipc_data)
924 ModemInterface *modem = (ModemInterface*)sim->priv;
925 GValue *val = g_hash_table_lookup(modem->caches[INTERFACE_SIM],GSMD_SIM_KEY_AUTH_STATUS);
926 if (!modem->no_cache && val)
928 modem->sim_ipc->get_auth_status_reply(modem->sim_ipc,
929 ipc_data,
930 g_value_get_string(val));
932 else
934 gsmd_modem_post_at_command_id( modem,
935 PIN_QUERY,
936 NULL,
937 ipc_data,
938 (ErrorFunction)modem->sim_ipc->get_auth_status_error,
939 (gpointer)modem->sim_ipc,
940 INTERFACE_SIM,
941 NULL);
947 void gsmd_sim_command_unlock(SIMInterface *sim,
948 gpointer ipc_data,
949 const char* puk,
950 const char* new_pin)
952 g_debug("%s",__func__);
953 ModemInterface *modem = (ModemInterface*)sim->priv;
954 GString* param = g_string_new ("");
955 g_string_printf(param, "\"%s\",\"%s\"",puk,new_pin);
957 gsmd_modem_post_at_command_id( modem,
958 PUK_SETUP,
959 param->str,
960 ipc_data,
961 (ErrorFunction)modem->sim_ipc->unlock_error,
962 (gpointer)modem->sim_ipc,
963 INTERFACE_SIM,
964 NULL);
965 g_string_free(param,TRUE);
969 void gsmd_sim_command_change_auth_code(SIMInterface *sim,
970 gpointer ipc_data,
971 const char* old_pin,
972 const char* new_pin)
974 ModemInterface *modem = (ModemInterface*)sim->priv;
975 GString* param = g_string_new ("");
976 g_string_printf(param, "\"%s\",\"%s\"",old_pin,new_pin);
978 gsmd_modem_post_at_command_id( modem,
979 PIN_CHANGE,
980 param->str,
981 ipc_data,
982 (ErrorFunction)modem->sim_ipc->change_auth_code_error,
983 (gpointer)modem->sim_ipc,
984 INTERFACE_SIM,
985 NULL);
986 g_string_free(param,TRUE);
991 * Handler for reply to query_imsi command.
993 * @param modem pointer to modem struct
994 * @param response response sent by gsm modem
995 * @return AT_HANDLER_DONE when response is recognized
997 static
998 AtCommandHandlerStatus gsmd_sim_handler_query_imsi( ModemInterface *modem,
999 AtCommandContext *at,
1000 GString *response)
1003 at+cimi
1004 +CIMI: 244917070350971
1009 AtCommandHandlerStatus status = AT_HANDLER_DONT_UNDERSTAND;
1010 GError *error = NULL;
1011 GRegex *regex = g_regex_new ("^\\+CIMI:\\s(?<imsi>\\d+)$|^(?<imsi2>\\d+)$|^(?<error>ERROR)$|^(?<ok>OK)$",
1012 0, 0, &error);
1013 if ( error )
1015 g_debug("%s : '%s'", __func__, error->message);
1016 g_error_free( error );
1017 return AT_HANDLER_ERROR;
1019 GMatchInfo *match_info;
1020 GValue *val = NULL;
1023 if (g_regex_match (regex, response->str, 0, &match_info))
1025 if (gsmd_utils_match_exists(match_info,"imsi"))
1027 gchar *match = g_match_info_fetch_named(match_info,
1028 "imsi");
1029 g_debug("%s : imsi : %s", __func__, match);
1031 gsmd_utils_table_insert_string(at->handler_data,
1032 GSMD_SIM_KEY_IMSI,
1033 match);
1035 g_free(match);
1036 status = AT_HANDLER_NEED_MORE;
1038 else if (gsmd_utils_match_exists(match_info,"imsi2"))
1040 gchar *match = g_match_info_fetch_named(match_info,
1041 "imsi2");
1043 g_debug("%s : imsi2 : %s", __func__, match);
1044 gsmd_utils_table_insert_string(at->handler_data,
1045 GSMD_SIM_KEY_IMSI,
1046 match);
1048 g_free(match);
1049 status = AT_HANDLER_NEED_MORE;
1051 else if (gsmd_utils_match_exists(match_info,"error"))
1053 gsmd_utils_send_error(at,
1054 GSMD_ERROR_UNKNOWN,
1055 "FAILED TO READ IMSI");
1056 status = AT_HANDLER_DONE_ERROR;
1058 else if (gsmd_utils_match_exists(match_info,"ok"))
1060 val = g_hash_table_lookup(at->handler_data,GSMD_SIM_KEY_IMSI);
1061 g_debug("%s : ok : %p", __func__, val);
1062 if (val)
1064 status = AT_HANDLER_DONE;
1066 else
1068 // If we didn't get the response,
1069 // then this OK is not for us
1070 status = AT_HANDLER_DONT_UNDERSTAND;
1076 g_match_info_free (match_info);
1077 g_regex_unref (regex);
1080 return status;
1083 static
1084 gboolean gsmd_sim_command_get_sim_info_reply(ModemInterface *modem,
1085 gpointer ipc_data,
1086 GHashTable *info)
1088 g_debug("%s", __func__);
1089 if ( !modem->no_cache )
1091 GValue *imsi = g_hash_table_lookup(info,GSMD_SIM_KEY_IMSI);
1092 if ( imsi )
1094 gsmd_utils_table_insert_copy(modem->caches[INTERFACE_SIM],GSMD_SIM_KEY_IMSI,imsi);
1097 modem->sim_ipc->get_sim_info_reply( modem->sim_ipc,
1098 ipc_data,
1099 info);
1100 return TRUE;
1102 static
1103 AtCommandHandlerStatus gsmd_sim_handler_get_sim_info( ModemInterface *modem,
1104 AtCommandContext *at,
1105 GString *response)
1107 AtCommandHandlerStatus status = AT_HANDLER_DONT_UNDERSTAND;
1108 switch (at->command->cmd_id)
1110 case IMSI_QUERY:
1111 g_debug("%s : IMSI_QUERY", __func__);
1112 status = at->command->handler(modem,at,response);
1113 switch (status)
1115 case AT_HANDLER_DONE_ERROR:
1116 case AT_HANDLER_ERROR:
1117 return AT_HANDLER_DONE_ERROR;
1118 break;
1119 case AT_HANDLER_DONE:
1120 if ( !g_hash_table_lookup(at->handler_data,GSMD_SIM_KEY_IMSI) )
1122 gsmd_utils_send_error(at,GSMD_ERROR_UNKNOWN,"UNABLE TO READ IMSI");
1123 return AT_HANDLER_DONE_ERROR;
1125 gsmd_sim_command_get_sim_info_reply(modem, at->ipc_data, at->handler_data);
1126 /* gsmd_modem_post_at_command_id( modem, */
1127 /* QUERY_SUBSCRIBER_NUMBERS, */
1128 /* NULL, */
1129 /* ipc_data, */
1130 /* (ErrorFunction)modem->sim_ipc->get_subscriber_numbers_error, */
1131 /* (gpointer)modem->sim_ipc, */
1132 /* INTERFACE_SIM, */
1133 /* NULL); */
1134 break;
1135 case AT_HANDLER_DONT_UNDERSTAND:
1136 case AT_HANDLER_NEED_MORE:
1137 case AT_HANDLER_RETRY:
1138 return status;
1140 break;
1142 return status;
1145 void gsmd_sim_command_get_sim_info(SIMInterface *sim,
1146 gpointer ipc_data)
1148 ModemInterface *modem = (ModemInterface*)sim->priv;
1149 GValue *imsi = NULL;
1150 GValue *subs_num = NULL;
1151 GValue *dialcode = NULL;
1152 if (!modem->no_cache )
1154 imsi = g_hash_table_lookup(modem->caches[INTERFACE_SIM],GSMD_SIM_KEY_IMSI);
1155 subs_num = g_hash_table_lookup(modem->caches[INTERFACE_SIM],GSMD_SIM_KEY_SUBSCRIBER_NUMBER);
1156 dialcode = g_hash_table_lookup(modem->caches[INTERFACE_SIM],GSMD_SIM_KEY_DIAL_CODE);
1159 if (imsi && subs_num && dialcode)
1161 g_debug("%s: sim info is cached",__func__);
1162 GHashTable *info = gsmd_utils_create_hash_table();
1163 gsmd_utils_table_insert_copy(info,GSMD_SIM_KEY_IMSI,imsi);
1164 gsmd_utils_table_insert_copy(info,GSMD_SIM_KEY_SUBSCRIBER_NUMBER,subs_num);
1165 gsmd_utils_table_insert_copy(info,GSMD_SIM_KEY_DIAL_CODE, dialcode);
1166 modem->sim_ipc->get_sim_info_reply(modem->sim_ipc,
1167 ipc_data,
1168 info);
1169 g_hash_table_destroy(info);
1171 else
1173 AtCommandContext *cmd = NULL;
1174 cmd = gsmd_at_command_context_new_from_id( modem,
1175 IMSI_QUERY,
1176 NULL,
1177 ipc_data,
1178 (ErrorFunction)modem->sim_ipc->get_sim_info_error,
1179 (gpointer)modem->sim_ipc,
1180 NULL);
1181 cmd->handler = &gsmd_sim_handler_get_sim_info;
1182 gsmd_modem_post_at_command(modem,cmd,INTERFACE_SIM);
1187 static
1188 gboolean gsmd_sim_command_get_phonebook_info_reply(ModemInterface *modem,
1189 gpointer ipc_data,
1190 GHashTable *info)
1192 g_debug("%s", __func__);
1193 if ( !modem->no_cache )
1195 GValue *slots = g_hash_table_lookup(info,GSMD_SIM_KEY_PHONEBOOK_SLOTS);
1196 GValue *used = g_hash_table_lookup(info,GSMD_SIM_KEY_PHONEBOOK_SLOTS_USED);
1197 GValue *number_len = g_hash_table_lookup(info,GSMD_SIM_KEY_PHONEBOOK_NUMBER_LEN);
1198 GValue *name_len = g_hash_table_lookup(info,GSMD_SIM_KEY_PHONEBOOK_NAME_LEN);
1199 if ( slots )
1201 gsmd_utils_table_insert_copy(info,GSMD_SIM_KEY_PHONEBOOK_SLOTS,slots);
1203 if ( used )
1205 gsmd_utils_table_insert_copy(info,GSMD_SIM_KEY_PHONEBOOK_SLOTS_USED, used);
1207 if ( number_len )
1209 gsmd_utils_table_insert_copy(info,GSMD_SIM_KEY_PHONEBOOK_NUMBER_LEN,number_len);
1211 if ( name_len )
1213 gsmd_utils_table_insert_copy(info,GSMD_SIM_KEY_PHONEBOOK_NAME_LEN,name_len);
1216 modem->sim_ipc->get_sim_info_reply( modem->sim_ipc,
1217 ipc_data,
1218 info);
1219 return TRUE;
1222 static
1223 AtCommandHandlerStatus gsmd_sim_handler_get_phonebook_info( ModemInterface *modem,
1224 AtCommandContext *at,
1225 GString *response)
1227 AtCommandHandlerStatus status = AT_HANDLER_DONT_UNDERSTAND;
1228 AtCommandContext *cmd = NULL;
1229 switch (at->command->cmd_id)
1231 case PHONEBOOK_GET_INDEX_BOUNDARIES:
1232 g_debug("%s : PHONEBOOK_GET_INDEX_BOUNDARIES", __func__);
1233 status = at->command->handler(modem,at,response);
1234 switch (status)
1236 case AT_HANDLER_DONE_ERROR:
1237 case AT_HANDLER_ERROR:
1238 return AT_HANDLER_DONE_ERROR;
1239 break;
1240 case AT_HANDLER_DONE:
1241 cmd = gsmd_at_command_context_new_from_id( modem,
1242 PHONEBOOK_STATUS_QUERY,
1243 NULL,
1244 at->ipc_data,
1245 (ErrorFunction)modem->sim_ipc->get_phonebook_info_error,
1246 (gpointer)modem->sim_ipc,
1247 at->handler_data);
1248 at->handler_data = NULL;
1249 cmd->handler = &gsmd_sim_handler_get_phonebook_info;
1250 gsmd_modem_post_at_command(modem,cmd,INTERFACE_SIM);
1251 break;
1252 case AT_HANDLER_DONT_UNDERSTAND:
1253 case AT_HANDLER_NEED_MORE:
1254 case AT_HANDLER_RETRY:
1255 return status;
1257 break;
1258 case PHONEBOOK_STATUS_QUERY:
1259 g_debug("%s : PHONEBOOK_STATUS_QUERY", __func__);
1260 status = at->command->handler(modem,at,response);
1261 switch (status)
1263 case AT_HANDLER_DONE_ERROR:
1264 case AT_HANDLER_ERROR:
1265 return AT_HANDLER_DONE_ERROR;
1266 break;
1267 case AT_HANDLER_DONE:
1268 gsmd_sim_command_get_phonebook_info_reply(modem, at->ipc_data, at->handler_data);
1269 break;
1270 case AT_HANDLER_DONT_UNDERSTAND:
1271 case AT_HANDLER_NEED_MORE:
1272 case AT_HANDLER_RETRY:
1273 return status;
1275 break;
1277 return status;
1281 * @brief Retrieves the whole phonebook
1283 * @param sim SIM interface
1284 * @param ipc_data IPC method context data
1286 void gsmd_sim_command_retrieve_phonebook(SIMInterface *sim,
1287 gpointer ipc_data)
1289 //TODO implement
1293 * @brief Requests phonebook info
1295 * @param sim SIM interface
1296 * @param ipc_data IPC method context data
1298 void gsmd_sim_command_get_phonebook_info(SIMInterface *sim,
1299 gpointer ipc_data)
1301 ModemInterface *modem = (ModemInterface*)sim->priv;
1302 GValue *slots = NULL;
1303 GValue *used = NULL;
1304 GValue *number_len = NULL;
1305 GValue *name_len = NULL;
1306 if (!modem->no_cache )
1308 slots = g_hash_table_lookup(modem->caches[INTERFACE_SIM],GSMD_SIM_KEY_PHONEBOOK_SLOTS);
1309 used = g_hash_table_lookup(modem->caches[INTERFACE_SIM],GSMD_SIM_KEY_PHONEBOOK_SLOTS_USED);
1310 number_len = g_hash_table_lookup(modem->caches[INTERFACE_SIM],GSMD_SIM_KEY_PHONEBOOK_NUMBER_LEN);
1311 name_len = g_hash_table_lookup(modem->caches[INTERFACE_SIM],GSMD_SIM_KEY_PHONEBOOK_NAME_LEN);
1314 if (slots && used && number_len && name_len)
1316 g_debug("%s: info is cached",__func__);
1317 GHashTable *info = gsmd_utils_create_hash_table();
1318 gsmd_utils_table_insert_copy(info,GSMD_SIM_KEY_PHONEBOOK_SLOTS,slots);
1319 gsmd_utils_table_insert_copy(info,GSMD_SIM_KEY_PHONEBOOK_SLOTS_USED, used);
1320 gsmd_utils_table_insert_copy(info,GSMD_SIM_KEY_PHONEBOOK_NUMBER_LEN,number_len);
1321 gsmd_utils_table_insert_copy(info,GSMD_SIM_KEY_PHONEBOOK_NAME_LEN,name_len);
1322 modem->sim_ipc->get_phonebook_info_reply(modem->sim_ipc,
1323 ipc_data,
1324 info);
1325 g_hash_table_destroy(info);
1327 else
1329 AtCommandContext *cmd = NULL;
1330 cmd = gsmd_at_command_context_new_from_id( modem,
1331 PHONEBOOK_GET_INDEX_BOUNDARIES,
1332 NULL,
1333 ipc_data,
1334 (ErrorFunction)modem->sim_ipc->get_phonebook_info_error,
1335 (gpointer)modem->sim_ipc,
1336 NULL);
1337 cmd->handler = &gsmd_sim_handler_get_phonebook_info;
1338 gsmd_modem_post_at_command(modem,cmd,INTERFACE_SIM);
1344 * @brief Creates at command to set service center
1346 * @param modem modem to send command to
1347 * @param centerNo center number
1349 void gsmd_sim_command_set_service_center (SIMInterface *sim,
1350 gpointer ipc_data,
1351 const char* centerNo)
1353 ModemInterface *modem = (ModemInterface*)sim->priv;
1354 GString* command= g_string_new ("");
1355 gint format=0;
1356 if (g_strrstr (centerNo, "+"))
1358 //Internation format
1359 format = 145;
1361 else
1363 //national format
1364 format = 129;
1366 g_string_printf (command, "%s,%d", centerNo, format);
1367 gsmd_modem_post_at_command_id( modem,
1368 SMS_SET_CENTER,
1369 command->str,
1370 ipc_data,
1371 (ErrorFunction)modem->sim_ipc->set_service_center_number_error,
1372 (gpointer)modem->sim_ipc,
1373 INTERFACE_SIM,
1374 NULL);
1375 g_string_free(command,TRUE);
1379 * @brief Handler for replies sent by the gsm modem when a service center query
1380 * command is sent
1382 * @param modem modem whose replies to interpret
1383 * @return true if replies were correct
1385 AtCommandHandlerStatus gsmd_sim_handler_query_service_center (ModemInterface *modem,
1386 AtCommandContext *at,
1387 GString *response)
1389 //input is +CSCA: "+393359609600", 145
1390 GScanner* scanner = modem->scanner;
1391 if (scanner->token == SYMBOL_OK)
1393 if (modem->sim_ipc->get_service_center_number_reply)
1395 GValue *val = g_hash_table_lookup(at->handler_data,GSMD_SIM_KEY_SERVICE_CENTER);
1396 if (!val)
1398 g_warning("%s : Invalid handler data. service center: %p",
1399 __func__,
1400 val);
1402 gsmd_utils_send_error(at,
1403 GSMD_ERROR_UNKNOWN,
1404 "OK WITHOUT RESPONSE");
1406 modem->sim_ipc->get_service_center_number_reply(modem->sim_ipc,
1407 at->ipc_data,
1408 g_value_get_string(val));
1411 return AT_HANDLER_DONE;
1413 if (scanner->token == '+')
1415 g_scanner_get_next_token (scanner);
1416 if (scanner->token == SYMBOL_CSCA)
1418 g_scanner_get_next_token (scanner);//get :
1419 if (scanner->token == ':')
1421 g_scanner_get_next_token (scanner);
1422 gsmd_utils_table_insert_string(at->handler_data,GSMD_SIM_KEY_SERVICE_CENTER,scanner->value.v_string);
1425 return AT_HANDLER_NEED_MORE;
1429 return AT_HANDLER_DONT_UNDERSTAND;
1434 * @brief Creates at command to query service center
1436 * @param modem modem to send command to
1438 void gsmd_sim_command_query_service_center (SIMInterface *sim,
1439 gpointer ipc_data)
1441 ModemInterface *modem = (ModemInterface*)sim->priv;
1442 GValue *val = g_hash_table_lookup(modem->caches[INTERFACE_SIM],GSMD_SIM_KEY_SERVICE_CENTER);
1443 if (val && modem->no_cache)
1445 modem->sim_ipc->get_service_center_number_reply(modem->sim_ipc,
1446 ipc_data,
1447 g_value_get_string(val));
1449 else
1451 gsmd_modem_post_at_command_id( modem,
1452 SMS_CENTER_QUERY,
1453 NULL,
1454 ipc_data,
1455 (ErrorFunction)modem->sim_ipc->get_service_center_number_error,
1456 (gpointer)modem->sim_ipc,
1457 INTERFACE_SIM,
1458 NULL);
1465 * @brief Handler for replies sent by the gsm modem when a service center query
1466 * command is sent
1468 * @param modem modem whose replies to interpret
1469 * @return true if replies were correct
1471 static
1472 AtCommandHandlerStatus gsmd_sim_handler_get_subscriber_numbers (ModemInterface *modem,
1473 AtCommandContext *at,
1474 GString *response)
1477 at+cnum
1479 +CNUM: "","",129
1484 return AT_HANDLER_DONE;
1489 * @brief Handler for replies sent by the gsm modem when a set service centre
1490 * command is sent
1492 * @param modem modem whose replies to interpret
1493 * @return true if replies were correct
1495 AtCommandHandlerStatus gsmd_sim_handler_set_service_center (ModemInterface *modem,
1496 AtCommandContext *at,
1497 GString *response)
1499 GScanner* scanner = modem->scanner;
1500 g_assert( at );
1501 switch (scanner->token)
1503 case SYMBOL_OK:
1504 modem->sim_ipc->set_service_center_number_reply(modem->sim_ipc,
1505 at->ipc_data);
1506 return AT_HANDLER_DONE;
1507 break;
1508 case SYMBOL_ERROR:
1509 gsmd_utils_send_error(at,
1510 GSMD_ERROR_UNKNOWN,
1511 "FAILED TO SET SERVICE CENTER");
1512 return AT_HANDLER_DONE_ERROR;
1513 break;
1514 default:
1515 break;
1517 return AT_HANDLER_DONT_UNDERSTAND;
1520 static void gsmd_sim_command_store_message (SIMInterface *sim,
1521 gpointer ipc_data,
1522 const gchar *message,
1523 const gchar *number)
1526 at+cmgw=48
1528 > 0011000C915348500496870000AA0AE8329BFD4697D9EC37
1531 g_debug("%s : Storing message %s to %s",__func__,message,number);
1532 ModemInterface *modem = (ModemInterface*)sim->priv;
1533 gsmd_sms_send_pdu (modem,
1534 ipc_data,
1535 message,
1536 number,
1537 SMS_STORE,
1538 INTERFACE_SIM,
1539 (ErrorFunction)modem->sim_ipc->store_message_error,
1540 modem->sim_ipc,
1541 TRUE);
1547 * @brief 7 bit decode
1549 * @param src source message
1550 * @param dst destination message
1551 * @param src_length length of the source string
1552 * @return resulting destination's string
1554 static int gsmd_sim_decode_7bits(const guchar*src, guchar* dst, gint src_length)
1556 //divide bytes into groups, each group has 7 bytes, decode it
1557 //to 8 bytes
1558 gint src_p=0;//processed bytes in source gourp
1559 gint dst_p=0;//processed bytes in dest group
1560 gint cur_index=0;// char index of current processing group
1561 gint cur_left=0;// the left bits from last byte
1562 while (src_p < src_length)
1564 *dst = ((*src << cur_index) | cur_left) & 0x7f;
1565 cur_left = *src >> (7 - cur_index);
1566 dst++;
1567 dst_p++;
1568 cur_index++;
1569 if (cur_index == 7)
1571 *dst = cur_left;
1572 dst++;
1573 dst_p++;
1574 cur_left = 0;
1575 cur_index = 0;
1577 src++;
1578 src_p++;
1579 g_assert(dst_p < 512);
1581 *dst=0;
1582 return dst_p;
1586 * @brief Normalizes received telephonenumber.
1588 * Adds + to the beginning of
1589 * phone number if the phonenumber is in international format.
1591 * @param pdu sms parameters
1593 static void gsmd_sim_normalize_received_telnumber (SmsParam* pdu)
1595 gint i=0;
1596 gint len = strlen ((const char*)pdu->TPA);
1597 if (pdu->TOA == 0x91)
1599 //international format
1600 //add +before the number
1601 for (i=len; i>0; i--)
1603 pdu->TPA[i] = pdu->TPA[i-1];
1605 pdu->TPA[0] = '+';
1606 pdu->TPA[len+1] = '\0';
1616 //method call handler
1618 * @brief Handler for delete sms command's replies.
1620 * @param modem whose replies to handle
1621 * @return true if response was recognized
1623 AtCommandHandlerStatus gsmd_sim_handler_delete(ModemInterface *modem,
1624 AtCommandContext *at,
1625 GString *response)
1627 GScanner* scanner = modem->scanner;
1628 guint symbol;
1629 symbol = scanner->token;
1630 if (scanner->token == SYMBOL_OK)
1632 if (modem->sim_ipc->delete_message_reply)
1634 modem->sim_ipc->delete_message_reply(modem->sim_ipc,at->ipc_data);
1636 return AT_HANDLER_DONE;
1639 if (gsmd_utils_send_error_from_response(at,
1640 response,
1641 "UNKNOWN ERROR OCCURRED WHEN DELETING A MESSAGE",
1642 "TIMEOUT OCCURRED WHEN DELETING A MESSAGE"))
1644 return AT_HANDLER_DONE_ERROR;
1648 return AT_HANDLER_DONT_UNDERSTAND;
1654 static gboolean gsmd_sim_convert(guchar** src,
1655 guchar* dst,
1656 int src_length,
1657 int *dst_length,
1658 int move)
1660 if (strlen((char*)*src) < src_length + move)
1661 return FALSE;
1662 if (!gsmd_sms_string_to_bytes(*src,dst,src_length,dst_length))
1663 return FALSE;
1665 *src+=move;
1666 return TRUE;
1669 static gboolean gsmd_sim_convert_number(guchar** src,
1670 guchar* dst,
1671 int src_length,
1672 gboolean is_encode,
1673 int move)
1675 if (!gsmd_sms_invert_number(*src,dst,src_length,is_encode))
1676 return FALSE;
1677 if (strlen((char*)*src) < move)
1678 return FALSE;
1679 *src+=move;
1680 return TRUE;
1683 static gboolean sim_decoder_pdu_header( guchar **src, SmsParam *pdu)
1685 guchar tmp;
1687 //the SMSC Number length
1688 if (!gsmd_sim_convert(src,&tmp,2,NULL,4))
1689 return FALSE;
1691 tmp = (tmp-1)*2;
1693 //SMSC number
1694 if (!gsmd_sim_convert_number(src,pdu->SCA,tmp,FALSE,tmp))
1695 return FALSE;
1697 return TRUE;
1701 static gboolean sim_decoder_pdu_type( guchar **src, SmsParam *pdu)
1703 guchar tmp;
1705 if (!gsmd_sim_convert(src,&tmp,2,NULL,2))
1706 return FALSE;
1708 //check if it is send or receive
1709 pdu->storing = (tmp & 1);
1710 //check if it's multipart
1711 pdu->multipart = (tmp&64);
1713 if (pdu->storing) //if encoding submitted message, ignore reference number
1714 *src+=2;
1717 return TRUE;
1720 static gboolean sim_decoder_pdu_sender_num( guchar **src, SmsParam *pdu)
1722 guchar tmp;
1726 //the real status does not match the spec, in spec the 7bits should be 1 to
1727 //include the reply path. but the real value is 04H
1728 //include reply info
1730 //length of sender number
1731 if (!gsmd_sim_convert(src,&tmp,2,NULL,2))
1732 return FALSE;
1734 if (tmp & 1)
1735 tmp += 1;
1737 //length of sender number
1738 if (!gsmd_sim_convert(src,&pdu->TOA,2,NULL,2))
1739 return FALSE;
1741 if (!gsmd_sim_convert_number(src,pdu->TPA,tmp,FALSE,tmp))
1742 return FALSE;
1744 gsmd_sim_normalize_received_telnumber (pdu);
1746 return TRUE;
1749 static gboolean sim_decoder_pdu_protocol( guchar **src, SmsParam *pdu)
1751 return gsmd_sim_convert(src,&pdu->TP_PID,2,NULL,2);
1754 static gboolean sim_decoder_pdu_coding_scheme( guchar **src, SmsParam *pdu)
1756 return gsmd_sim_convert(src,&pdu->TP_DCS,2,NULL,2);
1759 static gboolean sim_decoder_pdu_validity_period( guchar **src, SmsParam *pdu)
1761 if (pdu->storing)
1763 *src+=2; //if submit format, skip validity period
1766 return TRUE;
1770 static gboolean sim_decoder_pdu_timestamp( guchar **src, SmsParam *pdu)
1772 if (!pdu->storing)
1774 if (!gsmd_sim_convert_number(src,pdu->TP_SCTS,14,FALSE,14))
1775 return FALSE;
1777 else
1779 memset(pdu->TP_SCTS,0,14);
1782 return TRUE;
1786 static gboolean sim_decoder_pdu_userdata( guchar **src, SmsParam *pdu)
1788 int dst_length;
1789 guchar tmp;
1790 gint len;
1791 guchar buf[256];
1792 guchar div = 0;
1794 if (!gsmd_sim_convert(src,&tmp,2,NULL,2))
1795 return FALSE;
1798 if (pdu->multipart)
1800 if (!gsmd_sim_convert(src,&div,2,NULL,6))
1801 return FALSE;
1802 if (!gsmd_sim_convert(src,&pdu->multipart_ref,2,NULL,2))
1803 return FALSE;
1804 if (!gsmd_sim_convert(src,&pdu->multipart_count,2,NULL,2))
1805 return FALSE;
1806 if (!gsmd_sim_convert(src,&pdu->multipart_index,2,NULL,2))
1807 return FALSE;
1810 div+=1;
1813 //if header doesn't stop at the edge of septet, skip fill bytes
1814 if (pdu->TP_DCS == GSM_7BIT && (div % 7) != 0)
1816 div += (7-((div)%7));
1818 //skip back userdata header
1819 *src-=12;
1822 else
1824 pdu->multipart_ref = 0;
1825 pdu->multipart_count = 0;
1826 pdu->multipart_index = 0;
1829 if (pdu->TP_DCS == GSM_7BIT)
1831 // 7-bit
1832 len = (tmp - tmp/8)*2;
1833 if (!gsmd_sim_convert(src,buf,len,&dst_length,0))
1834 return FALSE;
1836 gsmd_sim_decode_7bits (buf, pdu->TP_UD, dst_length); //TP-DU
1838 //If it's multipart, remove its header
1839 if (div > 0)
1841 memmove(pdu->TP_UD,&pdu->TP_UD[div],tmp-div);
1842 memset(&pdu->TP_UD[tmp-div],0,div);
1845 dst_length = tmp;
1846 pdu->TP_UD_LEN = dst_length;
1847 return TRUE;
1850 else if (pdu->TP_DCS == GSM_UCS2)
1852 // UCS2
1853 len = tmp*2;
1854 if (!gsmd_sim_convert(src,buf,len,&dst_length,0))
1855 return FALSE;
1856 memset (pdu->TP_UD, 0, sizeof(pdu->TP_UD));
1857 memcpy (pdu->TP_UD, buf, dst_length);
1858 pdu->TP_UD_LEN = dst_length;
1859 return TRUE;
1862 else
1864 // 8-bit
1865 g_warning("Not supported format");
1866 return FALSE;
1869 return FALSE;
1872 static gboolean sim_decoder_pdu_userdata_normalize( guchar **src, SmsParam *pdu)
1874 gchar code_buffer[161];
1875 guchar* q;
1876 gint i;
1877 gchar temp;
1878 glong write_bytes;
1879 GError* error;
1880 glong read_words;
1882 pdu->number = g_strdup((gchar*)pdu->TPA);
1884 if (!pdu->storing)
1886 pdu->timestamp = gsmd_utils_convert_to_timestamp((gchar*)pdu->TP_SCTS);
1888 else
1890 pdu->timestamp = 0;
1894 if (pdu->TP_DCS == GSM_7BIT)
1896 pdu->message = g_strdup((gchar*)pdu->TP_UD);
1898 else if (pdu->TP_DCS == GSM_UCS2)
1900 //covert it to UTF8
1901 memset (code_buffer, 0, sizeof(code_buffer));
1903 * The intel CPU is little-endian, but the ucs2 in sms
1904 * is big-endian, so the usc_string byte order need to
1905 * be converted
1906 * For example chinese hello in utf16 is 4F60 597D
1907 * but usc_string is 604F 7D59
1908 * Following while() is to convert the byte order
1910 q = pdu->TP_UD;
1911 for (i=0; i < pdu->TP_UD_LEN; i += 2)
1913 temp = *q;
1914 *q = *(q+1);
1915 *(q+1) = temp;
1916 q += 2;
1919 pdu->message = g_strdup(g_utf16_to_utf8 ((gunichar2*)pdu->TP_UD,
1921 ,&read_words,
1922 &write_bytes,
1923 &error));
1925 else
1927 return FALSE;
1930 return TRUE;
1934 * @brief Pdu decoder
1936 * @param src string to decode
1937 * @param pdu sms parameters
1938 * @return true if pdu was succesfully decoded
1940 static gboolean gsmd_sim_decoder_pdu (guchar* src,SmsParam* pdu)
1942 g_debug("%s : %s",__func__,src);
1945 if (!sim_decoder_pdu_header(&src,pdu))
1946 return FALSE;
1947 if (!sim_decoder_pdu_type(&src,pdu))
1948 return FALSE;
1949 if (!sim_decoder_pdu_sender_num(&src,pdu))
1950 return FALSE;
1951 if (!sim_decoder_pdu_protocol(&src,pdu))
1952 return FALSE;
1953 if (!sim_decoder_pdu_coding_scheme(&src,pdu))
1954 return FALSE;
1955 if (!sim_decoder_pdu_validity_period(&src,pdu))
1956 return FALSE;
1957 if (!sim_decoder_pdu_timestamp(&src,pdu))
1958 return FALSE;
1959 if (!sim_decoder_pdu_userdata(&src,pdu))
1960 return FALSE;
1961 return sim_decoder_pdu_userdata_normalize(&src,pdu);
1965 * @brief Removes the trailing \r\n from input stream
1967 * @param input input to modify
1968 * @return modified string
1970 static guchar* gsmd_sim_get_sms_body (GString* input)
1972 gchar *s = g_strdup(input->str);
1973 g_strstrip(s);
1974 g_string_truncate(input, 0);
1975 g_string_append(input,s);
1976 g_free( s );
1977 return (guchar*)input->str;
1982 static void gsmd_sim_command_retrieve_messagebook (SIMInterface *sim,
1983 gpointer ipc_data,
1984 const gchar *status)
1986 ModemInterface *modem = (ModemInterface*)sim->priv;
1987 g_debug("%s: Listing messages with status %s",__func__,status);
1989 gchar *valid[] = {"unread","read","unsent","sent","all"};
1990 gint i=0;
1991 GHashTable *data = gsmd_utils_create_hash_table();
1993 GArray *list = g_array_new(FALSE,TRUE,sizeof(int));
1994 gsmd_utils_table_insert_pointer(data,GSMD_SIM_KEY_MESSAGE_BOOK,list);
1996 gsmd_utils_table_insert_string(data,GSMD_SIM_KEY_MESSAGE_BOOK_TYPE,status);
1998 GString *param = g_string_new("");
2001 for (i=0;i<5;i++)
2003 if (g_str_equal(status,valid[i]))
2005 g_string_printf(param,"%d",i);
2006 gsmd_modem_post_at_command_id( modem,
2007 SMS_LIST,
2008 param->str,
2009 ipc_data,
2010 (ErrorFunction)modem->sim_ipc->retrieve_messagebook_error,
2011 (gpointer)modem->sim_ipc,
2012 INTERFACE_SIM,
2013 data);
2014 g_string_free(param,TRUE);
2015 return;
2019 g_string_free(param,TRUE);
2020 g_array_free(list,TRUE);
2021 g_hash_table_destroy(data);
2022 gsmd_utils_send_error_full((ErrorFunction)modem->sim_ipc->retrieve_messagebook_error,
2023 modem->sim_ipc,
2024 ipc_data,
2025 GSMD_ERROR_UNKNOWN,
2026 "INVALID SMS STATUS");
2030 * @brief Creates the at command to delete a sms message.
2032 * @param modem modem whose sms to delete
2033 * @param pos sms message's index
2035 static void gsmd_sim_command_delete (SIMInterface *sim,
2036 gpointer ipc_data,
2037 gint pos)
2039 ModemInterface *modem = (ModemInterface*)sim->priv;
2040 gchar *pos_str = g_strdup_printf ("%d", pos);
2041 gsmd_modem_post_at_command_id( modem,
2042 SMS_DELETE,
2043 pos_str,
2044 ipc_data,
2045 (ErrorFunction)modem->sim_ipc->delete_message_error,
2046 (gpointer)modem->sim_ipc,
2047 INTERFACE_SIM,
2048 NULL);
2049 g_free (pos_str);
2053 * @brief Sends a sms from database
2055 * Fetches specified sms from the database, prepares it for sending and
2056 * calls gsmd_sms_command_send to actually send the message.
2058 * @param modem modem whose message to send
2059 * @param msgid id of the mssage to send
2061 void gsmd_sim_command_send_stored_message (SIMInterface *sim,
2062 gpointer ipc_data,
2063 gint index)
2065 //TODO want_report is currently ignored
2066 ModemInterface *modem = (ModemInterface*)sim->priv;
2067 GString* message = g_string_new ("");
2068 g_string_printf(message, "%d",index);
2070 gsmd_modem_post_at_command_id( modem,
2071 SIM_SEND,
2072 message->str,
2073 ipc_data,
2074 (ErrorFunction)modem->sim_ipc->send_stored_message_error,
2075 (gpointer)modem->sim_ipc,
2076 INTERFACE_SIM,
2077 NULL);
2078 g_string_free(message,TRUE);
2082 * @brief Free function for retrieve_message method
2084 * @param at at command context which contents should be freed
2086 static void gsmd_sms_handler_read_free(AtCommandContext *at)
2088 g_debug("%s",__func__);
2089 GValue *val = g_hash_table_lookup(at->handler_data,
2090 GSMD_SIM_KEY_PDU_MULTIPART_LIST);
2092 if (!val)
2093 return;
2095 GList *list = g_value_get_pointer(val);
2096 if (!list)
2097 return;
2099 GList *iter = list;
2100 while (iter)
2102 multipart_sms *sms = iter->data;
2103 if (sms)
2105 g_free(sms->message);
2106 g_free(sms);
2108 iter = g_list_next(iter);
2111 g_hash_table_remove(at->handler_data,
2112 GSMD_SIM_KEY_PDU_MULTIPART_LIST);
2114 g_list_free(list);
2120 * @brief Gets message part's contents from given index
2122 * Finds given index in glist containing multipart_sms and
2123 * returns it's message, NULL if not found.
2125 * @param list list containing multipart_sms
2126 * @param index index to find
2127 * @return message contents or null if not found
2129 gchar *gsmd_sim_handler_read_assemble_get_index(GList *list,gint index)
2131 while (list)
2133 multipart_sms *sms = list->data;
2134 if (sms && sms->multipart_index == index)
2135 return sms->message;
2136 list = g_list_next(list);
2139 return NULL;
2143 * @brief Gets the count of messages to assemble
2145 * Gets the first multipart_sms from glist and returns it's
2146 * multipart_count
2147 * @param list GList containing multipart_sms
2148 * @return messages in to assemble
2150 gint gsmd_sim_handler_read_assemble_get_count(GList *list)
2152 if (!list)
2153 return -1;
2155 multipart_sms *sms = list->data;
2156 if (!sms)
2157 return -1;
2159 return sms->multipart_count;
2164 * @brief Assemble multipart messages
2166 * Once all multipart messages are retrieved with AT+CMGL=4
2167 * this function assembles those messages together and sends
2168 * ipc reply
2169 * @param modem pointer to modem interface
2170 * @param at at command context
2171 * @return handler status
2173 AtCommandHandlerStatus gsmd_sim_handler_read_assemble(ModemInterface *modem,
2174 AtCommandContext *at)
2176 GList *list = gsmd_utils_table_get_pointer(at->handler_data,
2177 GSMD_SIM_KEY_PDU_MULTIPART_LIST,
2178 NULL);
2180 if (!list)
2182 gsmd_utils_send_error(at,
2183 GSMD_ERROR_UNKNOWN,
2184 "INVALID HANDLER DATA");
2185 return AT_HANDLER_DONE_ERROR;
2188 gint count = gsmd_sim_handler_read_assemble_get_count(list);
2190 if (count < 2)
2192 gsmd_utils_send_error(at,
2193 GSMD_ERROR_UNKNOWN,
2194 "INVALID HANDLER DATA");
2195 return AT_HANDLER_DONE_ERROR;
2198 GString *result = g_string_new("");
2199 gint i=1;
2201 for (i=1;i<=count;i++)
2203 gchar *part = gsmd_sim_handler_read_assemble_get_index(list,i);
2204 if (part)
2206 g_string_append(result,part);
2208 else
2210 g_string_append_printf(result,"<Message %d/%d missing>",i,count);
2214 g_debug("%s : Assembled message is '%s'",__func__,result->str);
2216 modem->sim_ipc->retrieve_message_reply(modem->sim_ipc,
2217 at->ipc_data,
2218 gsmd_utils_table_get_string(at->handler_data,
2219 GSMD_SIM_KEY_NUMBER,
2220 ""),
2221 result->str);
2223 g_string_free(result,TRUE);
2225 return AT_HANDLER_DONE;
2230 * @brief Checks if given pdu is multipart and part of message we are assembling
2231 * and adds it to at->handler_data if it is.
2233 * @param modem pointer to modem interface
2234 * @param at at command context
2235 * @param pdu of the message to check
2236 * @return handler status
2238 AtCommandHandlerStatus gsmd_sim_handler_read_check_pdu(ModemInterface *modem,
2239 AtCommandContext *at,
2240 gchar *pdu)
2242 g_debug("%s",__func__);
2243 SmsParam *sms = g_try_new0(SmsParam,1);
2245 if (!gsmd_sim_decoder_pdu((guchar*)pdu,sms))
2247 gsmd_sms_sms_param_free(sms);
2248 return AT_HANDLER_DONT_UNDERSTAND;
2251 if (!sms->multipart)
2253 gsmd_sms_sms_param_free(sms);
2254 return AT_HANDLER_NEED_MORE;
2258 gint ref = gsmd_utils_table_get_int(at->handler_data,
2259 GSMD_SIM_KEY_PDU_MULTIPART_REF,
2262 if (sms->multipart_ref != ref)
2264 g_debug("%s : got multipart ref %d, wanted %d",
2265 __func__,
2266 sms->multipart_ref,
2267 ref);
2269 gsmd_sms_sms_param_free(sms);
2270 return AT_HANDLER_NEED_MORE;
2275 GList *list = gsmd_utils_table_get_pointer(at->handler_data,
2276 GSMD_SIM_KEY_PDU_MULTIPART_LIST,
2277 NULL);
2279 multipart_sms *part = g_try_new0(multipart_sms,1);
2280 part->multipart_count = sms->multipart_count;
2281 part->multipart_index = sms->multipart_index;
2282 part->multipart_ref = sms->multipart_ref;
2283 part->message = g_strdup(sms->message);
2285 g_debug("%s : Got part %d/%d of multipart message : '%s'",
2286 __func__,
2287 part->multipart_index,
2288 part->multipart_count,
2289 part->message);
2291 list = g_list_append(list,part);
2293 gsmd_utils_table_insert_pointer(at->handler_data,
2294 GSMD_SIM_KEY_PDU_MULTIPART_LIST,
2295 list);
2296 gsmd_sms_sms_param_free(sms);
2297 return AT_HANDLER_NEED_MORE;
2301 * @brief Handler to find multipart message's each part
2303 * When retrieving a multipart message, all parts must be retrieved
2304 * so at+cmgl=4 is sent to modem to list all messages. This function
2305 * Finds all of the messages parts, assembles then and sends the
2306 * ipc response.
2308 * @param modem pointer to modem interface
2309 * @param at command context
2310 * @param response from modem
2311 * @return handler status
2313 AtCommandHandlerStatus gsmd_sim_handler_read_list (ModemInterface *modem,
2314 AtCommandContext *at,
2315 GString *response)
2317 g_debug("%s",__func__);
2319 at+cmgl=1
2320 +CMGL: 1,1,"",145
2321 <pdu>
2322 +CMGL: 2,1,"",148
2323 <pdu>
2324 +CMGL: 3,1,"",158
2326 Regular expression:
2327 \+CMGL:\s(\d+),.*
2330 AtCommandHandlerStatus status = AT_HANDLER_DONT_UNDERSTAND;
2331 GError **error = NULL;
2332 GRegex *regex = g_regex_new ("\\+CMGL:\\s(?<id>\\d+),.*|(?<error>ERROR)|(?<ok>OK)|(?<pdu>[0-9A-F]+)", 0, 0, error);
2334 GMatchInfo *match_info;
2337 if (g_regex_match (regex, response->str, 0, &match_info))
2339 //Ignore +CMGL line
2340 if (gsmd_utils_match_exists(match_info,"id"))
2342 status = AT_HANDLER_NEED_MORE;
2344 else //If error occurs, then return error
2345 if (gsmd_utils_match_exists(match_info,"error"))
2347 gsmd_utils_send_error(at,
2348 GSMD_ERROR_UNKNOWN,
2349 "UNABLE TO READ MESSAGE");
2350 status = AT_HANDLER_DONE_ERROR;
2351 //If we get ok, then we'll assemble the pieces
2352 //and send reply
2354 else if (gsmd_utils_match_exists(match_info,"ok"))
2356 status = gsmd_sim_handler_read_assemble(modem,at);
2358 else //when we have a pdu, then check it and add to
2359 //list
2360 if (gsmd_utils_match_exists(match_info,"pdu"))
2362 status = gsmd_sim_handler_read_check_pdu(modem,
2364 response->str);
2368 g_free(error);
2369 g_match_info_free (match_info);
2370 g_regex_unref (regex);
2373 return status;
2377 * @brief Handler for replies sent by the gsm modem when a read command is sent.
2379 * First message's pdu is returned and decoded. If it isn't a multipart message
2380 * then message's contents are sent through ipc. Otherwise the message is
2381 * assembled from it's parts.
2383 * To assemble a message all it's parts have to be found. Message has a
2384 * reference to identify it from other multipart messages. This is stored
2385 * to at->handler_data. Then AT+CMGL=4
2386 * is sent to gsm modem to list all messages. Replies to them are handled
2387 * by gsmd_sim_handler_read_list which uses gsmd_sim_handler_read_check_pdu
2388 * to check if listed message has proper reference code. If it has proper
2389 * reference code then it is added to a list in at->handler_data.
2390 * once AT+CMGL=4 is done (OK is returned) then gsmd_sim_handler_read_assemble
2391 * is called to assemble the message from list within at->handler_data.
2392 * Once message is assembled, it is sent to ipc.
2395 * @param modem pointer to modem interface
2396 * @param at at command context
2397 * @param response modem's response
2398 * @return handler status
2400 AtCommandHandlerStatus gsmd_sim_handler_read (ModemInterface *modem,
2401 AtCommandContext *at,
2402 GString *response)
2404 /* g_debug("%s",__func__); */
2405 //Do we have pdu to parse?
2406 gboolean pdu_ready = gsmd_utils_table_get_boolean(at->handler_data,
2407 GSMD_SIM_KEY_PDU_READY,
2408 FALSE);
2410 //Is it a multipart message? Then let gsmd_sim_handler_read_list
2411 //handle AT+CMGL=4's responses
2412 if (gsmd_utils_table_get_boolean(at->handler_data,
2413 GSMD_SIM_KEY_PDU_MULTIPART_LISTING,
2414 FALSE))
2415 return gsmd_sim_handler_read_list(modem,at,response);
2418 GScanner* scanner = modem->scanner;
2419 guchar* src;
2420 GString* input_data;
2422 guint symbol;
2423 g_assert( at );
2424 symbol = scanner->token;
2426 //pdu_ready will be set when there is +CMGR
2427 if (pdu_ready)
2431 SmsParam *pdu = g_try_new0(SmsParam,1);
2432 //decode the pdu;
2433 input_data = g_string_new (response->str);
2434 src = gsmd_sim_get_sms_body (input_data);
2436 if (!gsmd_sim_decoder_pdu (src, pdu))
2438 gsmd_sms_sms_param_free(pdu);
2439 return AT_HANDLER_DONT_UNDERSTAND;
2442 if (pdu->multipart) //if it's multipart then only the first part
2444 //is a valid one from ipc's perspective
2445 //and others are invalid
2446 g_debug("%s : Got first sms of multipart message"
2447 ,__func__);
2450 if (pdu->multipart_index != 1)
2452 gsmd_utils_send_error(at,
2453 GSMD_ERROR_UNKNOWN, //TODO change better error code
2454 "INVALID MESSAGE INDEX");
2455 gsmd_sms_sms_param_free(pdu);
2456 return AT_HANDLER_DONE_ERROR;
2458 else
2460 //mark handler_data that we are dealing with
2461 //multipart message and store messages reference
2462 //code
2463 gsmd_utils_table_insert_boolean(at->handler_data,
2464 GSMD_SIM_KEY_PDU_MULTIPART,
2465 TRUE);
2466 gsmd_utils_table_insert_int(at->handler_data,
2467 GSMD_SIM_KEY_PDU_MULTIPART_REF,
2468 pdu->multipart_ref);
2471 else
2474 //If it's normal (single) message, store the message
2475 gsmd_utils_table_insert_string(at->handler_data,
2476 GSMD_SIM_KEY_MESSAGE,
2477 pdu->message);
2480 //and store phone number and timestamp
2481 gsmd_utils_table_insert_string(at->handler_data,
2482 GSMD_SIM_KEY_NUMBER,
2483 pdu->number);
2486 gsmd_utils_table_insert_int(at->handler_data,
2487 GSMD_SIM_KEY_TIMESTAMP,
2488 pdu->timestamp);
2492 g_string_free (input_data, TRUE);
2494 gsmd_utils_table_insert_boolean(at->handler_data,
2495 GSMD_SIM_KEY_PDU_READY,
2496 FALSE);
2497 gsmd_sms_sms_param_free(pdu);
2498 return AT_HANDLER_NEED_MORE;
2501 switch (symbol)
2503 case SYMBOL_OK:
2505 //once we've got ok, check if the message is a multipart one
2506 //then we'll need to find the rest
2507 if (gsmd_utils_table_get_boolean(at->handler_data,
2508 GSMD_SIM_KEY_PDU_MULTIPART,
2509 FALSE))
2512 gsmd_utils_table_insert_boolean(at->handler_data,
2513 GSMD_SIM_KEY_PDU_MULTIPART_LISTING,
2514 TRUE);
2516 gsmd_modem_serial_write_simple( modem,
2517 "AT+CMGL=4\r\n",
2518 INTERFACE_SMS);
2519 return AT_HANDLER_NEED_MORE;
2522 GValue *msg = g_hash_table_lookup(at->handler_data,GSMD_SIM_KEY_MESSAGE);
2523 GValue *num = g_hash_table_lookup(at->handler_data,GSMD_SIM_KEY_NUMBER);
2524 //GValue *time = g_hash_table_lookup(at->handler_data,GSMD_SIM_KEY_TIMESTAMP);
2525 if (!msg || !num)
2527 gsmd_utils_send_error(at,
2528 GSMD_ERROR_UNKNOWN,
2529 "OK WITHOUT REPSPONSE");
2530 g_warning("%s : Invalid handler data, number or message missing",__func__);
2531 return AT_HANDLER_ERROR;
2534 if (modem->sim_ipc->retrieve_message_reply)
2536 modem->sim_ipc->retrieve_message_reply(modem->sim_ipc,
2537 at->ipc_data,
2538 g_value_get_string(num),
2539 g_value_get_string(msg)
2540 /*,g_value_get_int(time)*/);
2543 return AT_HANDLER_DONE;
2544 case '+':
2545 g_scanner_get_next_token (scanner);
2546 if (scanner->token == SYMBOL_CMS)
2548 g_warning ("read sms from simcard error\n");
2549 gsmd_utils_send_error(at,
2550 GSMD_ERROR_UNKNOWN,
2551 "FAILED TO READ FROM SIM CARD");
2552 return AT_HANDLER_DONE_ERROR;
2554 else if (scanner->token == SYMBOL_CMGR)
2557 g_scanner_get_next_token (scanner);//get :
2558 g_scanner_get_next_token (scanner);//get status
2559 //sms_status = scanner->value.v_int;
2560 gsmd_utils_table_insert_boolean(at->handler_data,
2561 GSMD_SIM_KEY_PDU_READY,
2562 TRUE);
2565 return AT_HANDLER_NEED_MORE;
2568 return AT_HANDLER_DONT_UNDERSTAND;
2574 * @brief Creates the at command to read a sms message
2576 * @param modem modem where to read from
2577 * @param pos index of the message to read
2579 void gsmd_sim_command_read (SIMInterface *sim,
2580 gpointer ipc_data,
2581 gint pos)
2583 gchar *pos_str = g_strdup_printf ("%d", pos);
2584 ModemInterface *modem = (ModemInterface*)sim->priv;
2585 GHashTable *data = gsmd_utils_create_hash_table();
2587 gsmd_utils_table_insert_boolean(data,
2588 GSMD_SIM_KEY_PDU_READY,
2589 FALSE);
2591 gsmd_modem_post_at_command_id( modem,
2592 SMS_READ,
2593 pos_str,
2594 ipc_data,
2595 (ErrorFunction)modem->sim_ipc->retrieve_message_error,
2596 (gpointer)modem->sim_ipc,
2597 INTERFACE_SIM,
2598 data);
2599 g_free (pos_str);
2602 /* void gsmd_sim_free_storage_spaces_array(GHashTable *table) */
2603 /* { */
2604 /* int i=0; */
2605 /* GValue *val = g_hash_table_lookup(table,GSMD_SIM_KEY_STORAGE_SPACES); */
2606 /* if (val) { */
2607 /* GArray *array = g_value_get_pointer(val); */
2609 /* for (i=0;i<array->len;i++) { */
2610 /* g_string_free(g_array_index(array, */
2611 /* GString*, */
2612 /* i), */
2613 /* TRUE); */
2614 /* } */
2615 /* g_array_free(array,TRUE); */
2618 /* } */
2619 /* } */
2621 /* static void gsmd_sim_storage_spaces_free(AtCommandContext *at) */
2622 /* { */
2623 /* gsmd_sim_free_storage_spaces_array(at->handler_data); */
2624 /* } */
2626 /* AtCommandHandlerStatus */
2627 /* gsmd_sim_handler_get_storage_spaces(ModemInterface *modem, */
2628 /* AtCommandContext *at, */
2629 /* GString *response) */
2630 /* { */
2631 /* /\* */
2632 /* AT+CPBS=? */
2634 /* +CPBS: ("SM","FD","LD","MC","RC") */
2636 /* OK */
2637 /* *\/ */
2640 /* AtCommandHandlerStatus status = AT_HANDLER_DONT_UNDERSTAND; */
2641 /* GError *error = NULL; */
2642 /* GRegex *regex = g_regex_new ("(?<cpbs>\\+CPBS:\\s\\((\"\\w+\",?)+\\))|(?<error>ERROR)|(?<ok>OK)", 0, 0, NULL); */
2643 /* GMatchInfo *match_info; */
2645 /* if (g_regex_match (regex, response->str, 0, &match_info)) { */
2646 /* if (gsmd_utils_match_exists(match_info,"cpbs")) { */
2647 /* g_free(error); */
2648 /* g_match_info_free (match_info); */
2649 /* g_regex_unref (regex); */
2650 /* error = NULL; */
2651 /* match_info = NULL; */
2654 /* regex = g_regex_new ("\"(?<id>\\w+)\"", 0, 0, NULL); */
2656 /* if (g_regex_match (regex, response->str, 0, &match_info)) { */
2657 /* GString *line = NULL; */
2660 /* GArray *array = g_array_new(FALSE, */
2661 /* TRUE, */
2662 /* sizeof(GString*)); */
2663 /* gchar *match = NULL; */
2665 /* while (g_match_info_matches (match_info)) { */
2666 /* match = g_match_info_fetch_named(match_info,"id"); */
2667 /* line = g_string_new(match); */
2668 /* g_free(match); */
2669 /* g_array_append_val(array,line); */
2670 /* g_match_info_next (match_info, NULL); */
2671 /* } */
2673 /* gsmd_utils_table_insert_pointer(at->handler_data, */
2674 /* GSMD_SIM_KEY_STORAGE_SPACES, */
2675 /* array); */
2677 /* } */
2679 /* status = AT_HANDLER_NEED_MORE; */
2681 /* } else if (gsmd_utils_match_exists(match_info,"error")) { */
2682 /* gsmd_utils_send_error(at, */
2683 /* GSMD_ERROR_UNKNOWN, */
2684 /* "FAILED TO GET STORAGE SPACES"); */
2686 /* status = AT_HANDLER_DONE_ERROR; */
2687 /* } else if (gsmd_utils_match_exists(match_info,"ok")) { */
2688 /* GValue *val = g_hash_table_lookup(at->handler_data, */
2689 /* GSMD_SIM_KEY_STORAGE_SPACES); */
2691 /* if (!val) { */
2692 /* g_warning("%s : Invalid handler data. storage spaces: %p", */
2693 /* __func__, */
2694 /* val); */
2696 /* gsmd_utils_send_error(at, */
2697 /* GSMD_ERROR_UNKNOWN, */
2698 /* "INVALID HANDLER DATA"); */
2699 /* status = AT_HANDLER_DONE_ERROR; */
2700 /* } else { */
2701 /* gsmd_sim_free_storage_spaces_array(modem->caches[INTERFACE_SIM]); */
2702 /* g_hash_table_remove(modem->caches[INTERFACE_SIM],GSMD_SIM_KEY_STORAGE_SPACES); */
2704 /* /\* modem->sim_ipc->get_storage_spaces_reply(modem->sim_ipc, *\/ */
2705 /* /\* at->ipc_data, *\/ */
2706 /* /\* g_value_get_pointer(val)); *\/ */
2707 /* gsmd_utils_table_insert_pointer(modem->caches[INTERFACE_SIM], */
2708 /* GSMD_SIM_KEY_STORAGE_SPACES, */
2709 /* g_value_get_pointer(val)); */
2710 /* g_hash_table_remove(at->handler_data,GSMD_SIM_KEY_STORAGE_SPACES); */
2711 /* status = AT_HANDLER_DONE; */
2712 /* } */
2713 /* } */
2716 /* } */
2718 /* g_free(error); */
2719 /* g_match_info_free (match_info); */
2720 /* g_regex_unref (regex); */
2723 /* return status; */
2724 /* } */
2727 /* void gsmd_sim_command_get_storage_spaces(SIMInterface *sim, */
2728 /* gpointer ipc_data) */
2729 /* { */
2730 /* ModemInterface *modem = (ModemInterface*)sim->priv; */
2731 /* GValue *val = g_hash_table_lookup(modem->caches[INTERFACE_SIM],GSMD_SIM_KEY_STORAGE_SPACES); */
2733 /* if (!modem->no_cache && val) { */
2734 /* /\* modem->sim_ipc->get_storage_spaces_reply(modem->sim_ipc, *\/ */
2735 /* /\* ipc_data, *\/ */
2736 /* /\* g_value_get_pointer(val)); *\/ */
2737 /* } else { */
2739 /* gsmd_modem_post_at_command_id( modem, */
2740 /* PHONEBOOK_SPACES_QUERY, */
2741 /* NULL, */
2742 /* ipc_data, */
2743 /* (ErrorFunction)modem->sim_ipc->get_storage_spaces_error, */
2744 /* (gpointer)modem->sim_ipc, */
2745 /* INTERFACE_SIM, */
2746 /* NULL); */
2747 /* } */
2748 /* } */
2750 AtCommandHandlerStatus gsmd_sim_handler_get_phonebook_status(ModemInterface *modem,
2751 AtCommandContext *at,
2752 GString *response)
2755 AT+CPBS?
2757 +CPBS: "SM",2,250
2761 \+CPBS:\s"(\w+)",\d+,\d+
2763 AtCommandHandlerStatus status = AT_HANDLER_DONT_UNDERSTAND;
2764 GError *error = NULL;
2765 GRegex *regex = g_regex_new ("\\+CPBS:\\s\"(?<space>\\w+)\",(?<used>\\d+),(?<total>\\d+)|"
2766 "(?<error>ERROR)|(?<ok>OK)", 0, 0, &error);
2767 GMatchInfo *match_info;
2770 if (g_regex_match (regex, response->str, 0, &match_info))
2772 if (gsmd_utils_match_exists(match_info,"used"))
2774 gchar *match = g_match_info_fetch_named(match_info,"used");
2775 gint used = atoi(match);
2776 gsmd_utils_table_insert_int(at->handler_data,GSMD_SIM_KEY_PHONEBOOK_SLOTS_USED,used);
2777 g_free(match);
2779 status = AT_HANDLER_NEED_MORE;
2782 if (gsmd_utils_match_exists(match_info,"error"))
2784 gsmd_utils_send_error(at,
2785 GSMD_ERROR_UNKNOWN,
2786 "FAILED TO GET DEFAULT PHONEBOOK STORAGE SPACE");
2787 status = AT_HANDLER_DONE_ERROR;
2790 if (gsmd_utils_match_exists(match_info,"ok"))
2792 GValue *val = g_hash_table_lookup(at->handler_data,
2793 GSMD_SIM_KEY_PHONEBOOK_SLOTS_USED);
2794 if (!val)
2796 g_warning("%s : Invalid handler data.", __func__);
2798 gsmd_utils_send_error(at,
2799 GSMD_ERROR_UNKNOWN,
2800 "OK WITHOUT RESPONSE");
2802 status = AT_HANDLER_DONE;
2807 if ( error )
2809 g_error_free(error);
2811 g_match_info_free (match_info);
2812 g_regex_unref (regex);
2815 return status;
2819 /* AtCommandHandlerStatus gsmd_sim_handler_set_default_storage_space(ModemInterface *modem, */
2820 /* AtCommandContext *at, */
2821 /* GString *response) */
2822 /* { */
2823 /* AtCommandHandlerStatus status = AT_HANDLER_DONT_UNDERSTAND; */
2824 /* GError **error = NULL; */
2825 /* GRegex *regex = g_regex_new ("(?<error>ERROR)|(?<ok>OK)", 0, 0, error); */
2826 /* GMatchInfo *match_info; */
2829 /* if (g_regex_match (regex, response->str, 0, &match_info)) { */
2830 /* if (gsmd_utils_match_exists(match_info,"error")) { */
2831 /* gsmd_utils_send_error(at, */
2832 /* GSMD_ERROR_UNKNOWN, */
2833 /* "FAILED TO SET DEFAULT PHONEBOOK STORAGE SPACE"); */
2834 /* status = AT_HANDLER_DONE_ERROR; */
2835 /* } */
2837 /* if (gsmd_utils_match_exists(match_info,"ok")) { */
2838 /* //Since storage space changed, it's index boundaries */
2839 /* //might have changed aswell */
2840 /* gsmd_utils_table_insert_int(modem->caches[INTERFACE_SIM], */
2841 /* GSMD_SIM_KEY_LOWEST_INDEX, */
2842 /* 9999); */
2844 /* gsmd_utils_table_insert_int(modem->caches[INTERFACE_SIM], */
2845 /* GSMD_SIM_KEY_HIGHEST_INDEX, */
2846 /* -9999); */
2848 /* GValue *val = g_hash_table_lookup(at->handler_data,GSMD_SIM_KEY_DEFAULT_STORAGE_SPACE); */
2850 /* if (!val) { */
2851 /* g_warning("%s : Invalid handler data. default storage space: %p", */
2852 /* __func__, */
2853 /* val); */
2855 /* gsmd_utils_send_error(at, */
2856 /* GSMD_ERROR_UNKNOWN, */
2857 /* "INVALID HANDLER DATA"); */
2858 /* } */
2860 /* gsmd_utils_table_insert_copy(modem->caches[INTERFACE_SIM], */
2861 /* GSMD_SIM_KEY_DEFAULT_STORAGE_SPACE, */
2862 /* val); */
2864 /* modem->sim_ipc->set_default_storage_space_reply(modem->sim_ipc, */
2865 /* at->ipc_data); */
2867 /* status = AT_HANDLER_DONE; */
2868 /* } */
2870 /* } */
2872 /* g_free(error); */
2873 /* g_match_info_free (match_info); */
2874 /* g_regex_unref (regex); */
2877 /* return status; */
2878 /* } */
2881 /* void gsmd_sim_command_set_default_storage_space(SIMInterface *sim, */
2882 /* gpointer ipc_data, */
2883 /* const char *space) */
2884 /* { */
2885 /* ModemInterface *modem = (ModemInterface*)sim->priv; */
2887 /* GHashTable *data = gsmd_utils_create_hash_table(); */
2888 /* gsmd_utils_table_insert_string(data, */
2889 /* GSMD_SIM_KEY_DEFAULT_STORAGE_SPACE, */
2890 /* space); */
2892 /* gsmd_modem_post_at_command_id( modem, */
2893 /* PHONEBOOK_SPACE_SET, */
2894 /* space, */
2895 /* ipc_data, */
2896 /* (ErrorFunction)modem->sim_ipc->set_default_storage_space_error, */
2897 /* (gpointer)modem->sim_ipc, */
2898 /* INTERFACE_SIM, */
2899 /* data); */
2900 /* } */
2902 static
2903 AtCommandHandlerStatus gsmd_sim_handler_get_index_boundaries(
2904 ModemInterface *modem,
2905 AtCommandContext *at,
2906 GString *response)
2909 AT+CPBR=?
2911 +CPBR: (1-250),20,20
2915 Regular expression: \+CPBR:\s\((\d+)-(\d+)\)
2917 AtCommandHandlerStatus status = AT_HANDLER_DONT_UNDERSTAND;
2918 GError *error = NULL;
2919 GRegex *regex = g_regex_new ("\\+CPBR:\\s\\((?<min>\\d+)-(?<max>\\d+)\\),(?<number_len>\\d+),(?<name_len>\\d+)|"
2920 "(?<error>ERROR)|(?<ok>OK)", 0, 0, &error);
2921 GMatchInfo *match_info;
2922 gchar *match = NULL;
2926 if (g_regex_match (regex, response->str, 0, &match_info))
2928 if (gsmd_utils_match_exists(match_info,"min"))
2930 match = g_match_info_fetch_named(match_info,"min");
2931 gint min = atoi(match);
2932 g_free(match);
2934 match = g_match_info_fetch_named(match_info,"max");
2935 gint max = atoi(match);
2936 gsmd_utils_table_insert_int(at->handler_data,GSMD_SIM_KEY_PHONEBOOK_SLOTS, max-min+1);
2937 g_free(match);
2939 match = g_match_info_fetch_named(match_info,"number_len");
2940 gint number_len = atoi(match);
2941 gsmd_utils_table_insert_int(at->handler_data,GSMD_SIM_KEY_PHONEBOOK_NUMBER_LEN, number_len);
2942 g_free(match);
2944 match = g_match_info_fetch_named(match_info,"name_len");
2945 gint name_len = atoi(match);
2946 gsmd_utils_table_insert_int(at->handler_data,GSMD_SIM_KEY_PHONEBOOK_NAME_LEN, name_len);
2947 g_free(match);
2949 status = AT_HANDLER_NEED_MORE;
2951 else if (gsmd_utils_match_exists(match_info,"error"))
2953 //TODO should empty string be sent as a reply instead?
2954 gsmd_utils_send_error(at,
2955 GSMD_ERROR_UNKNOWN,
2956 "UNABLE TO READ PHONEBOOK INFO");
2957 status = AT_HANDLER_DONE_ERROR;
2959 else if (gsmd_utils_match_exists(match_info,"ok"))
2961 GValue *slots = g_hash_table_lookup(at->handler_data,GSMD_SIM_KEY_PHONEBOOK_SLOTS);
2962 GValue *number_len = g_hash_table_lookup(at->handler_data,GSMD_SIM_KEY_PHONEBOOK_NUMBER_LEN);
2963 GValue *name_len = g_hash_table_lookup(at->handler_data,GSMD_SIM_KEY_PHONEBOOK_NAME_LEN);
2965 if (!slots || !number_len || !name_len)
2967 g_warning("%s : Invalid handler data. slots: %p, number_len: %p, name_len: %p",
2968 __func__, slots, number_len, name_len);
2970 gsmd_utils_send_error(at,
2971 GSMD_ERROR_UNKNOWN,
2972 "INVALID HANDLER DATA");
2973 status = AT_HANDLER_DONE_ERROR;
2975 else
2977 status = AT_HANDLER_DONE;
2983 if ( error )
2985 g_error_free(error);
2987 g_match_info_free (match_info);
2988 g_regex_unref (regex);
2991 return status;
2995 AtCommandHandlerStatus gsmd_sim_handler_delete_entry(ModemInterface *modem,
2996 AtCommandContext *at,
2997 GString *response)
2999 AtCommandHandlerStatus status = AT_HANDLER_DONT_UNDERSTAND;
3000 GError **error = NULL;
3001 GRegex *regex = g_regex_new ("(?<error>ERROR)|(?<ok>OK)", 0, 0, error);
3002 GMatchInfo *match_info;
3005 if (g_regex_match (regex, response->str, 0, &match_info))
3007 if (gsmd_utils_match_exists(match_info,"error"))
3009 gsmd_utils_send_error(at,
3010 GSMD_ERROR_UNKNOWN,
3011 "FAILED TO DELETE PHONEBOOK ENTRY");
3012 status = AT_HANDLER_DONE_ERROR;
3015 if (gsmd_utils_match_exists(match_info,"ok"))
3017 modem->sim_ipc->delete_entry_reply(modem->sim_ipc,
3018 at->ipc_data);
3019 status = AT_HANDLER_DONE;
3024 g_free(error);
3025 g_match_info_free (match_info);
3026 g_regex_unref (regex);
3029 return status;
3032 void gsmd_sim_command_delete_entry(SIMInterface *sim,
3033 gpointer ipc_data,
3034 const int index)
3036 GString* message = g_string_new ("");
3037 g_string_printf(message, "%d",index);
3039 ModemInterface *modem = (ModemInterface*)sim->priv;
3040 gsmd_modem_post_at_command_id( modem,
3041 PHONEBOOK_ENTRY_DELETE,
3042 message->str,
3043 ipc_data,
3044 (ErrorFunction)modem->sim_ipc->delete_entry_error,
3045 (gpointer)modem->sim_ipc,
3046 INTERFACE_SIM,
3047 NULL);
3048 g_string_free(message,TRUE);
3053 AtCommandHandlerStatus gsmd_sim_handler_store_entry(
3054 ModemInterface *modem,
3055 AtCommandContext *at,
3056 GString *response)
3059 AT+CPBW=2,+35844123456789,145,Name
3064 AtCommandHandlerStatus status = AT_HANDLER_DONT_UNDERSTAND;
3065 GError **error = NULL;
3066 GRegex *regex = g_regex_new ("(?<error>ERROR)|(?<ok>OK)", 0, 0, error);
3067 GMatchInfo *match_info;
3070 if (g_regex_match (regex, response->str, 0, &match_info))
3072 if (gsmd_utils_match_exists(match_info,"error"))
3074 gsmd_utils_send_error(at,
3075 GSMD_ERROR_UNKNOWN,
3076 "FAILED TO STORE PHONEBOOK ENTRY");
3077 status = AT_HANDLER_DONE_ERROR;
3080 if (gsmd_utils_match_exists(match_info,"ok"))
3082 modem->sim_ipc->store_entry_reply(modem->sim_ipc,
3083 at->ipc_data);
3084 status = AT_HANDLER_DONE;
3089 g_free(error);
3090 g_match_info_free (match_info);
3091 g_regex_unref (regex);
3094 return status;
3098 void gsmd_sim_command_get_home_zones(SIMInterface *sim,
3099 gpointer ipc_data)
3101 //TODO implement
3102 ModemInterface *modem = (ModemInterface*)sim->priv;
3103 modem->sim_ipc->get_home_zones_reply(modem->sim_ipc,
3104 ipc_data,
3105 NULL);
3108 void gsmd_sim_command_send_generic_sim_command(SIMInterface *sim,
3109 gpointer ipc_data,
3110 const gchar *command)
3112 //TODO implement
3113 ModemInterface *modem = (ModemInterface*)sim->priv;
3114 modem->sim_ipc->send_generic_sim_command_reply(modem->sim_ipc,
3115 ipc_data,
3116 NULL);
3119 void gsmd_sim_command_send_restricted_sim_command(SIMInterface *sim,
3120 gpointer ipc_data,
3121 gint command,
3122 gint fileid,
3123 gint p1,
3124 gint p2,
3125 gint p3,
3126 const gchar *data)
3128 //TODO implement
3129 ModemInterface *modem = (ModemInterface*)sim->priv;
3130 modem->sim_ipc->send_generic_sim_command_reply(modem->sim_ipc,
3131 ipc_data,
3132 NULL);
3136 void gsmd_sim_command_store_entry(SIMInterface *sim,
3137 gpointer ipc_data,
3138 const int index,
3139 const char *name,
3140 const char *number)
3142 GString* message = g_string_new ("");
3143 // TODO Better number checks
3144 if (*number == '+')
3146 g_string_printf(message, "%d,%s,145,%s",index,number,name);
3148 else
3150 g_string_printf(message, "%d,%s,129,%s",index,number,name);
3153 ModemInterface *modem = (ModemInterface*)sim->priv;
3154 gsmd_modem_post_at_command_id( modem,
3155 PHONEBOOK_ENTRY_SET,
3156 message->str,
3157 ipc_data,
3158 (ErrorFunction)modem->sim_ipc->store_entry_error,
3159 (gpointer)modem->sim_ipc,
3160 INTERFACE_SIM,
3161 NULL);
3162 g_string_free(message,TRUE);
3166 AtCommandHandlerStatus gsmd_sim_handler_retrieve_entry(ModemInterface *modem,
3167 AtCommandContext *at,
3168 GString *response)
3171 AT+CPBR=1
3173 +CPBR: 1,"040123456789",129,"Name"
3177 Regular expression: \+CPBR:\s(\d+),"(\w+)",(\d+),"(\w+)"
3179 AtCommandHandlerStatus status = AT_HANDLER_DONT_UNDERSTAND;
3180 GError **error = NULL;
3181 GRegex *regex = g_regex_new ("\\+CPBR:\\s(?<id>\\d)+,\"(?<number>\\+?\\w+)\",(?<type>\\d+),\"(?<text>\\w+)\"|(?<error>ERROR)|(?<ok>OK)", 0, 0, error);
3183 GMatchInfo *match_info;
3186 if (g_regex_match (regex, response->str, 0, &match_info))
3188 if (gsmd_utils_match_exists(match_info,"id"))
3191 gchar *type = g_match_info_fetch_named(match_info,"type");
3192 gchar *name = g_match_info_fetch_named(match_info,"text");
3193 gchar *number = g_match_info_fetch_named(match_info,"number");
3195 //TODO only send this once we have ok
3196 modem->sim_ipc->retrieve_entry_reply(modem->sim_ipc,
3197 at->ipc_data,
3198 name,
3199 number);
3200 g_free(type);
3201 g_free(name);
3202 g_free(number);
3204 status = AT_HANDLER_NEED_MORE;
3207 if (gsmd_utils_match_exists(match_info,"error"))
3209 //TODO should empty string be sent as a reply instead?
3210 gsmd_utils_send_error(at,
3211 GSMD_ERROR_UNKNOWN,
3212 "UNABLE TO READ PHONEBOOK INDEX BOUNDARIES");
3213 status = AT_HANDLER_DONE_ERROR;
3216 if (gsmd_utils_match_exists(match_info,"ok"))
3218 status = AT_HANDLER_DONE;
3223 g_free(error);
3224 g_match_info_free (match_info);
3225 g_regex_unref (regex);
3228 return status;
3233 void gsmd_sim_command_retrieve_entry(SIMInterface *sim,
3234 gpointer ipc_data,
3235 const int index)
3237 GString* message = g_string_new ("");
3238 g_string_printf(message, "%d",index);
3240 ModemInterface *modem = (ModemInterface*)sim->priv;
3241 gsmd_modem_post_at_command_id( modem,
3242 PHONEBOOK_ENTRY_GET,
3243 message->str,
3244 ipc_data,
3245 (ErrorFunction)modem->sim_ipc->retrieve_entry_error,
3246 (gpointer)modem->sim_ipc,
3247 INTERFACE_SIM,
3248 NULL);
3249 g_string_free(message,TRUE);
3253 void gsmd_sim_init(ModemInterface *modem)
3255 modem->sim->priv = (gpointer)modem;
3256 modem->sim->send_auth_code = &gsmd_sim_command_setup_pin;
3257 modem->sim->get_auth_status = &gsmd_sim_command_query_pin_status;
3258 modem->sim->get_sim_info = &gsmd_sim_command_get_sim_info;
3259 modem->sim->change_auth_code = &gsmd_sim_command_change_auth_code;
3260 modem->sim->unlock = &gsmd_sim_command_unlock;
3261 modem->sim->retrieve_messagebook = &gsmd_sim_command_retrieve_messagebook;
3262 modem->sim->retrieve_phonebook = &gsmd_sim_command_retrieve_phonebook;
3263 modem->sim->send_stored_message = &gsmd_sim_command_send_stored_message;
3264 modem->sim->delete_message = &gsmd_sim_command_delete;
3265 modem->sim->set_service_center_number = &gsmd_sim_command_set_service_center;
3266 modem->sim->get_service_center_number = &gsmd_sim_command_query_service_center;
3267 modem->sim->store_message = &gsmd_sim_command_store_message;
3268 modem->sim->retrieve_message = &gsmd_sim_command_read;
3269 modem->sim->retrieve_entry = &gsmd_sim_command_retrieve_entry;
3270 modem->sim->store_entry = &gsmd_sim_command_store_entry;
3271 modem->sim->delete_entry = &gsmd_sim_command_delete_entry;
3272 modem->sim->get_phonebook_info = &gsmd_sim_command_get_phonebook_info;
3273 modem->sim->send_generic_sim_command = &gsmd_sim_command_send_generic_sim_command;
3274 modem->sim->send_restricted_sim_command = &gsmd_sim_command_send_restricted_sim_command;
3275 modem->sim->get_home_zones = &gsmd_sim_command_get_home_zones;
3276 gsmd_sim_init_at_handler(modem);
3280 void gsmd_sim_deinitialize(ModemInterface *modem)