Random fixes and cleanups
[gsmd2.git] / src / utils.c
blob73506d2c633afa4a9bc8b86ab89ea636f6ac7924
1 /*
2 * utils.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
30 #include "utils.h"
31 #include <string.h>
32 #include <stdlib.h>
35 #include <fcntl.h>
36 #include <unistd.h>
38 #include <dbus/dbus.h>
39 #include <dbus/dbus-glib-lowlevel.h>
41 #define ERROR_PREFIX "org.freesmartphone.GSM."
43 const gchar* call_status_names[] = {"CALL_IDLE",
44 "CALL_CALLING",
45 "CALL_CONNECTED",
46 "CALL_WAITING",
47 "CALL_INCOMING",
48 "CALL_HOLD"
50 /**
51 * @brief Converts call status to a string and returns it
53 * @param status status to convert
54 * @return const gchar* containing status' name
56 const gchar *gsmd_utils_call_status_to_string(CallStatus status)
58 return call_status_names[status];
61 /**
62 * @brief Converts callstatus to a status string understood by
63 * freesmartphone.org's otapi
65 * @param status call's status to convert
66 * @return const gchar* containing status
68 const gchar *gsmd_utils_call_status_to_fso(CallStatus status)
70 switch (status) {
71 case CALL_IDLE:
72 return "unknown";
73 break;
74 case CALL_WAITING:
75 case CALL_CALLING:
76 return "outgoing";
77 break;
78 case CALL_CONNECTED:
79 return "active";
80 break;
81 case CALL_INCOMING:
82 return "incoming";
83 break;
84 case CALL_HOLD:
85 return "held";
86 break;
88 return NULL;
92 /**
93 * @brief Check if the scanner has standard end token "OK" or "ERROR"
95 * @param scanner the input scanner
97 * @return if the scanner is string "OK" or "ERROR" return TRUE, otherwise FALSE
99 gboolean gsmd_utils_check_end_token(GScanner* scanner)
101 if ((scanner->token == SYMBOL_OK) || (scanner->token == SYMBOL_ERROR)) {
102 return TRUE;
103 } else {
104 return FALSE;
110 * @brief Helper function to check if a regular expression match exists
112 * @param match_info match info to check
113 * @param name name to match
114 * @return TRUE if match exists
116 gboolean gsmd_utils_match_exists(GMatchInfo *match_info,const char *name)
118 gboolean result = FALSE;
119 gchar *match = g_match_info_fetch_named(match_info,name);
121 if (match && strlen(match) > 0)
122 result = TRUE;
124 g_free(match);
126 return result;
130 static
131 const gchar* gsmd_utils_get_error_name(GsmdErrorCode code)
133 const gchar *name = NULL;
134 switch(code)
136 case GSMD_ERROR_DEVICE_TIMEOUT:
137 name = ERROR_PREFIX "Device.Timeout";
138 break;
139 case GSMD_ERROR_NOTSUPPORTED:
140 name = ERROR_PREFIX "UnsupportedCommand";
141 break;
142 case GSMD_ERROR_NETWORK_NOT_PRESENT:
143 name = ERROR_PREFIX "Network.NotPresent";
144 break;
145 case GSMD_ERROR_SIM_UNAUTHORIZED:
146 name = ERROR_PREFIX "SIM.Unauthorized";
147 break;
148 case GSMD_ERROR_INTERNAL:
149 name = ERROR_PREFIX "Unknown.Internal";
150 break;
151 case GSMD_ERROR_CALL_NOTFOUND:
152 name = ERROR_PREFIX "Call.NotFound";
153 break;
154 case GSMD_ERROR_CALL_INVALIDSTATE:
155 name = ERROR_PREFIX "Call.InvalidState";
156 break;
157 case GSMD_ERROR_UNKNOWN:
158 case GSMD_ERROR_RESET:
159 default:
160 name = ERROR_PREFIX "Device.Failed";
161 break;
163 return name;
167 * @brief Creates a GError with given data and calls error_function
169 * @param error_function error function to call
170 * @param ipc_data ipc data for the error function
171 * @param code error code for GError
172 * @param message error message
174 void gsmd_utils_send_error_full(ErrorFunction error_function,
175 gpointer error_data,
176 gpointer ipc_data,
177 GsmdErrorCode code,
178 const char *message)
180 if (error_function && error_data) {
181 GError *err = NULL;
182 DBusError error = {0,};
183 error.name = gsmd_utils_get_error_name(code);
184 error.message = message;
185 dbus_set_g_error(&err, &error);
186 error_function(error_data,ipc_data,err);
187 g_error_free( err );
193 * @brief Send error response according to scanner's data
195 * @param at current command's context
196 * @param response modem's reply
197 * @param errormsg error message to send if scanner has ERROR token
198 * @param timeoutmsg error message to send if scanner has TIMEOUT token
199 * @return TRUE if ERROR or TIMEOUT found and response was sent
201 gboolean gsmd_utils_send_error_from_response(AtCommandContext *at,
202 GString* response,
203 const gchar *errormsg,
204 const gchar *timeoutmsg)
206 g_assert(at);
208 static GRegex *regex_error = NULL;
209 static GRegex *regex_timeout = NULL;
210 if( !regex_error ) {
211 GError *error = NULL;
212 regex_error = g_regex_new ("^ERROR$", 0, 0, &error);
213 if ( error ) {
214 g_error("%s: %s", __func__, error->message);
216 regex_timeout = g_regex_new ("^TIME_OUT$", 0, 0, &error);
217 if ( error ) {
218 g_error("%s: %s", __func__, error->message);
221 GMatchInfo *match_info;
223 if (g_regex_match (regex_error, response->str, 0, &match_info)) {
224 gsmd_utils_send_error(at,
225 GSMD_ERROR_UNKNOWN,
226 errormsg);
227 return TRUE;
230 if (g_regex_match (regex_timeout, response->str, 0, &match_info)) {
231 gsmd_utils_send_error(at,
232 GSMD_ERROR_DEVICE_TIMEOUT,
233 timeoutmsg);
234 return TRUE;
236 gint code = 0;
237 if( gsmd_utils_parse_cms_error(response, &code) ) {
238 g_warning("%s : CMS ERROR: %d", __func__, code);
239 gsmd_utils_send_error(at,
240 GSMD_ERROR_UNKNOWN,
241 errormsg);
242 return TRUE;
244 if( gsmd_utils_parse_cme_error(response, &code) ) {
245 g_warning("%s : CME ERROR: %d", __func__, code);
246 gsmd_utils_send_error(at,
247 GSMD_ERROR_UNKNOWN,
248 errormsg);
249 return TRUE;
251 return FALSE;
255 * @brief Sends error for given at command context with given message
257 * @param at at command context whose error function to call
258 * @param code error's code
259 * @param message error message to send
261 void gsmd_utils_send_error(AtCommandContext *at,
262 GsmdErrorCode code,
263 const char *message)
265 gsmd_utils_send_error_full(at->error_function,
266 at->error_data,
267 at->ipc_data,
268 code,
269 message);
273 * @brief Prints information on all current calls
275 * @param modem pointer to modem interface
277 void gsmd_utils_print_calls(ModemInterface *modem)
279 GList *list = modem->calls;
280 Call *call = NULL;
281 gint index = 0;
282 if( list ) {
283 list = g_list_nth(list, g_list_length(list)-1);
285 while ( list ) {
286 call = (Call*)list->data;
287 g_debug("Call %d",index);
288 g_debug("---");
289 g_debug("Status: %s",gsmd_utils_call_status_to_string(call->status));
290 g_debug("Number: %s",call->number->str);
291 g_debug("Type: %s",call->type->str);
292 g_debug("Id: %d",call->id);
293 g_debug("Index: %d",call->index);
294 g_debug("Vendor id: %d",call->vendor_id);
296 g_debug("\n");
298 list = g_list_previous( list );
299 index++;
304 * @brief Finds first call with given status
306 * @param modem pointer to modem interface
307 * @param status call status to find
308 * @return call pointer or NULL if none found
310 Call* gsmd_utils_find_first_call_status(ModemInterface *modem,
311 CallStatus status)
313 g_debug("%s", __func__);
314 GList *list = modem->calls;
315 Call *call = NULL;
316 while ( list ) {
317 call = (Call*)list->data;
318 if (call->status == status)
319 return call;
320 list = g_list_next( list );
323 return NULL;
327 * @brief Finds call with given phone number
329 * @param modem pointer to modem interface
330 * @param number call's number to find
331 * @return call or NULL if none found
333 Call* gsmd_utils_find_call_number(ModemInterface *modem, const gchar *number)
335 g_debug("%s", __func__);
336 GList *list = modem->calls;
337 Call *call = NULL;
338 while ( list ) {
339 call = (Call*)list->data;
340 if (strcmp(call->number->str, number) == 0) {
341 return call;
343 g_debug("%s : call (0x%x) id: %d, number %s != %s", __func__,(guint)call,
344 call->id, call->number->str, number);
345 list = g_list_next( list );
347 return NULL;
351 * @brief Finds call with given id
353 * @param modem pointer to modem interface
354 * @param id id to find
355 * @return call or NULL if none found
357 Call* gsmd_utils_find_call_id(ModemInterface *modem, guint id)
359 g_debug("%s", __func__);
360 GList *list = modem->calls;
361 Call *call = NULL;
362 while ( list ) {
363 call = (Call*)list->data;
364 if (call->id == id) {
365 return call;
367 g_debug("%s : call (0x%x) id: %d != %d", __func__,(guint)call, call->id, id);
368 list = g_list_next( list );
370 return NULL;
375 * @brief Returns the first call
377 * @param modem pointer to modem interface
378 * @return call or NULL if none found
380 Call* gsmd_utils_get_first_call(ModemInterface *modem)
382 GList *list = modem->calls;
383 if ( list ) {
384 return list->data;
386 return NULL;
390 * @brief Finds call with given vendor id
392 * @param modem pointer to modem interface
393 * @param vendor_id vendor id to find
394 * @return call or NULL if none found
396 Call* gsmd_utils_find_call_vendor_id(ModemInterface *modem, gint vendor_id)
398 g_debug("%s", __func__);
399 GList *list = modem->calls;
400 Call *call = NULL;
401 while ( list ) {
402 call = (Call*)list->data;
403 if (call->vendor_id == vendor_id) {
404 return call;
406 g_debug("%s : Call vendor id: %d, wanted %d", __func__, call->vendor_id, vendor_id);
407 list = g_list_next( list );
410 return NULL;
414 * @brief Gets specified call's status
416 * @param modem pointer to modem interface
417 * @param id call id of the call whose status to get
418 * @return call's status or CALL_IDLE if none found
420 CallStatus gsmd_utils_get_call_status(ModemInterface *modem, gint id)
422 g_debug("%s", __func__);
423 Call *call = gsmd_utils_find_call_id(modem,id);
424 if (call)
425 return call->status;
427 return CALL_IDLE;
432 * @brief Returns the number of calls with specified status
434 * @param modem pointer to modem interface
435 * @param status calls with this status to count
436 * @return count of calls with specified status
438 gint gsmd_utils_get_call_status_count(ModemInterface *modem,CallStatus status)
440 gint result = 0;
441 GList *list = modem->calls;
442 Call *call = NULL;
443 while ( list ) {
444 call = (Call*)list->data;
445 if (call->status == status)
446 result++;
447 list = g_list_next( list );
450 return result;
454 * @brief Finds first unknown modem id and sets given id to it
456 * @param modem pointer to modem struct
457 * @param vendor_id new call id to be set
459 void gsmd_utils_set_unknown_vendor_id(ModemInterface *modem, gint vendor_id)
461 g_debug("%s", __func__);
462 GList *list = modem->calls;
463 Call *call = NULL;
464 while ( list ) {
465 call = (Call*)list->data;
466 if (call->vendor_id == -1) {
467 call->vendor_id = vendor_id;
468 g_debug("%s : Setting call vendor id %d for call %d", __func__, call->vendor_id, call->id);
469 return;
471 list = g_list_next( list );
474 gsmd_utils_print_calls(modem);
475 g_warning("%s : No unknown calls!", __func__);
480 * @brief Free's call's data
482 * @param call Call whose data to free
484 void gsmd_utils_call_free(Call *call)
486 g_assert(call);
487 if (call->number)
488 g_string_free(call->number,TRUE);
489 if (call->type)
490 g_string_free(call->type,TRUE);
491 g_hash_table_destroy(call->vendor_properties);
492 call->type = NULL;
493 call->number = NULL;
494 g_free(call);
498 * @brief Helper function to get call propeties for status signal/reply
500 * @param call call which properties to get
502 GHashTable* gsmd_utils_call_get_properties(Call *call)
504 GHashTable *properties = gsmd_utils_create_hash_table();
505 GList *keys = g_hash_table_get_keys(call->vendor_properties);
506 GList *list = keys;
507 while(list ) {
508 gchar *key = (gchar*)list->data;
509 GValue *val = g_hash_table_lookup(call->vendor_properties, key);
510 gsmd_utils_table_insert_copy(properties, key, val);
511 list = g_list_next(list);
513 gsmd_utils_table_insert_string(properties,
514 GSMD_MODEM_KEY_PHONE_NUMBER,
515 call->number->str);
516 return properties;
520 * @brief Helper function to send a call status signal with given status
522 * @param modem Modem who owns call
523 * @param call call which status signal to send
524 * @param status status to be sent
525 * @param phonenumber should phone number be added to properties
527 void gsmd_utils_call_send_status(ModemInterface *modem,
528 Call *call,
529 const gchar *status)
531 g_debug("%s", __func__);
532 if (modem && modem->call_ipc->call_status && call) {
533 GHashTable *properties = gsmd_utils_call_get_properties(call);
535 modem->call_ipc->call_status(modem->call_ipc,
536 call->id,
537 status,
538 properties);
539 g_hash_table_destroy(properties);
546 * @brief Removes given call from modem's list
548 * @param modem pointer to modem interface to remove call from
549 * @param call pointer to call to remove
550 * @param send_released_call should signal be sent that a call was released
552 void gsmd_utils_remove_call_direct(ModemInterface *modem,
553 Call *call,
554 gboolean send_released_call)
556 if ( call ) {
557 if ( send_released_call)
558 gsmd_utils_call_send_status(modem,call,"released");
561 modem->calls = g_list_remove(modem->calls, call);
562 gsmd_utils_call_free(call);
567 * @brief Removes all calls that have a specific status
569 * @param modem pointer to modem interface to remove calls from
570 * @param status status of the calls to be removed
571 * @param send_released_call should signal be sent that a call was released for
572 * all calls
574 void gsmd_utils_remove_calls_with_status(ModemInterface *modem,
575 CallStatus status,
576 gboolean send_released_call)
578 GList *list = modem->calls;
579 Call *call = NULL;
580 while ( list ) {
581 call = (Call*)list->data;
582 if (call->status == status) {
583 gsmd_utils_remove_call_direct(modem,call,send_released_call);
584 break;
586 list = g_list_next( list );
592 * @brief Removes all calls
594 * @param modem pointer to modem interface
595 * @param send_released_call If true, send ReleasedCall signal
597 void gsmd_utils_remove_calls(ModemInterface *modem,
598 gboolean send_released_call)
600 g_debug("%s", __func__);
601 GList *list = modem->calls;
602 Call *call = NULL;
603 while ( list ) {
604 call = (Call*)list->data;
605 g_debug("%s : Removing call id %d (vendor id %d)", __func__, call->id, call->vendor_id);
606 gsmd_utils_call_send_status(modem,call,"released");
607 gsmd_utils_call_free(call);
608 list = g_list_next( list );
611 g_list_free(modem->calls);
612 modem->calls = NULL;
617 * @brief Removes a call from call array
619 * @param modem pointer to modem interface
620 * @param id id of the call to remove
621 * @param send_released_call If true, send ReleasedCall signal
623 void gsmd_utils_remove_call(ModemInterface *modem,
624 guint id,
625 gboolean send_released_call)
627 g_debug("%s", __func__);
628 GList *list = modem->calls;
629 Call *call = NULL;
630 while ( list ) {
631 call = (Call*)list->data;
632 if (call->id == id) {
633 g_debug("%s : Removing call id %d (vendor id %d)", __func__, id, call->vendor_id);
634 gsmd_utils_remove_call_direct(modem,call,send_released_call);
635 break;
637 list = g_list_next( list );
638 call = NULL;
644 * @brief Removes a call with given vendor id from call array
646 * @param modem pointer to modem interface
647 * @param vendor_id vendor id of the call to remove
649 void gsmd_utils_remove_call_vendor_id(ModemInterface *modem,
650 gint vendor_id,
651 gboolean send_released_call)
653 g_debug("%s", __func__);
654 Call *call = gsmd_utils_find_call_vendor_id(modem,vendor_id);
655 gsmd_utils_remove_call(modem,
656 call->id,
657 send_released_call);
662 * @brief Get latest call that was made or received
664 * @param modem pointer to modem interface
666 * @return Latest call or NULL if none
668 Call* gsmd_utils_call_get_current(ModemInterface *modem)
670 g_debug("%s", __func__);
671 return modem->calls ? (Call*)modem->calls->data : NULL;
675 * @brief Creates a new call and and adds it to call array
677 * @param modem pointer to modem struct
678 * @param number phone number of the remote end
679 * @param type call type
680 * @param status Call status
681 * @return the newly created call
683 Call* gsmd_utils_new_call(ModemInterface *modem,
684 const gchar *number,
685 const gchar *type,
686 CallStatus status)
688 // FIXME conflict possible after 2^sizeof(guint) calls ;)
689 static guint call_id = 0;
690 Call *call = g_new0(Call,1);
691 g_debug("%s : New call 0x%x", __func__, (guint)call);
692 call->status = status;
693 call->type = g_string_new(type);
694 call->number = g_string_new(number);
695 call->id = call_id++;
696 call->vendor_id = -1;
697 call->index = -1;
698 call->vendor_properties = gsmd_utils_create_hash_table();
699 modem->calls = g_list_prepend(modem->calls, call);
700 return call;
703 * @brief Helper function to create a gvalue from given int
704 * and insert it to given table
706 * @param table GHashTable to insert gvalue to
707 * @param key key to insert value with
708 * @param value value to insert
710 void gsmd_utils_table_insert_int(GHashTable *table,
711 gchar *key,
712 const gint value)
714 GValue *val = g_new0(GValue,1);
715 g_value_init(val,G_TYPE_INT);
716 g_value_set_int(val,value);
717 g_hash_table_insert(table,
718 key,
719 val);
723 * @brief Helper function to create a gvalue from given string
724 * and insert it to given table
726 * @param table GHashTable to insert gvalue to
727 * @param key key to insert value with
728 * @param value value to insert
730 void gsmd_utils_table_insert_string(GHashTable *table,
731 gchar *key,
732 const gchar *value)
734 GValue *val = g_new0(GValue,1);
735 g_value_init(val,G_TYPE_STRING);
736 g_value_set_string(val,value);
737 g_hash_table_insert(table,
738 key,
739 val);
743 * @brief Helper function to create a gvalue from given boolean
744 * and insert it to given table
746 * @param table GHashTable to insert gvalue to
747 * @param key key to insert value with
748 * @param value value to insert
750 void gsmd_utils_table_insert_boolean(GHashTable *table,
751 gchar *key,
752 const gboolean value)
754 GValue *val = g_new0(GValue,1);
755 g_value_init(val,G_TYPE_BOOLEAN);
756 g_value_set_boolean(val,value);
757 g_hash_table_insert(table,
758 key,
759 val);
764 * @brief Helper function to get string value from hashtable
766 * @param table GHashTable to get string value from
767 * @param key key to find value with
768 * @param value default to return if no value found
770 const gchar *gsmd_utils_table_get_string(GHashTable *table,
771 gchar *key,
772 const gchar* value)
774 GValue *val = g_hash_table_lookup(table,key);
775 if (!val)
776 return value;
777 return g_value_get_string(val);
781 * @brief Helper function to get boolean value from hashtable
783 * @param table GHashTable to get boolean value from
784 * @param key key to find value with
785 * @param value default to return if no value found
787 gboolean gsmd_utils_table_get_boolean(GHashTable *table,
788 gchar *key,
789 gboolean value)
791 GValue *val = g_hash_table_lookup(table,key);
792 if (!val)
793 return value;
794 return g_value_get_boolean(val);
798 * @brief Helper function to get int value from hashtable
800 * @param table GHashTable to get int value from
801 * @param key key to find value with
802 * @param value default to return if no value found
804 gint gsmd_utils_table_get_int(GHashTable *table,
805 gchar *key,
806 gint value)
808 GValue *val = g_hash_table_lookup(table,key);
809 if (!val)
810 return value;
811 return g_value_get_int(val);
815 * @brief Helper function to get pointer value from hashtable
817 * @param table GHashTable to get pointer value from
818 * @param key key to find value with
819 * @param value default to return if no value found
821 gpointer gsmd_utils_table_get_pointer(GHashTable *table,
822 gchar *key,
823 gpointer value)
825 GValue *val = g_hash_table_lookup(table,key);
826 if (!val)
827 return value;
828 return g_value_get_pointer(val);
832 * @brief Helper function to create a gvalue from given pointer
833 * and insert it to given table
835 * @param table GHashTable to insert value to
836 * @param key key to insert value with
837 * @param value value to insert
839 void gsmd_utils_table_insert_pointer(GHashTable *table,
840 gchar *key,
841 const gpointer value)
843 GValue *val = g_new0(GValue,1);
844 g_value_init(val,G_TYPE_POINTER);
845 g_value_set_pointer(val,value);
846 g_hash_table_insert(table,
847 key,
848 val);
853 * @brief Helper function to create a copy of gvalue and insert it
854 * to given hash table
856 * @param table ghashtable to insert copy of given value
857 * @param key value's key
858 * @param value value to copy and insert
860 void gsmd_utils_table_insert_copy(GHashTable *table,
861 gchar *key,
862 GValue *value)
864 g_assert(table);
865 g_assert(value);
867 GValue *copy = g_new0(GValue,1);
868 g_value_init(copy,G_VALUE_TYPE(value));
869 g_value_copy(value,copy);
870 g_hash_table_insert(table,key,copy);
874 * @brief Fetches a matching text, converts it to int and returns it
876 * @param matc_info match info to fetch value from
877 * @param match key to fetch
878 * @param value default value to return if matching value was not found
879 * @return matching text converted to int
881 gint gsmd_utils_fetch_match_int(GMatchInfo *match_info,
882 gchar *match,
883 gint value)
885 gchar *str = g_match_info_fetch_named(match_info,match);
886 gint result = atoi(str);
887 g_free(str);
888 return result;
892 * @brief Fetches a matching text, converts it to GString and returns it
894 * @param matc_info match info to fetch value from
895 * @param match key to fetch
896 * @param value default value to return if matching value was not found
897 * @return matching text converted to GString
899 GString *gsmd_utils_fetch_match_string(GMatchInfo *match_info,
900 gchar *match,
901 GString *value)
903 gchar *str = g_match_info_fetch_named(match_info,match);
904 GString *result = g_string_new(str);
905 g_free(str);
906 return result;
910 * @brief Function to free gvalue
912 * @param data gvalue pointer
914 void gsmd_utils_gvalue_free(gpointer data)
916 GValue *val = data;
917 g_value_unset(val);
918 g_free(val);
922 * @brief Defaults serial port initializer
924 * @param device device
925 * @param cflag control mode flag
926 * @param speed serial port's speed
927 * @return handle
929 gint gsmd_utils_default_serial_init (const gchar *device,
930 tcflag_t cflag,
931 speed_t speed)
933 g_debug("%s", __func__);
934 struct termios t;
935 gint fd = g_open (device, O_RDWR | O_APPEND | O_NOCTTY | O_NONBLOCK, 0);
936 if ( !fd ) {
937 g_warning("%s : open failed: '%s'", __func__, device);
938 return 0;
940 if (tcgetattr(fd, &t) < 0) {
941 g_warning("%s : get attr failed '%s'", __func__, device);
942 goto error;
945 cfsetispeed(&t, speed);
946 cfsetospeed(&t, speed);
948 t.c_cflag = cflag;
949 t.c_lflag &= ~(ICANON|ECHO);
950 t.c_iflag &= ~(IXON|ICRNL);
951 t.c_oflag &= ~(ONLCR);
952 t.c_cc[VMIN] = 0;
953 t.c_cc[VTIME] = 0;
954 // t.c_cc[VSUSP] = 0;
956 if (tcsetattr (fd, TCSANOW, &t) < 0) {
957 g_warning("%s : setattr failed", __func__);
958 goto error;
960 return fd;
961 error:
962 close( fd );
963 return 0;
967 * @brief Creates a new hash table with string keys and GValue values
968 * This is to be used throughout gsmd2 and with ipc mechanisms aswell.
970 * @return new hash table
972 GHashTable *gsmd_utils_create_hash_table()
974 return g_hash_table_new_full(NULL,
975 g_str_equal,
976 NULL,
977 gsmd_utils_gvalue_free);
981 * @brief Handler to scan for OK/ERROR/TIMEOUT message
982 * Returns AT_HANDLER_DONE on OK
983 * Returns AT_HANDLER_DONE_ERROR on ERROR
984 * Returns AT_HANDLER_RETRY on TIMEOUT
985 * Or returns AT_HANDLER_DONT_UNDERSTAND
988 * @param modem modem to scan
989 * @param at at command's context
990 * @param response string modem sent
991 * @return true if OK/ERROR scanned
993 AtCommandHandlerStatus gsmd_utils_handler_ok (ModemInterface *modem,
994 AtCommandContext *at,
995 GString *response)
997 GScanner* scanner = modem->scanner;
998 switch (scanner->token) {
999 case SYMBOL_OK:
1000 return AT_HANDLER_DONE;
1001 case SYMBOL_ERROR:
1002 return AT_HANDLER_DONE_ERROR;
1003 case SYMBOL_TIME_OUT:
1004 return AT_HANDLER_RETRY;
1005 default:
1006 return AT_HANDLER_DONT_UNDERSTAND;
1011 * @brief Helper utility that prints command or data along with special characters
1012 * @param func function's name to prepend to the text
1013 * @param prepend text to prepend before command
1014 * @param data data to write
1016 void gsmd_utils_print_data(const gchar *func,
1017 const gchar *prepend,
1018 const gchar *data)
1021 GString *debug_str = g_string_new(func);
1022 if (prepend)
1023 g_string_append_printf(debug_str," : %s",prepend);
1024 else
1025 g_string_append_printf(debug_str," : ");
1027 gint i;
1028 for (i=0; i < strlen(data); i++) {
1029 switch (data[i]) {
1031 case '\r':
1032 g_string_append(debug_str, "\\r");
1033 break;
1034 case '\n':
1035 g_string_append(debug_str, "\\n");
1036 break;
1037 case '%':
1038 g_string_append(debug_str, "%%");
1039 break;
1040 case 26:
1041 g_string_append(debug_str, "<EOF>");
1042 break;
1043 default:
1044 g_string_append_printf(debug_str, "%c", data[i]);
1045 break;
1049 g_string_append(debug_str, "<end>");
1050 g_debug(debug_str->str);
1051 g_string_free( debug_str, TRUE);
1055 * @brief returns integer from first 2 characters
1057 * @param str str whose first 2 characters to convert
1058 * @return integer
1060 int gsmd_utils_convert_to_int(const gchar *str)
1062 gchar two[3] = {0};
1063 memcpy(two,str,2);
1064 return atoi(two);
1068 * @brief Converts timestamp information from pdu to time_t
1070 * @param str string containing timestamp information
1071 * @return timestamp converted to time_t
1073 time_t gsmd_utils_convert_to_timestamp(const gchar *str)
1075 if (strlen(str) < 14)
1076 return 0;
1078 struct tm timeinfo;
1079 //We'll be having problems with this..
1080 timeinfo.tm_year = 100 + gsmd_utils_convert_to_int(str);
1081 str+=2;
1083 timeinfo.tm_mon = gsmd_utils_convert_to_int(str) - 1;
1084 str+=2;
1086 timeinfo.tm_mday = gsmd_utils_convert_to_int(str);
1087 str+=2;
1089 timeinfo.tm_hour = gsmd_utils_convert_to_int(str);
1090 str+=2;
1092 timeinfo.tm_min = gsmd_utils_convert_to_int(str);
1093 str+=2;
1095 timeinfo.tm_sec = gsmd_utils_convert_to_int(str);
1096 str+=2;
1099 timeinfo.tm_isdst = -1;
1102 char tz = (char)gsmd_utils_convert_to_int(str);
1104 return mktime ( &timeinfo ) + (900 * tz);
1108 * @brief Parses cms error and stoes it to given variable
1110 * @param response string to parse cms error from
1111 * @param code code to store cms code
1112 * @return true if cms error was found and parsed from response
1114 gboolean gsmd_utils_parse_cms_error(GString *response,
1115 gint *code)
1117 static GRegex *regex = NULL;
1118 if( !regex ) {
1119 GError *error = NULL;
1120 regex = g_regex_new ("^\\+CMS ERROR:\\s(?<code>\\d+)$.*$", 0, 0, &error);
1121 if ( error ) {
1122 g_error("%s: %s", __func__, error->message);
1125 GMatchInfo *match_info;
1128 if (g_regex_match (regex, response->str, 0, &match_info)) {
1129 if ( code ) {
1130 gchar *match = g_match_info_fetch_named(match_info,"code");
1131 *code = atoi(match);
1132 g_free(match);
1134 return TRUE;
1136 return FALSE;
1140 * @brief Parses cme error and stoes it to given variable
1142 * @param response string to parse cms error from
1143 * @param code code to store cms code
1144 * @return true if cms error was found and parsed from response
1146 gboolean gsmd_utils_parse_cme_error(GString *response,
1147 gint *code)
1149 static GRegex *regex = NULL;
1150 if( !regex ) {
1151 GError *error = NULL;
1152 regex = g_regex_new ("^\\+CME ERROR:\\s(?<code>\\d+)$.*$", 0, 0, &error);
1153 if ( error ) {
1154 g_error("%s: %s", __func__, error->message);
1157 GMatchInfo *match_info;
1160 if (g_regex_match (regex, response->str, 0, &match_info)) {
1161 if ( code ) {
1162 gchar *match = g_match_info_fetch_named(match_info,"code");
1163 *code = atoi(match);
1164 g_free(match);
1166 return TRUE;
1168 return FALSE;