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)
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.
33 #include "gsmd-error.h"
38 static void gsmd_sms_handler_read_free(AtCommandContext
*at
);
40 static gboolean
gsmd_sim_decoder_pdu (guchar
* src
,SmsParam
* pdu
);
43 AtCommandHandlerStatus
gsmd_sim_handler_query_pin_status (ModemInterface
*modem
,
48 AtCommandHandlerStatus
gsmd_sim_handler_query_imsi( ModemInterface
*modem
,
52 AtCommandHandlerStatus
gsmd_sim_handler_pin(ModemInterface
*modem
,
56 AtCommandHandlerStatus
gsmd_sim_handler_read (ModemInterface
*modem
,
60 AtCommandHandlerStatus
gsmd_sim_handler_delete(ModemInterface
*modem
,
65 AtCommandHandlerStatus
gsmd_sim_handler_query_service_center (ModemInterface
*modem
,
70 AtCommandHandlerStatus
gsmd_sim_handler_set_service_center (ModemInterface
*modem
,
75 AtCommandHandlerStatus
gsmd_sim_handler_get_subscriber_numbers (ModemInterface
*modem
,
80 AtCommandHandlerStatus
gsmd_sim_handler_retrieve_messagebook (ModemInterface
*modem
,
85 AtCommandHandlerStatus
gsmd_sim_handler_send_message (ModemInterface
*modem
,
90 void gsmd_sim_handler_retrieve_messagebook_free (AtCommandContext
*at
);
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
,
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
,
116 AtCommandHandlerStatus
gsmd_sim_handler_delete_entry(
117 ModemInterface
*modem
,
118 AtCommandContext
*at
,
122 AtCommandHandlerStatus
gsmd_sim_handler_get_index_boundaries(
123 ModemInterface
*modem
,
124 AtCommandContext
*at
,
127 AtCommandHandlerStatus
gsmd_sim_handler_retrieve_entry(
128 ModemInterface
*modem
,
129 AtCommandContext
*at
,
133 static const AtCommand
138 { PIN_QUERY
, "AT+CPIN?\r\n", 20000,
140 gsmd_sim_handler_query_pin_status
, NULL
, SIM_UNKNOWN
, NULL
},
141 //Query subscriber numbers
142 { QUERY_SUBSCRIBER_NUMBERS
, "AT+CNUM\r\n", 20000,
144 gsmd_sim_handler_get_subscriber_numbers
, NULL
, SIM_UNKNOWN
, NULL
},
147 { PIN_SETUP
, "AT+CPIN=\"%s\"\r\n", 20000,
149 gsmd_sim_handler_pin
, NULL
, SIM_UNKNOWN
, NULL
},
152 { PIN_CHANGE
, "AT+CPIN=%s\r\n", 20000,
154 gsmd_sim_handler_pin
, NULL
, SIM_UNKNOWN
, NULL
},
157 { PUK_SETUP
, "AT+CPIN=%s\r\n", 20000,
159 gsmd_sim_handler_pin
, NULL
, SIM_UNKNOWN
, NULL
},
162 { IMSI_QUERY
, "AT+CIMI\r\n", 5000,
164 gsmd_sim_handler_query_imsi
, NULL
, SIM_READY
},
166 { SMS_READ
, "AT+CMGR=%s\r\n", 5000,
168 gsmd_sim_handler_read
, NULL
, SIM_READY
, gsmd_sms_handler_read_free
},
171 { SMS_DELETE
, "AT+CMGD=%s\r\n", 5000,
173 gsmd_sim_handler_delete
, NULL
, SIM_READY
, NULL
},
175 //Query sms service center
176 { SMS_CENTER_QUERY
, "AT+CSCA?\r\n", 20000,
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,
183 gsmd_sim_handler_set_service_center
, NULL
, SIM_READY
, NULL
},
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, */
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,
204 gsmd_sim_handler_get_phonebook_status
, NULL
, SIM_READY
,
208 /* { PHONEBOOK_SPACE_SET, "AT+CPBS=%s\r\n", 100, */
210 /* gsmd_sim_handler_set_default_storage_space, NULL, SIM_READY, */
213 //Get storage item's index boundaries
214 { PHONEBOOK_GET_INDEX_BOUNDARIES
, "AT+CPBR=?\r\n", 100,
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,
221 gsmd_sim_handler_retrieve_entry
, NULL
, SIM_READY
, NULL
},
224 { PHONEBOOK_ENTRY_SET
, "AT+CPBW=%s\r\n", 100,
226 gsmd_sim_handler_store_entry
, NULL
, SIM_READY
, NULL
},
228 //Delete storage entry
229 { PHONEBOOK_ENTRY_DELETE
, "AT+CPBW=%s\r\n", 100,
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
241 { "SIM", SYMBOL_SIM
, },
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
));
252 while (sim_command_p
->command
)
254 gsmd_modem_register_command (modem
,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
267 void gsmd_sim_change_auth_status( ModemInterface
*modem
,
270 const gchar
*message
,
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
,
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
,
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
,
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
)
315 modem
->sim_ipc
->send_auth_code_reply(modem
->sim_ipc
,at
->ipc_data
);
318 modem
->sim_ipc
->change_auth_code_reply(modem
->sim_ipc
,at
->ipc_data
);
321 modem
->sim_ipc
->unlock_reply(modem
->sim_ipc
,at
->ipc_data
);
327 * @brief Free's messagebook entry
328 * @param msg entry to free
330 void gsmd_sim_handler_retrieve_messagebook_free_entry(messagebook_msg
*msg
)
333 g_string_free(msg
->status
,TRUE
);
335 g_string_free(msg
->number
,TRUE
);
337 g_string_free(msg
->content
,TRUE
);
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
);
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
);
374 GArray
*list
= g_value_get_pointer(val
);
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);
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
,
401 if (!sms
|| !handler_data
)
404 g_debug("%s",__func__
);
405 GValue
*val
= g_hash_table_lookup(handler_data
,GSMD_SIM_KEY_MESSAGE_BOOK
);
409 GArray
*list
= g_value_get_pointer(val
);
414 messagebook_msg
*msg
= g_array_index(list
,messagebook_msg
*,list
->len
-1);
418 g_string_append_len(msg
->content
,(gchar
*)sms
->TP_UD
, (gint
)sms
->TP_UD_LEN
);
422 msg
->status
= g_string_new(gsmd_utils_table_get_string(handler_data
,
423 GSMD_SIM_KEY_MESSAGE_BOOK_TYPE
,
426 msg
->number
= g_string_new((gchar
*)sms
->TPA
);
427 msg
->content
= g_string_new_len((gchar
*)sms
->TPA
,sms
->TP_UD_LEN
);
433 AtCommandHandlerStatus
gsmd_sim_handler_retrieve_messagebook (ModemInterface
*modem
,
434 AtCommandContext
*at
,
449 AtCommandHandlerStatus status
= AT_HANDLER_DONT_UNDERSTAND
;
451 if ( gsmd_utils_parse_cms_error(response
,&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
,
465 g_value_get_pointer(val
));
466 return AT_HANDLER_DONE
;
469 g_warning("%s : CMS ERROR: %d", __func__
, cms_code
);
470 gsmd_utils_send_error(at
,
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
);
495 gsmd_utils_send_error(at
,
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
);
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
,
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
);
523 gsmd_utils_send_error(at
,
525 "OK WITHOUT RESPONSE");
526 status
= AT_HANDLER_DONE_ERROR
;
530 modem
->sim_ipc
->retrieve_messagebook_reply(modem
->sim_ipc
,
532 g_value_get_pointer(val
));
535 status
= AT_HANDLER_DONE
;
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
,
559 else //Otherwise create a new entry
560 gsmd_sim_handler_retrieve_messagebook_fill_last_message(sms
,
567 gsmd_sms_sms_param_free(sms
);
569 status
= AT_HANDLER_NEED_MORE
;
577 g_match_info_free (match_info
);
578 g_regex_unref (regex
);
585 AtCommandHandlerStatus
gsmd_sim_handler_send_message (ModemInterface
*modem
,
586 AtCommandContext
*at
,
589 g_debug("%s",__func__
);
591 AtCommandHandlerStatus status
= AT_HANDLER_DONT_UNDERSTAND
;
592 if (gsmd_utils_send_error_from_response(at
,
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
))
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
,
614 status
= AT_HANDLER_NEED_MORE
;
618 if (gsmd_utils_match_exists(match_info
,"ok"))
620 GValue
*val
= g_hash_table_lookup(at
->handler_data
,GSMD_SIM_KEY_CMSS_ID
);
624 g_warning("%s : Invalid handler data. Didn't get CMSS id",
627 gsmd_utils_send_error(at
,
629 "OK WITHOUT RESPONSE");
630 status
= AT_HANDLER_DONE_ERROR
;
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
;
644 if (gsmd_utils_match_exists(match_info
,"cms"))
646 status
= gsmd_sms_process_sms_error_response (modem
,
654 g_match_info_free (match_info
);
655 g_regex_unref (regex
);
662 * @brief Handler to modems response from setupPin command
664 * @param modem modem whose response to handle
665 * @return true if responses were recognized
668 AtCommandHandlerStatus
gsmd_sim_handler_pin(ModemInterface
*modem
,
669 AtCommandContext
*at
,
673 AtCommandHandlerStatus ret
= AT_HANDLER_DONT_UNDERSTAND
;
675 GScanner
* scanner
= modem
->scanner
;
678 g_debug("gsmd_sim_handler_setup_pin %d", scanner
->token
);
681 g_debug("gsmd_sim_handler_setup_pin error - no scanner");
682 return AT_HANDLER_DONE
;
687 switch (scanner
->token
)
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
;
696 gsmd_utils_send_error(at
,
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
;
714 g_warning("%s : No match to setupPin handler", __func__
);
721 void gsmd_sim_cache_auth_status(ModemInterface
*modem
,
722 AtCommandContext
*at
,
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
738 AtCommandHandlerStatus
gsmd_sim_handler_query_pin_status (ModemInterface
*modem
,
739 AtCommandContext
*at
,
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",
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
,
765 g_value_get_int(status
),
766 g_value_get_string(message
),
769 return AT_HANDLER_DONE
;
772 if (scanner
->token
== SYMBOL_ERROR
)
774 gsmd_utils_send_error(at
,
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
)
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
,
816 gsmd_sim_change_auth_status(modem
,
823 return AT_HANDLER_DONE
;
827 g_scanner_unexp_token (scanner
, ':', NULL
, "symbol",
834 g_scanner_unexp_token (scanner
, SYMBOL_ERROR
, NULL
, "symbol",
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
,
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
,
866 else if (scanner
->token
== SYMBOL_PUK
)
868 gsmd_sim_cache_auth_status(modem
,
874 return AT_HANDLER_NEED_MORE
;
878 g_scanner_unexp_token (scanner
, SYMBOL_READY
, NULL
, "symbol",
883 g_warning("No match after getting + \n");
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
,
902 const char* pin_code
)
904 ModemInterface
*modem
= (ModemInterface
*)sim
->priv
;
905 gsmd_modem_post_at_command_id( modem
,
909 (ErrorFunction
)modem
->sim_ipc
->send_auth_code_error
,
910 (gpointer
)modem
->sim_ipc
,
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
,
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
,
930 g_value_get_string(val
));
934 gsmd_modem_post_at_command_id( modem
,
938 (ErrorFunction
)modem
->sim_ipc
->get_auth_status_error
,
939 (gpointer
)modem
->sim_ipc
,
947 void gsmd_sim_command_unlock(SIMInterface
*sim
,
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
,
961 (ErrorFunction
)modem
->sim_ipc
->unlock_error
,
962 (gpointer
)modem
->sim_ipc
,
965 g_string_free(param
,TRUE
);
969 void gsmd_sim_command_change_auth_code(SIMInterface
*sim
,
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
,
982 (ErrorFunction
)modem
->sim_ipc
->change_auth_code_error
,
983 (gpointer
)modem
->sim_ipc
,
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
998 AtCommandHandlerStatus
gsmd_sim_handler_query_imsi( ModemInterface
*modem
,
999 AtCommandContext
*at
,
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)$",
1015 g_debug("%s : '%s'", __func__
, error
->message
);
1016 g_error_free( error
);
1017 return AT_HANDLER_ERROR
;
1019 GMatchInfo
*match_info
;
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
,
1029 g_debug("%s : imsi : %s", __func__
, match
);
1031 gsmd_utils_table_insert_string(at
->handler_data
,
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
,
1043 g_debug("%s : imsi2 : %s", __func__
, match
);
1044 gsmd_utils_table_insert_string(at
->handler_data
,
1049 status
= AT_HANDLER_NEED_MORE
;
1051 else if (gsmd_utils_match_exists(match_info
,"error"))
1053 gsmd_utils_send_error(at
,
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
);
1064 status
= AT_HANDLER_DONE
;
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
);
1084 gboolean
gsmd_sim_command_get_sim_info_reply(ModemInterface
*modem
,
1088 g_debug("%s", __func__
);
1089 if ( !modem
->no_cache
)
1091 GValue
*imsi
= g_hash_table_lookup(info
,GSMD_SIM_KEY_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
,
1103 AtCommandHandlerStatus
gsmd_sim_handler_get_sim_info( ModemInterface
*modem
,
1104 AtCommandContext
*at
,
1107 AtCommandHandlerStatus status
= AT_HANDLER_DONT_UNDERSTAND
;
1108 switch (at
->command
->cmd_id
)
1111 g_debug("%s : IMSI_QUERY", __func__
);
1112 status
= at
->command
->handler(modem
,at
,response
);
1115 case AT_HANDLER_DONE_ERROR
:
1116 case AT_HANDLER_ERROR
:
1117 return AT_HANDLER_DONE_ERROR
;
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, */
1130 /* (ErrorFunction)modem->sim_ipc->get_subscriber_numbers_error, */
1131 /* (gpointer)modem->sim_ipc, */
1132 /* INTERFACE_SIM, */
1135 case AT_HANDLER_DONT_UNDERSTAND
:
1136 case AT_HANDLER_NEED_MORE
:
1137 case AT_HANDLER_RETRY
:
1145 void gsmd_sim_command_get_sim_info(SIMInterface
*sim
,
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
,
1169 g_hash_table_destroy(info
);
1173 AtCommandContext
*cmd
= NULL
;
1174 cmd
= gsmd_at_command_context_new_from_id( modem
,
1178 (ErrorFunction
)modem
->sim_ipc
->get_sim_info_error
,
1179 (gpointer
)modem
->sim_ipc
,
1181 cmd
->handler
= &gsmd_sim_handler_get_sim_info
;
1182 gsmd_modem_post_at_command(modem
,cmd
,INTERFACE_SIM
);
1188 gboolean
gsmd_sim_command_get_phonebook_info_reply(ModemInterface
*modem
,
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
);
1201 gsmd_utils_table_insert_copy(info
,GSMD_SIM_KEY_PHONEBOOK_SLOTS
,slots
);
1205 gsmd_utils_table_insert_copy(info
,GSMD_SIM_KEY_PHONEBOOK_SLOTS_USED
, used
);
1209 gsmd_utils_table_insert_copy(info
,GSMD_SIM_KEY_PHONEBOOK_NUMBER_LEN
,number_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
,
1223 AtCommandHandlerStatus
gsmd_sim_handler_get_phonebook_info( ModemInterface
*modem
,
1224 AtCommandContext
*at
,
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
);
1236 case AT_HANDLER_DONE_ERROR
:
1237 case AT_HANDLER_ERROR
:
1238 return AT_HANDLER_DONE_ERROR
;
1240 case AT_HANDLER_DONE
:
1241 cmd
= gsmd_at_command_context_new_from_id( modem
,
1242 PHONEBOOK_STATUS_QUERY
,
1245 (ErrorFunction
)modem
->sim_ipc
->get_phonebook_info_error
,
1246 (gpointer
)modem
->sim_ipc
,
1248 at
->handler_data
= NULL
;
1249 cmd
->handler
= &gsmd_sim_handler_get_phonebook_info
;
1250 gsmd_modem_post_at_command(modem
,cmd
,INTERFACE_SIM
);
1252 case AT_HANDLER_DONT_UNDERSTAND
:
1253 case AT_HANDLER_NEED_MORE
:
1254 case AT_HANDLER_RETRY
:
1258 case PHONEBOOK_STATUS_QUERY
:
1259 g_debug("%s : PHONEBOOK_STATUS_QUERY", __func__
);
1260 status
= at
->command
->handler(modem
,at
,response
);
1263 case AT_HANDLER_DONE_ERROR
:
1264 case AT_HANDLER_ERROR
:
1265 return AT_HANDLER_DONE_ERROR
;
1267 case AT_HANDLER_DONE
:
1268 gsmd_sim_command_get_phonebook_info_reply(modem
, at
->ipc_data
, at
->handler_data
);
1270 case AT_HANDLER_DONT_UNDERSTAND
:
1271 case AT_HANDLER_NEED_MORE
:
1272 case AT_HANDLER_RETRY
:
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
,
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
,
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
,
1325 g_hash_table_destroy(info
);
1329 AtCommandContext
*cmd
= NULL
;
1330 cmd
= gsmd_at_command_context_new_from_id( modem
,
1331 PHONEBOOK_GET_INDEX_BOUNDARIES
,
1334 (ErrorFunction
)modem
->sim_ipc
->get_phonebook_info_error
,
1335 (gpointer
)modem
->sim_ipc
,
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
,
1351 const char* centerNo
)
1353 ModemInterface
*modem
= (ModemInterface
*)sim
->priv
;
1354 GString
* command
= g_string_new ("");
1356 if (g_strrstr (centerNo
, "+"))
1358 //Internation format
1366 g_string_printf (command
, "%s,%d", centerNo
, format
);
1367 gsmd_modem_post_at_command_id( modem
,
1371 (ErrorFunction
)modem
->sim_ipc
->set_service_center_number_error
,
1372 (gpointer
)modem
->sim_ipc
,
1375 g_string_free(command
,TRUE
);
1379 * @brief Handler for replies sent by the gsm modem when a service center query
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
,
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
);
1398 g_warning("%s : Invalid handler data. service center: %p",
1402 gsmd_utils_send_error(at
,
1404 "OK WITHOUT RESPONSE");
1406 modem
->sim_ipc
->get_service_center_number_reply(modem
->sim_ipc
,
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
,
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
,
1447 g_value_get_string(val
));
1451 gsmd_modem_post_at_command_id( modem
,
1455 (ErrorFunction
)modem
->sim_ipc
->get_service_center_number_error
,
1456 (gpointer
)modem
->sim_ipc
,
1465 * @brief Handler for replies sent by the gsm modem when a service center query
1468 * @param modem modem whose replies to interpret
1469 * @return true if replies were correct
1472 AtCommandHandlerStatus
gsmd_sim_handler_get_subscriber_numbers (ModemInterface
*modem
,
1473 AtCommandContext
*at
,
1484 return AT_HANDLER_DONE
;
1489 * @brief Handler for replies sent by the gsm modem when a set service centre
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
,
1499 GScanner
* scanner
= modem
->scanner
;
1501 switch (scanner
->token
)
1504 modem
->sim_ipc
->set_service_center_number_reply(modem
->sim_ipc
,
1506 return AT_HANDLER_DONE
;
1509 gsmd_utils_send_error(at
,
1511 "FAILED TO SET SERVICE CENTER");
1512 return AT_HANDLER_DONE_ERROR
;
1517 return AT_HANDLER_DONT_UNDERSTAND
;
1520 static void gsmd_sim_command_store_message (SIMInterface
*sim
,
1522 const gchar
*message
,
1523 const gchar
*number
)
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
,
1539 (ErrorFunction
)modem
->sim_ipc
->store_message_error
,
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
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
);
1579 g_assert(dst_p
< 512);
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
)
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];
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
,
1627 GScanner
* scanner
= modem
->scanner
;
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
,
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
,
1660 if (strlen((char*)*src
) < src_length
+ move
)
1662 if (!gsmd_sms_string_to_bytes(*src
,dst
,src_length
,dst_length
))
1669 static gboolean
gsmd_sim_convert_number(guchar
** src
,
1675 if (!gsmd_sms_invert_number(*src
,dst
,src_length
,is_encode
))
1677 if (strlen((char*)*src
) < move
)
1683 static gboolean
sim_decoder_pdu_header( guchar
**src
, SmsParam
*pdu
)
1687 //the SMSC Number length
1688 if (!gsmd_sim_convert(src
,&tmp
,2,NULL
,4))
1694 if (!gsmd_sim_convert_number(src
,pdu
->SCA
,tmp
,FALSE
,tmp
))
1701 static gboolean
sim_decoder_pdu_type( guchar
**src
, SmsParam
*pdu
)
1705 if (!gsmd_sim_convert(src
,&tmp
,2,NULL
,2))
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
1720 static gboolean
sim_decoder_pdu_sender_num( guchar
**src
, SmsParam
*pdu
)
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))
1737 //length of sender number
1738 if (!gsmd_sim_convert(src
,&pdu
->TOA
,2,NULL
,2))
1741 if (!gsmd_sim_convert_number(src
,pdu
->TPA
,tmp
,FALSE
,tmp
))
1744 gsmd_sim_normalize_received_telnumber (pdu
);
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
)
1763 *src
+=2; //if submit format, skip validity period
1770 static gboolean
sim_decoder_pdu_timestamp( guchar
**src
, SmsParam
*pdu
)
1774 if (!gsmd_sim_convert_number(src
,pdu
->TP_SCTS
,14,FALSE
,14))
1779 memset(pdu
->TP_SCTS
,0,14);
1786 static gboolean
sim_decoder_pdu_userdata( guchar
**src
, SmsParam
*pdu
)
1794 if (!gsmd_sim_convert(src
,&tmp
,2,NULL
,2))
1800 if (!gsmd_sim_convert(src
,&div
,2,NULL
,6))
1802 if (!gsmd_sim_convert(src
,&pdu
->multipart_ref
,2,NULL
,2))
1804 if (!gsmd_sim_convert(src
,&pdu
->multipart_count
,2,NULL
,2))
1806 if (!gsmd_sim_convert(src
,&pdu
->multipart_index
,2,NULL
,2))
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
1824 pdu
->multipart_ref
= 0;
1825 pdu
->multipart_count
= 0;
1826 pdu
->multipart_index
= 0;
1829 if (pdu
->TP_DCS
== GSM_7BIT
)
1832 len
= (tmp
- tmp
/8)*2;
1833 if (!gsmd_sim_convert(src
,buf
,len
,&dst_length
,0))
1836 gsmd_sim_decode_7bits (buf
, pdu
->TP_UD
, dst_length
); //TP-DU
1838 //If it's multipart, remove its header
1841 memmove(pdu
->TP_UD
,&pdu
->TP_UD
[div
],tmp
-div
);
1842 memset(&pdu
->TP_UD
[tmp
-div
],0,div
);
1846 pdu
->TP_UD_LEN
= dst_length
;
1850 else if (pdu
->TP_DCS
== GSM_UCS2
)
1854 if (!gsmd_sim_convert(src
,buf
,len
,&dst_length
,0))
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
;
1865 g_warning("Not supported format");
1872 static gboolean
sim_decoder_pdu_userdata_normalize( guchar
**src
, SmsParam
*pdu
)
1874 gchar code_buffer
[161];
1882 pdu
->number
= g_strdup((gchar
*)pdu
->TPA
);
1886 pdu
->timestamp
= gsmd_utils_convert_to_timestamp((gchar
*)pdu
->TP_SCTS
);
1894 if (pdu
->TP_DCS
== GSM_7BIT
)
1896 pdu
->message
= g_strdup((gchar
*)pdu
->TP_UD
);
1898 else if (pdu
->TP_DCS
== GSM_UCS2
)
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
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
1911 for (i
=0; i
< pdu
->TP_UD_LEN
; i
+= 2)
1919 pdu
->message
= g_strdup(g_utf16_to_utf8 ((gunichar2
*)pdu
->TP_UD
,
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
))
1947 if (!sim_decoder_pdu_type(&src
,pdu
))
1949 if (!sim_decoder_pdu_sender_num(&src
,pdu
))
1951 if (!sim_decoder_pdu_protocol(&src
,pdu
))
1953 if (!sim_decoder_pdu_coding_scheme(&src
,pdu
))
1955 if (!sim_decoder_pdu_validity_period(&src
,pdu
))
1957 if (!sim_decoder_pdu_timestamp(&src
,pdu
))
1959 if (!sim_decoder_pdu_userdata(&src
,pdu
))
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
);
1974 g_string_truncate(input
, 0);
1975 g_string_append(input
,s
);
1977 return (guchar
*)input
->str
;
1982 static void gsmd_sim_command_retrieve_messagebook (SIMInterface
*sim
,
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"};
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("");
2003 if (g_str_equal(status
,valid
[i
]))
2005 g_string_printf(param
,"%d",i
);
2006 gsmd_modem_post_at_command_id( modem
,
2010 (ErrorFunction
)modem
->sim_ipc
->retrieve_messagebook_error
,
2011 (gpointer
)modem
->sim_ipc
,
2014 g_string_free(param
,TRUE
);
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
,
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
,
2039 ModemInterface
*modem
= (ModemInterface
*)sim
->priv
;
2040 gchar
*pos_str
= g_strdup_printf ("%d", pos
);
2041 gsmd_modem_post_at_command_id( modem
,
2045 (ErrorFunction
)modem
->sim_ipc
->delete_message_error
,
2046 (gpointer
)modem
->sim_ipc
,
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
,
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
,
2074 (ErrorFunction
)modem
->sim_ipc
->send_stored_message_error
,
2075 (gpointer
)modem
->sim_ipc
,
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
);
2095 GList
*list
= g_value_get_pointer(val
);
2102 multipart_sms
*sms
= iter
->data
;
2105 g_free(sms
->message
);
2108 iter
= g_list_next(iter
);
2111 g_hash_table_remove(at
->handler_data
,
2112 GSMD_SIM_KEY_PDU_MULTIPART_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
)
2133 multipart_sms
*sms
= list
->data
;
2134 if (sms
&& sms
->multipart_index
== index
)
2135 return sms
->message
;
2136 list
= g_list_next(list
);
2143 * @brief Gets the count of messages to assemble
2145 * Gets the first multipart_sms from glist and returns it's
2147 * @param list GList containing multipart_sms
2148 * @return messages in to assemble
2150 gint
gsmd_sim_handler_read_assemble_get_count(GList
*list
)
2155 multipart_sms
*sms
= list
->data
;
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
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
,
2182 gsmd_utils_send_error(at
,
2184 "INVALID HANDLER DATA");
2185 return AT_HANDLER_DONE_ERROR
;
2188 gint count
= gsmd_sim_handler_read_assemble_get_count(list
);
2192 gsmd_utils_send_error(at
,
2194 "INVALID HANDLER DATA");
2195 return AT_HANDLER_DONE_ERROR
;
2198 GString
*result
= g_string_new("");
2201 for (i
=1;i
<=count
;i
++)
2203 gchar
*part
= gsmd_sim_handler_read_assemble_get_index(list
,i
);
2206 g_string_append(result
,part
);
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
,
2218 gsmd_utils_table_get_string(at
->handler_data
,
2219 GSMD_SIM_KEY_NUMBER
,
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
,
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",
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
,
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'",
2287 part
->multipart_index
,
2288 part
->multipart_count
,
2291 list
= g_list_append(list
,part
);
2293 gsmd_utils_table_insert_pointer(at
->handler_data
,
2294 GSMD_SIM_KEY_PDU_MULTIPART_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
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
,
2317 g_debug("%s",__func__
);
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
))
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
,
2349 "UNABLE TO READ MESSAGE");
2350 status
= AT_HANDLER_DONE_ERROR
;
2351 //If we get ok, then we'll assemble the pieces
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
2360 if (gsmd_utils_match_exists(match_info
,"pdu"))
2362 status
= gsmd_sim_handler_read_check_pdu(modem
,
2369 g_match_info_free (match_info
);
2370 g_regex_unref (regex
);
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
,
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
,
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
,
2415 return gsmd_sim_handler_read_list(modem
,at
,response
);
2418 GScanner
* scanner
= modem
->scanner
;
2420 GString
* input_data
;
2424 symbol
= scanner
->token
;
2426 //pdu_ready will be set when there is +CMGR
2431 SmsParam
*pdu
= g_try_new0(SmsParam
,1);
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"
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
;
2460 //mark handler_data that we are dealing with
2461 //multipart message and store messages reference
2463 gsmd_utils_table_insert_boolean(at
->handler_data
,
2464 GSMD_SIM_KEY_PDU_MULTIPART
,
2466 gsmd_utils_table_insert_int(at
->handler_data
,
2467 GSMD_SIM_KEY_PDU_MULTIPART_REF
,
2468 pdu
->multipart_ref
);
2474 //If it's normal (single) message, store the message
2475 gsmd_utils_table_insert_string(at
->handler_data
,
2476 GSMD_SIM_KEY_MESSAGE
,
2480 //and store phone number and timestamp
2481 gsmd_utils_table_insert_string(at
->handler_data
,
2482 GSMD_SIM_KEY_NUMBER
,
2486 gsmd_utils_table_insert_int(at->handler_data,
2487 GSMD_SIM_KEY_TIMESTAMP,
2492 g_string_free (input_data
, TRUE
);
2494 gsmd_utils_table_insert_boolean(at
->handler_data
,
2495 GSMD_SIM_KEY_PDU_READY
,
2497 gsmd_sms_sms_param_free(pdu
);
2498 return AT_HANDLER_NEED_MORE
;
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
,
2512 gsmd_utils_table_insert_boolean(at
->handler_data
,
2513 GSMD_SIM_KEY_PDU_MULTIPART_LISTING
,
2516 gsmd_modem_serial_write_simple( modem
,
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);
2527 gsmd_utils_send_error(at
,
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
,
2538 g_value_get_string(num
),
2539 g_value_get_string(msg
)
2540 /*,g_value_get_int(time)*/);
2543 return AT_HANDLER_DONE
;
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
,
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
,
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
,
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
,
2591 gsmd_modem_post_at_command_id( modem
,
2595 (ErrorFunction
)modem
->sim_ipc
->retrieve_message_error
,
2596 (gpointer
)modem
->sim_ipc
,
2602 /* void gsmd_sim_free_storage_spaces_array(GHashTable *table) */
2605 /* GValue *val = g_hash_table_lookup(table,GSMD_SIM_KEY_STORAGE_SPACES); */
2607 /* GArray *array = g_value_get_pointer(val); */
2609 /* for (i=0;i<array->len;i++) { */
2610 /* g_string_free(g_array_index(array, */
2615 /* g_array_free(array,TRUE); */
2621 /* static void gsmd_sim_storage_spaces_free(AtCommandContext *at) */
2623 /* gsmd_sim_free_storage_spaces_array(at->handler_data); */
2626 /* AtCommandHandlerStatus */
2627 /* gsmd_sim_handler_get_storage_spaces(ModemInterface *modem, */
2628 /* AtCommandContext *at, */
2629 /* GString *response) */
2634 /* +CPBS: ("SM","FD","LD","MC","RC") */
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); */
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, */
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); */
2673 /* gsmd_utils_table_insert_pointer(at->handler_data, */
2674 /* GSMD_SIM_KEY_STORAGE_SPACES, */
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); */
2692 /* g_warning("%s : Invalid handler data. storage spaces: %p", */
2696 /* gsmd_utils_send_error(at, */
2697 /* GSMD_ERROR_UNKNOWN, */
2698 /* "INVALID HANDLER DATA"); */
2699 /* status = AT_HANDLER_DONE_ERROR; */
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; */
2718 /* g_free(error); */
2719 /* g_match_info_free (match_info); */
2720 /* g_regex_unref (regex); */
2723 /* return status; */
2727 /* void gsmd_sim_command_get_storage_spaces(SIMInterface *sim, */
2728 /* gpointer ipc_data) */
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)); *\/ */
2739 /* gsmd_modem_post_at_command_id( modem, */
2740 /* PHONEBOOK_SPACES_QUERY, */
2743 /* (ErrorFunction)modem->sim_ipc->get_storage_spaces_error, */
2744 /* (gpointer)modem->sim_ipc, */
2745 /* INTERFACE_SIM, */
2750 AtCommandHandlerStatus
gsmd_sim_handler_get_phonebook_status(ModemInterface
*modem
,
2751 AtCommandContext
*at
,
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
);
2779 status
= AT_HANDLER_NEED_MORE
;
2782 if (gsmd_utils_match_exists(match_info
,"error"))
2784 gsmd_utils_send_error(at
,
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
);
2796 g_warning("%s : Invalid handler data.", __func__
);
2798 gsmd_utils_send_error(at
,
2800 "OK WITHOUT RESPONSE");
2802 status
= AT_HANDLER_DONE
;
2809 g_error_free(error
);
2811 g_match_info_free (match_info
);
2812 g_regex_unref (regex
);
2819 /* AtCommandHandlerStatus gsmd_sim_handler_set_default_storage_space(ModemInterface *modem, */
2820 /* AtCommandContext *at, */
2821 /* GString *response) */
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; */
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, */
2844 /* gsmd_utils_table_insert_int(modem->caches[INTERFACE_SIM], */
2845 /* GSMD_SIM_KEY_HIGHEST_INDEX, */
2848 /* GValue *val = g_hash_table_lookup(at->handler_data,GSMD_SIM_KEY_DEFAULT_STORAGE_SPACE); */
2851 /* g_warning("%s : Invalid handler data. default storage space: %p", */
2855 /* gsmd_utils_send_error(at, */
2856 /* GSMD_ERROR_UNKNOWN, */
2857 /* "INVALID HANDLER DATA"); */
2860 /* gsmd_utils_table_insert_copy(modem->caches[INTERFACE_SIM], */
2861 /* GSMD_SIM_KEY_DEFAULT_STORAGE_SPACE, */
2864 /* modem->sim_ipc->set_default_storage_space_reply(modem->sim_ipc, */
2865 /* at->ipc_data); */
2867 /* status = AT_HANDLER_DONE; */
2872 /* g_free(error); */
2873 /* g_match_info_free (match_info); */
2874 /* g_regex_unref (regex); */
2877 /* return status; */
2881 /* void gsmd_sim_command_set_default_storage_space(SIMInterface *sim, */
2882 /* gpointer ipc_data, */
2883 /* const char *space) */
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, */
2892 /* gsmd_modem_post_at_command_id( modem, */
2893 /* PHONEBOOK_SPACE_SET, */
2896 /* (ErrorFunction)modem->sim_ipc->set_default_storage_space_error, */
2897 /* (gpointer)modem->sim_ipc, */
2898 /* INTERFACE_SIM, */
2903 AtCommandHandlerStatus
gsmd_sim_handler_get_index_boundaries(
2904 ModemInterface
*modem
,
2905 AtCommandContext
*at
,
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
);
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);
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
);
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
);
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
,
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
,
2972 "INVALID HANDLER DATA");
2973 status
= AT_HANDLER_DONE_ERROR
;
2977 status
= AT_HANDLER_DONE
;
2985 g_error_free(error
);
2987 g_match_info_free (match_info
);
2988 g_regex_unref (regex
);
2995 AtCommandHandlerStatus
gsmd_sim_handler_delete_entry(ModemInterface
*modem
,
2996 AtCommandContext
*at
,
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
,
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
,
3019 status
= AT_HANDLER_DONE
;
3025 g_match_info_free (match_info
);
3026 g_regex_unref (regex
);
3032 void gsmd_sim_command_delete_entry(SIMInterface
*sim
,
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
,
3044 (ErrorFunction
)modem
->sim_ipc
->delete_entry_error
,
3045 (gpointer
)modem
->sim_ipc
,
3048 g_string_free(message
,TRUE
);
3053 AtCommandHandlerStatus
gsmd_sim_handler_store_entry(
3054 ModemInterface
*modem
,
3055 AtCommandContext
*at
,
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
,
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
,
3084 status
= AT_HANDLER_DONE
;
3090 g_match_info_free (match_info
);
3091 g_regex_unref (regex
);
3098 void gsmd_sim_command_get_home_zones(SIMInterface
*sim
,
3102 ModemInterface
*modem
= (ModemInterface
*)sim
->priv
;
3103 modem
->sim_ipc
->get_home_zones_reply(modem
->sim_ipc
,
3108 void gsmd_sim_command_send_generic_sim_command(SIMInterface
*sim
,
3110 const gchar
*command
)
3113 ModemInterface
*modem
= (ModemInterface
*)sim
->priv
;
3114 modem
->sim_ipc
->send_generic_sim_command_reply(modem
->sim_ipc
,
3119 void gsmd_sim_command_send_restricted_sim_command(SIMInterface
*sim
,
3129 ModemInterface
*modem
= (ModemInterface
*)sim
->priv
;
3130 modem
->sim_ipc
->send_generic_sim_command_reply(modem
->sim_ipc
,
3136 void gsmd_sim_command_store_entry(SIMInterface
*sim
,
3142 GString
* message
= g_string_new ("");
3143 // TODO Better number checks
3146 g_string_printf(message
, "%d,%s,145,%s",index
,number
,name
);
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
,
3158 (ErrorFunction
)modem
->sim_ipc
->store_entry_error
,
3159 (gpointer
)modem
->sim_ipc
,
3162 g_string_free(message
,TRUE
);
3166 AtCommandHandlerStatus
gsmd_sim_handler_retrieve_entry(ModemInterface
*modem
,
3167 AtCommandContext
*at
,
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
,
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
,
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
;
3224 g_match_info_free (match_info
);
3225 g_regex_unref (regex
);
3233 void gsmd_sim_command_retrieve_entry(SIMInterface
*sim
,
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
,
3245 (ErrorFunction
)modem
->sim_ipc
->retrieve_entry_error
,
3246 (gpointer
)modem
->sim_ipc
,
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
)