1 /* Copyright (c) 2002-2004 by Marcin Wiacek and Joergen Thomsen */
2 /* Copyright (c) 2009 - 2011 Michal Cihar <michal@cihar.com> */
12 #include <gammu-config.h>
19 #include <gammu-smsd.h>
30 #include <sys/types.h>
41 /* Some systems let waitpid(2) tell callers about stopped children. */
42 #if !defined (WCONTINUED)
45 #if !defined (WIFCONTINUED)
46 # define WIFCONTINUED(s) (0)
50 #include "services/files.h"
51 #include "services/null.h"
52 #if defined(HAVE_MYSQL_MYSQL_H) || defined(HAVE_POSTGRESQL_LIBPQ_FE_H) || defined(LIBDBI_FOUND) || defined(ODBC_FOUND)
53 #include "services/sql.h"
56 #ifdef HAVE_WINDOWS_EVENT_LOG
57 #include "log-event.h"
60 #include "../helper/string.h"
64 #define PATH_MAX (MAX_PATH)
66 #define PATH_MAX (4069)
70 const char smsd_name
[] = "gammu-smsd";
73 * Checks whether database schema version matches current one.
75 GSM_Error
SMSD_CheckDBVersion(GSM_SMSDConfig
*Config
, int version
)
77 SMSD_Log(DEBUG_NOTICE
, Config
, "Database structures version: %d, SMSD current version: %d", version
, SMSD_DB_VERSION
);
79 if (version
< SMSD_DB_VERSION
) {
80 SMSD_Log(DEBUG_ERROR
, Config
, "Database structure is from older Gammu version");
81 SMSD_Log(DEBUG_INFO
, Config
, "Please update database, you can find SQL scripts in documentation");
84 if (version
> SMSD_DB_VERSION
) {
85 SMSD_Log(DEBUG_ERROR
, Config
, "Database structure is from newer Gammu version");
86 SMSD_Log(DEBUG_INFO
, Config
, "Please update Gammu to use this database");
93 * Signals SMSD to shutdown.
95 GSM_Error
SMSD_Shutdown(GSM_SMSDConfig
*Config
)
97 if (!Config
->running
) {
98 return ERR_NOTRUNNING
;
100 Config
->shutdown
= TRUE
;
105 * Callback from libGammu on sending message.
107 void SMSD_SendSMSStatusCallback (GSM_StateMachine
*sm
, int status
, int mr
, void *user_data
)
109 GSM_SMSDConfig
*Config
= (GSM_SMSDConfig
*)user_data
;
111 SMSD_Log(DEBUG_NOTICE
, Config
, "SMS sent on device: \"%s\" status=%d, reference=%d",
112 GSM_GetConfig(sm
, -1)->Device
,
115 /* Remember message reference */
117 /* Was message sent okay? */
119 Config
->SendingSMSStatus
= ERR_NONE
;
121 Config
->SendingSMSStatus
= ERR_UNKNOWN
;
126 * Closes logging output for SMSD.
128 void SMSD_CloseLog(GSM_SMSDConfig
*Config
)
130 switch (Config
->log_type
) {
131 #ifdef HAVE_WINDOWS_EVENT_LOG
132 case SMSD_LOG_EVENTLOG
:
133 eventlog_close(Config
->log_handle
);
134 Config
->log_handle
= NULL
;
138 if (Config
->log_handle
!= NULL
) {
139 fclose(Config
->log_handle
);
140 Config
->log_handle
= NULL
;
146 Config
->log_type
= SMSD_LOG_NONE
;
150 * Logs current errno (or equivalent) details.
152 void SMSD_LogErrno(GSM_SMSDConfig
*Config
, const char *message
)
158 FORMAT_MESSAGE_ALLOCATE_BUFFER
|
159 FORMAT_MESSAGE_FROM_SYSTEM
|
160 FORMAT_MESSAGE_IGNORE_INSERTS
,
163 MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
), /* Default language */
168 SMSD_Log(DEBUG_ERROR
, Config
, "%s, Error %d: %s\n", message
, (int)GetLastError(), lpMsgBuf
);
172 SMSD_Log(DEBUG_ERROR
, Config
, "%s, Error %d: %s\n", message
, errno
, strerror(errno
));
177 * Log Gammu error code together with text.
179 void SMSD_LogError(SMSD_DebugLevel level
, GSM_SMSDConfig
*Config
, const char *message
, GSM_Error error
)
181 SMSD_Log(level
, Config
, "%s: %s (%s[%i])",
183 GSM_ErrorString(error
),
184 GSM_ErrorName(error
),
189 * Terminates SMSD, closing phone connection, closing log files and
190 * possibly reporting error code.
192 void SMSD_Terminate(GSM_SMSDConfig
*Config
, const char *msg
, GSM_Error error
, gboolean exitprogram
, int rc
)
194 GSM_Error ret
= ERR_NONE
;
196 /* Log error message */
197 if (error
!= ERR_NONE
&& error
!= 0) {
198 SMSD_LogError(DEBUG_ERROR
, Config
, msg
, error
);
199 } else if (rc
!= 0) {
200 SMSD_LogErrno(Config
, msg
);
203 /* Disconnect from phone */
204 if (GSM_IsConnected(Config
->gsm
)) {
205 SMSD_Log(DEBUG_INFO
, Config
, "Terminating communication...");
206 ret
= GSM_TerminateConnection(Config
->gsm
);
207 if (ret
!= ERR_NONE
) {
208 printf("%s\n", GSM_ErrorString(error
));
209 /* Try again without checking errors */
210 if (GSM_IsConnected(Config
->gsm
)) {
211 SMSD_Log(DEBUG_INFO
, Config
, "Terminating communication for second time...");
212 GSM_TerminateConnection(Config
->gsm
);
217 /* Should we terminate program? */
220 Config
->running
= FALSE
;
221 SMSD_CloseLog(Config
);
223 if (Config
->exit_on_failure
) {
225 } else if (error
!= ERR_NONE
) {
226 Config
->failure
= error
;
231 GSM_Error
SMSD_Init(GSM_SMSDConfig
*Config
) {
234 if (Config
->connected
) return ERR_NONE
;
236 error
= Config
->Service
->Init(Config
);
237 if (error
== ERR_NONE
) {
238 Config
->connected
= TRUE
;
245 void SMSD_Log(SMSD_DebugLevel level
, GSM_SMSDConfig
*Config
, const char *format
, ...)
247 GSM_DateTime date_time
;
254 va_start(argp
, format
);
255 vsprintf(Buffer
,format
, argp
);
258 switch (Config
->log_type
) {
259 case SMSD_LOG_EVENTLOG
:
260 #ifdef HAVE_WINDOWS_EVENT_LOG
261 eventlog_log(Config
->log_handle
, level
, Buffer
);
264 case SMSD_LOG_SYSLOG
:
271 priority
= LOG_NOTICE
;
277 priority
= LOG_DEBUG
;
280 syslog(priority
, "%s", Buffer
);
284 if (level
!= DEBUG_ERROR
&&
285 level
!= DEBUG_INFO
&&
286 (level
& Config
->debug_level
) == 0) {
290 GSM_GetCurrentDateTime(&date_time
);
292 if (Config
->use_timestamps
) {
293 fprintf(Config
->log_handle
,"%s %4d/%02d/%02d %02d:%02d:%02d ",
294 DayOfWeek(date_time
.Year
, date_time
.Month
, date_time
.Day
),
295 date_time
.Year
, date_time
.Month
, date_time
.Day
,
296 date_time
.Hour
, date_time
.Minute
, date_time
.Second
);
299 fprintf(Config
->log_handle
, "%s[%ld]: ", Config
->program_name
, (long)getpid());
301 fprintf(Config
->log_handle
, "%s: ", Config
->program_name
);
303 fprintf(Config
->log_handle
,"%s\n",Buffer
);
304 fflush(Config
->log_handle
);
310 if (Config
->use_stderr
&& level
== -1) {
312 fprintf(stderr
, "%s[%ld]: ", Config
->program_name
, (long)getpid());
314 fprintf(stderr
, "%s: ", Config
->program_name
);
316 fprintf(stderr
, "%s\n", Buffer
);
321 * Function used for passing log from libGammu to SMSD log.
323 void SMSD_Log_Function(const char *text
, void *data
)
325 GSM_SMSDConfig
*Config
= (GSM_SMSDConfig
*)data
;
329 /* Dump the buffer if we got \n */
330 if (strcmp("\n", text
) == 0) {
331 SMSD_Log(DEBUG_GAMMU
, Config
, "gammu: %s", Config
->gammu_log_buffer
);
332 Config
->gammu_log_buffer
[0] = 0;
336 /* Find out current position in the buffer */
337 if (Config
->gammu_log_buffer
== NULL
) {
340 pos
= strlen(Config
->gammu_log_buffer
);
343 /* Calculate how much memory we need */
344 newsize
= pos
+ strlen(text
) + 1;
346 /* Reallocate buffer if needed */
347 if (newsize
> Config
->gammu_log_buffer_size
) {
349 Config
->gammu_log_buffer
= realloc(Config
->gammu_log_buffer
, newsize
);
350 if (Config
->gammu_log_buffer
== NULL
) {
353 Config
->gammu_log_buffer_size
= newsize
;
356 /* Copy new text to the log buffer */
357 strcpy(Config
->gammu_log_buffer
+ pos
, text
);
361 * Allocates and clears new SMSD configuration structure.
363 GSM_SMSDConfig
*SMSD_NewConfig(const char *name
)
365 GSM_SMSDConfig
*Config
;
366 Config
= (GSM_SMSDConfig
*)malloc(sizeof(GSM_SMSDConfig
));
367 if (Config
== NULL
) return Config
;
369 Config
->running
= FALSE
;
370 Config
->failure
= ERR_NONE
;
371 Config
->exit_on_failure
= TRUE
;
372 Config
->shutdown
= FALSE
;
374 Config
->gammu_log_buffer
= NULL
;
375 Config
->gammu_log_buffer_size
= 0;
376 Config
->logfilename
= NULL
;
377 Config
->RunOnFailure
= NULL
;
378 Config
->smsdcfgfile
= NULL
;
379 Config
->log_handle
= NULL
;
380 Config
->log_type
= SMSD_LOG_NONE
;
381 Config
->debug_level
= 0;
382 Config
->ServiceName
= NULL
;
383 Config
->Service
= NULL
;
386 GSM_StringArray_New(&(Config
->IncludeNumbersList
));
387 GSM_StringArray_New(&(Config
->ExcludeNumbersList
));
388 GSM_StringArray_New(&(Config
->IncludeSMSCList
));
389 GSM_StringArray_New(&(Config
->ExcludeSMSCList
));
392 Config
->program_name
= smsd_name
;
394 Config
->program_name
= name
;
401 * Returns SMSD service based on configuration.
403 GSM_Error
SMSGetService(GSM_SMSDConfig
*Config
)
405 if (Config
->ServiceName
== NULL
) {
406 SMSD_Log(DEBUG_ERROR
, Config
, "No SMSD service configured, please set service to use in configuration file!");
407 return ERR_NOSERVICE
;
409 if (strcasecmp(Config
->ServiceName
, "FILES") == 0) {
410 SMSD_Log(DEBUG_NOTICE
, Config
, "Using FILES service");
411 Config
->Service
= &SMSDFiles
;
412 } else if (strcasecmp(Config
->ServiceName
, "NULL") == 0) {
413 SMSD_Log(DEBUG_NOTICE
, Config
, "Using NULL service");
414 Config
->Service
= &SMSDNull
;
415 } else if (strcasecmp(Config
->ServiceName
, "SQL") == 0) {
416 #if defined(ODBC_FOUND) || defined(LIBDBI_FOUND) || defined(HAVE_MYSQL_MYSQL_H) || defined(HAVE_POSTGRESQL_LIBPQ_FE_H)
417 SMSD_Log(DEBUG_NOTICE
, Config
, "Using SQL service");
418 Config
->Service
= &SMSDSQL
;
419 Config
->driver
= INI_GetValue(Config
->smsdcfgfile
, "smsd", "driver", FALSE
);
421 SMSD_Log(DEBUG_ERROR
, Config
, "SQL service was not compiled in!");
424 } else if(!strcasecmp("mysql", Config
->ServiceName
) || !strcasecmp("pgsql", Config
->ServiceName
) || !strcasecmp("dbi", Config
->ServiceName
)) {
425 SMSD_Log(DEBUG_ERROR
, Config
, "%s service is deprecated. Please use SQL service with correct driver.", Config
->ServiceName
);
426 if (strcasecmp(Config
->ServiceName
, "DBI") == 0) {
428 Config
->Service
= &SMSDSQL
;
429 Config
->driver
= INI_GetValue(Config
->smsdcfgfile
, "smsd", "driver", FALSE
);
431 SMSD_Log(DEBUG_ERROR
, Config
, "DBI service was not compiled in!");
434 } else if (strcasecmp(Config
->ServiceName
, "MYSQL") == 0) {
435 #ifdef HAVE_MYSQL_MYSQL_H
436 Config
->Service
= &SMSDSQL
;
437 Config
->driver
= "native_mysql";
439 SMSD_Log(DEBUG_ERROR
, Config
, "MYSQL service was not compiled in!");
442 } else if (strcasecmp(Config
->ServiceName
, "PGSQL") == 0) {
443 #ifdef HAVE_POSTGRESQL_LIBPQ_FE_H
444 Config
->Service
= &SMSDSQL
;
445 Config
->driver
= "native_pgsql";
447 SMSD_Log(DEBUG_ERROR
, Config
, "PGSQL service was not compiled in!");
452 SMSD_Log(DEBUG_ERROR
, Config
, "Unknown SMSD service type: \"%s\"", Config
->ServiceName
);
453 return ERR_UNCONFIGURED
;
459 * Frees any data allocated under SMSD configuration.
461 void SMSD_FreeConfig(GSM_SMSDConfig
*Config
)
463 if (Config
->Service
!= NULL
&& Config
->connected
) {
464 Config
->Service
->Free(Config
);
465 Config
->connected
= FALSE
;
466 Config
->Service
= NULL
;
469 SMSD_CloseLog(Config
);
471 GSM_StringArray_Free(&(Config
->IncludeNumbersList
));
472 GSM_StringArray_Free(&(Config
->ExcludeNumbersList
));
473 GSM_StringArray_Free(&(Config
->IncludeSMSCList
));
474 GSM_StringArray_Free(&(Config
->ExcludeSMSCList
));
476 free(Config
->gammu_log_buffer
);
478 INI_Free(Config
->smsdcfgfile
);
480 GSM_FreeStateMachine(Config
->gsm
);
486 * Loads list of numbers from defined config file section.
488 GSM_Error
SMSD_LoadIniNumbersList(GSM_SMSDConfig
*Config
, GSM_StringArray
*Array
, const char *section
)
492 for (e
= INI_FindLastSectionEntry(Config
->smsdcfgfile
, section
, FALSE
); e
!= NULL
; e
= e
->Prev
) {
493 if (!GSM_StringArray_Add(Array
, e
->EntryValue
)) {
494 return ERR_MOREMEMORY
;
502 * Loads lines from file defined by configuration key.
504 GSM_Error
SMSD_LoadNumbersFile(GSM_SMSDConfig
*Config
, GSM_StringArray
*Array
, const char *configkey
)
509 char buffer
[GSM_MAX_NUMBER_LENGTH
+ 1];
511 listfilename
= INI_GetValue(Config
->smsdcfgfile
, "smsd", configkey
, FALSE
);
512 if (listfilename
!= NULL
) {
513 listfd
= fopen(listfilename
, "r");
514 if (listfd
== NULL
) {
515 SMSD_LogErrno(Config
, "Failed to open numbers file");
516 return ERR_CANTOPENFILE
;
518 while (fgets(buffer
, sizeof(buffer
) - 1, listfd
)) {
519 len
= strlen(buffer
);
520 /* Remove trailing whitespace */
521 while (len
> 0 && isspace(buffer
[len
- 1])) {
525 /* Ignore empty lines */
526 if (len
== 0) continue;
527 /* Add line to array */
528 if (!GSM_StringArray_Add(Array
, buffer
)) {
529 return ERR_MOREMEMORY
;
538 * Configures SMSD logging.
540 * \param Config SMSD configuration data.
541 * \param uselog Whether to log errors to configured log.
543 GSM_Error
SMSD_ConfigureLogging(GSM_SMSDConfig
*Config
, gboolean uselog
)
550 /* No logging configured */
551 if (Config
->logfilename
== NULL
) {
556 Config
->log_type
= SMSD_LOG_FILE
;
557 Config
->use_stderr
= FALSE
;
560 return ERR_CANTOPENFILE
;
562 Config
->log_handle
= fdopen(fd
, "a");
563 Config
->use_timestamps
= FALSE
;
564 #ifdef HAVE_WINDOWS_EVENT_LOG
565 } else if (strcmp(Config
->logfilename
, "eventlog") == 0) {
566 Config
->log_type
= SMSD_LOG_EVENTLOG
;
567 Config
->log_handle
= eventlog_init();
568 Config
->use_stderr
= TRUE
;
571 } else if (strcmp(Config
->logfilename
, "syslog") == 0) {
572 if (Config
->logfacility
== NULL
) {
573 facility
= LOG_DAEMON
;
574 } else if (strcasecmp(Config
->logfacility
, "DAEMON")) {
575 facility
= LOG_DAEMON
;
576 } else if (strcasecmp(Config
->logfacility
, "USER")) {
578 } else if (strcasecmp(Config
->logfacility
, "LOCAL0")) {
579 facility
= LOG_LOCAL0
;
580 } else if (strcasecmp(Config
->logfacility
, "LOCAL1")) {
581 facility
= LOG_LOCAL1
;
582 } else if (strcasecmp(Config
->logfacility
, "LOCAL2")) {
583 facility
= LOG_LOCAL2
;
584 } else if (strcasecmp(Config
->logfacility
, "LOCAL3")) {
585 facility
= LOG_LOCAL3
;
586 } else if (strcasecmp(Config
->logfacility
, "LOCAL4")) {
587 facility
= LOG_LOCAL4
;
588 } else if (strcasecmp(Config
->logfacility
, "LOCAL5")) {
589 facility
= LOG_LOCAL5
;
590 } else if (strcasecmp(Config
->logfacility
, "LOCAL6")) {
591 facility
= LOG_LOCAL6
;
592 } else if (strcasecmp(Config
->logfacility
, "LOCAL7")) {
593 facility
= LOG_LOCAL7
;
595 fprintf(stderr
, "Invalid facility \"%s\"\n", Config
->logfacility
);
596 facility
= LOG_DAEMON
;
598 Config
->log_type
= SMSD_LOG_SYSLOG
;
599 openlog(Config
->program_name
, LOG_PID
, facility
);
600 Config
->use_stderr
= TRUE
;
603 Config
->log_type
= SMSD_LOG_FILE
;
604 if (strcmp(Config
->logfilename
, "stderr") == 0) {
607 return ERR_CANTOPENFILE
;
609 Config
->log_handle
= fdopen(fd
, "a");
610 Config
->use_stderr
= FALSE
;
611 } else if (strcmp(Config
->logfilename
, "stdout") == 0) {
614 return ERR_CANTOPENFILE
;
616 Config
->log_handle
= fdopen(fd
, "a");
617 Config
->use_stderr
= FALSE
;
619 Config
->log_handle
= fopen(Config
->logfilename
, "a");
620 Config
->use_stderr
= TRUE
;
622 if (Config
->log_handle
== NULL
) {
623 fprintf(stderr
, "Can't open log file \"%s\"\n", Config
->logfilename
);
624 return ERR_CANTOPENFILE
;
626 fprintf(stderr
, "Log filename is \"%s\"\n",Config
->logfilename
);
632 * Reads configuration file and feeds it's content into SMSD configuration structure.
634 GSM_Error
SMSD_ReadConfig(const char *filename
, GSM_SMSDConfig
*Config
, gboolean uselog
)
637 GSM_Config
*gammucfg
;
641 char fullpath
[PATH_MAX
+ 1];
646 char config_name
[MAX_PATH
];
649 memset(&smsdcfg
, 0, sizeof(smsdcfg
));
651 Config
->shutdown
= FALSE
;
652 Config
->running
= FALSE
;
653 Config
->connected
= FALSE
;
654 Config
->failure
= ERR_NONE
;
655 Config
->exit_on_failure
= TRUE
;
656 Config
->gsm
= GSM_AllocStateMachine();
657 if (Config
->gsm
== NULL
) {
658 fprintf(stderr
, "Failed to allocate memory for state machine!\n");
659 return ERR_MOREMEMORY
;
661 Config
->gammu_log_buffer
= NULL
;
662 Config
->gammu_log_buffer_size
= 0;
663 Config
->logfilename
= NULL
;
664 Config
->logfacility
= NULL
;
665 Config
->smsdcfgfile
= NULL
;
666 Config
->use_timestamps
= TRUE
;
667 Config
->log_type
= SMSD_LOG_NONE
;
668 Config
->log_handle
= NULL
;
669 Config
->use_stderr
= TRUE
;
672 /* Calculate key for shared memory */
673 if (realpath(filename
, fullpath
) == NULL
) {
674 strncpy(fullpath
, filename
, PATH_MAX
);
675 fullpath
[PATH_MAX
] = 0;
677 Config
->shm_key
= ftok(fullpath
, SMSD_SHM_KEY
);
680 if (GetFullPathName(filename
, sizeof(config_name
), config_name
, NULL
) == 0) {
684 len
= sprintf(Config
->map_key
, "Gammu-smsd-%s", config_name
);
685 /* Replace some possibly dangerous chars */
686 for (i
= 0; i
< len
; i
++) {
687 if (!isalpha(Config
->map_key
[i
]) && !isdigit(Config
->map_key
[i
])) {
688 Config
->map_key
[i
] = '_';
693 error
= INI_ReadFile(filename
, FALSE
, &Config
->smsdcfgfile
);
694 if (Config
->smsdcfgfile
== NULL
|| error
!= ERR_NONE
) {
695 if (error
== ERR_FILENOTSUPPORTED
) {
696 fprintf(stderr
, "Could not parse config file \"%s\"\n",filename
);
698 fprintf(stderr
, "Can't find file \"%s\"\n",filename
);
700 return ERR_CANTOPENFILE
;
703 str
= INI_GetValue(Config
->smsdcfgfile
, "smsd", "debuglevel", FALSE
);
705 Config
->debug_level
= atoi(str
);
707 Config
->debug_level
= 0;
710 Config
->logfilename
= INI_GetValue(Config
->smsdcfgfile
, "smsd", "logfile", FALSE
);
711 Config
->logfacility
= INI_GetValue(Config
->smsdcfgfile
, "smsd", "logfacility", FALSE
);
713 error
= SMSD_ConfigureLogging(Config
, uselog
);
714 if (error
!= ERR_NONE
) {
718 Config
->ServiceName
= INI_GetValue(Config
->smsdcfgfile
, "smsd", "service", FALSE
);
720 /* Get service object */
721 error
= SMSGetService(Config
);
722 if (error
!= ERR_NONE
) {
726 SMSD_Log(DEBUG_NOTICE
, Config
, "Configuring Gammu SMSD...");
728 SMSD_Log(DEBUG_NOTICE
, Config
, "SHM token: 0x%llx (%lld)", (long long)Config
->shm_key
, (long long)Config
->shm_key
);
731 /* Does our config file contain gammu section? */
732 if (INI_FindLastSectionEntry(Config
->smsdcfgfile
, "gammu", FALSE
) == NULL
) {
733 SMSD_Log(DEBUG_ERROR
, Config
, "No gammu configuration found (no [gammu] section in SMSD config file)!");
734 return ERR_UNCONFIGURED
;
737 gammucfg
= GSM_GetConfig(Config
->gsm
, 0);
738 GSM_ReadConfig(Config
->smsdcfgfile
, gammucfg
, 0);
739 GSM_SetConfigNum(Config
->gsm
, 1);
740 gammucfg
->UseGlobalDebugFile
= FALSE
;
742 /* Force debug level in Gammu */
743 if ((DEBUG_GAMMU
& Config
->debug_level
) != 0) {
744 strcpy(gammucfg
->DebugLevel
, "textall");
745 GSM_SetDebugLevel("textall", GSM_GetGlobalDebug());
748 Config
->PINCode
=INI_GetValue(Config
->smsdcfgfile
, "smsd", "PIN", FALSE
);
749 if (Config
->PINCode
== NULL
) {
750 SMSD_Log(DEBUG_INFO
, Config
, "Warning: No PIN code in %s file",filename
);
752 SMSD_Log(DEBUG_NOTICE
, Config
, "PIN code is \"%s\"",Config
->PINCode
);
755 Config
->NetworkCode
= INI_GetValue(Config
->smsdcfgfile
, "smsd", "NetworkCode", FALSE
);
756 if (Config
->NetworkCode
!= NULL
) {
757 SMSD_Log(DEBUG_NOTICE
, Config
, "Network code is \"%s\"",Config
->NetworkCode
);
760 Config
->PhoneCode
= INI_GetValue(Config
->smsdcfgfile
, "smsd", "PhoneCode", FALSE
);
761 if (Config
->PhoneCode
!= NULL
) {
762 SMSD_Log(DEBUG_NOTICE
, Config
, "Phone code is \"%s\"",Config
->PhoneCode
);
765 Config
->commtimeout
= INI_GetInt(Config
->smsdcfgfile
, "smsd", "commtimeout", 30);
766 Config
->deliveryreportdelay
= INI_GetInt(Config
->smsdcfgfile
, "smsd", "deliveryreportdelay", 600);
767 Config
->sendtimeout
= INI_GetInt(Config
->smsdcfgfile
, "smsd", "sendtimeout", 30);
768 Config
->receivefrequency
= INI_GetInt(Config
->smsdcfgfile
, "smsd", "receivefrequency", 0);
769 Config
->statusfrequency
= INI_GetInt(Config
->smsdcfgfile
, "smsd", "statusfrequency", 15);
770 Config
->loopsleep
= INI_GetInt(Config
->smsdcfgfile
, "smsd", "loopsleep", 1);
771 Config
->checksecurity
= INI_GetBool(Config
->smsdcfgfile
, "smsd", "checksecurity", TRUE
);
772 Config
->checksignal
= INI_GetBool(Config
->smsdcfgfile
, "smsd", "checksignal", TRUE
);
773 Config
->checkbattery
= INI_GetBool(Config
->smsdcfgfile
, "smsd", "checkbattery", TRUE
);
774 Config
->enable_send
= INI_GetBool(Config
->smsdcfgfile
, "smsd", "send", TRUE
);
775 Config
->enable_receive
= INI_GetBool(Config
->smsdcfgfile
, "smsd", "receive", TRUE
);
776 Config
->resetfrequency
= INI_GetInt(Config
->smsdcfgfile
, "smsd", "resetfrequency", 0);
777 Config
->hardresetfrequency
= INI_GetInt(Config
->smsdcfgfile
, "smsd", "hardresetfrequency", 0);
778 Config
->multiparttimeout
= INI_GetInt(Config
->smsdcfgfile
, "smsd", "multiparttimeout", 600);
779 Config
->maxretries
= INI_GetInt(Config
->smsdcfgfile
, "smsd", "maxretries", 1);
780 Config
->backend_retries
= INI_GetInt(Config
->smsdcfgfile
, "smsd", "backendretries", 10);
782 SMSD_Log(DEBUG_NOTICE
, Config
, "CommTimeout=%i, SendTimeout=%i, ReceiveFrequency=%i, ResetFrequency=%i, HardResetFrequency=%i",
783 Config
->commtimeout
, Config
->sendtimeout
, Config
->receivefrequency
, Config
->resetfrequency
, Config
->hardresetfrequency
);
784 SMSD_Log(DEBUG_NOTICE
, Config
, "checks: CheckSecurity=%d, CheckBattery=%d, CheckSignal=%d",
785 Config
->checksecurity
, Config
->checkbattery
, Config
->checksignal
);
786 SMSD_Log(DEBUG_NOTICE
, Config
, "mode: Send=%d, Receive=%d",
787 Config
->enable_send
, Config
->enable_receive
);
789 Config
->skipsmscnumber
= INI_GetValue(Config
->smsdcfgfile
, "smsd", "skipsmscnumber", FALSE
);
790 if (Config
->skipsmscnumber
== NULL
) Config
->skipsmscnumber
="";
792 Config
->deliveryreport
= INI_GetValue(Config
->smsdcfgfile
, "smsd", "deliveryreport", FALSE
);
793 if (Config
->deliveryreport
== NULL
|| (strcasecmp(Config
->deliveryreport
, "log") != 0 && strcasecmp(Config
->deliveryreport
, "sms") != 0)) {
794 Config
->deliveryreport
= "no";
796 SMSD_Log(DEBUG_NOTICE
, Config
, "deliveryreport = %s", Config
->deliveryreport
);
798 Config
->PhoneID
= INI_GetValue(Config
->smsdcfgfile
, "smsd", "phoneid", FALSE
);
799 if (Config
->PhoneID
== NULL
) Config
->PhoneID
= "";
800 SMSD_Log(DEBUG_NOTICE
, Config
, "phoneid = %s", Config
->PhoneID
);
802 Config
->RunOnReceive
= INI_GetValue(Config
->smsdcfgfile
, "smsd", "runonreceive", FALSE
);
803 Config
->RunOnFailure
= INI_GetValue(Config
->smsdcfgfile
, "smsd", "runonfailure", FALSE
);
805 str
= INI_GetValue(Config
->smsdcfgfile
, "smsd", "smsc", FALSE
);
807 Config
->SMSC
.Location
= 0;
808 Config
->SMSC
.DefaultNumber
[0] = 0;
809 Config
->SMSC
.DefaultNumber
[1] = 0;
810 Config
->SMSC
.Name
[0] = 0;
811 Config
->SMSC
.Name
[1] = 0;
812 Config
->SMSC
.Validity
.Format
= SMS_Validity_NotAvailable
;
813 Config
->SMSC
.Format
= SMS_FORMAT_Text
;
814 EncodeUnicode(Config
->SMSC
.Number
, str
, strlen(str
));
816 Config
->SMSC
.Location
= -1;
820 Config
->SMSCCache
.Location
= 0;
822 /* Read service specific configuration */
823 error
= Config
->Service
->ReadConfiguration(Config
);
824 if (error
!= ERR_NONE
) return error
;
826 /* Process include section in config file */
827 error
= SMSD_LoadIniNumbersList(Config
, &(Config
->IncludeNumbersList
), "include_numbers");
828 if (error
!= ERR_NONE
) return error
;
829 /* Process exclude section in config file */
830 error
= SMSD_LoadIniNumbersList(Config
, &(Config
->ExcludeNumbersList
), "exclude_numbers");
831 if (error
!= ERR_NONE
) return error
;
833 /* Load include numbers from external file */
834 error
= SMSD_LoadNumbersFile(Config
, &(Config
->IncludeNumbersList
), "includenumbersfile");
835 if (error
!= ERR_NONE
) return error
;
837 /* Load exclude numbers from external file */
838 error
= SMSD_LoadNumbersFile(Config
, &(Config
->ExcludeNumbersList
), "excludenumbersfile");
839 if (error
!= ERR_NONE
) return error
;
841 if (Config
->IncludeNumbersList
.used
> 0) {
842 SMSD_Log(DEBUG_NOTICE
, Config
, "Include numbers available");
844 if (Config
->ExcludeNumbersList
.used
> 0) {
845 if (Config
->IncludeNumbersList
.used
== 0) {
846 SMSD_Log(DEBUG_NOTICE
, Config
, "Exclude numbers available");
848 SMSD_Log(DEBUG_INFO
, Config
, "Exclude numbers available, but IGNORED");
852 /* Process include section in config file */
853 error
= SMSD_LoadIniNumbersList(Config
, &(Config
->IncludeSMSCList
), "include_smsc");
854 if (error
!= ERR_NONE
) return error
;
855 /* Process exclude section in config file */
856 error
= SMSD_LoadIniNumbersList(Config
, &(Config
->ExcludeSMSCList
), "exclude_smsc");
857 if (error
!= ERR_NONE
) return error
;
859 /* Load include smsc from external file */
860 error
= SMSD_LoadNumbersFile(Config
, &(Config
->IncludeSMSCList
), "includesmscfile");
861 if (error
!= ERR_NONE
) return error
;
863 /* Load exclude smsc from external file */
864 error
= SMSD_LoadNumbersFile(Config
, &(Config
->ExcludeSMSCList
), "excludesmscfile");
865 if (error
!= ERR_NONE
) return error
;
867 if (Config
->IncludeSMSCList
.used
> 0) {
868 SMSD_Log(DEBUG_NOTICE
, Config
, "Include smsc available");
870 if (Config
->ExcludeSMSCList
.used
> 0) {
871 if (Config
->IncludeSMSCList
.used
== 0) {
872 SMSD_Log(DEBUG_NOTICE
, Config
, "Exclude smsc available");
874 SMSD_Log(DEBUG_INFO
, Config
, "Exclude smsc available, but IGNORED");
879 Config
->prevSMSID
[0] = 0;
880 Config
->relativevalidity
= -1;
881 Config
->Status
= NULL
;
882 Config
->IncompleteMessageID
= -1;
883 Config
->IncompleteMessageTime
= 0;
889 * Checks whether phone does not need to enter some PIN.
891 gboolean
SMSD_CheckSecurity(GSM_SMSDConfig
*Config
)
893 GSM_SecurityCode SecurityCode
;
895 const char *code
= NULL
;
898 error
= GSM_GetSecurityStatus(Config
->gsm
, &SecurityCode
.Type
);
900 /* No supported - do not check more */
901 if (error
== ERR_NOTSUPPORTED
) {
906 if (error
!= ERR_NONE
) {
907 SMSD_LogError(DEBUG_ERROR
, Config
, "Error getting security status", error
);
908 SMSD_Log(DEBUG_ERROR
, Config
, "You might want to set CheckSecurity = 0 to avoid checking security status");
912 /* If PIN, try to enter */
913 switch (SecurityCode
.Type
) {
917 code
= Config
->PINCode
;
920 code
= Config
->PhoneCode
;
923 code
= Config
->NetworkCode
;
925 case SEC_SecurityCode
:
929 SMSD_Terminate(Config
, "ERROR: phone requires not supported code type", ERR_UNKNOWN
, TRUE
, -1);
933 /* Check if the PIN was configured */
935 SMSD_Log(DEBUG_INFO
, Config
, "Warning: no code in config when phone might want one!");
940 SMSD_Log(DEBUG_NOTICE
, Config
, "Trying to enter code");
941 strcpy(SecurityCode
.Code
, code
);
942 error
= GSM_EnterSecurityCode(Config
->gsm
, &SecurityCode
);
943 if (error
== ERR_SECURITYERROR
) {
944 SMSD_Terminate(Config
, "ERROR: incorrect PIN", error
, TRUE
, -1);
947 if (error
!= ERR_NONE
) {
948 SMSD_LogError(DEBUG_ERROR
, Config
, "Error entering PIN", error
);
955 * Prepares a command line for RunOn() function to execute user command.
957 char *SMSD_RunOnCommand(const char *locations
, const char *command
)
962 assert(command
!= NULL
);
964 if (locations
== NULL
) {
965 result
= strdup(command
);
966 assert(result
!= NULL
);
970 len
= strlen(locations
) + strlen(command
) + 4;
971 result
= (char *)malloc(len
);
972 assert(result
!= NULL
);
974 snprintf(result
, len
, "%s %s", command
, locations
);
979 #define setenv(var, value, force) SetEnvironmentVariable(var, value)
983 * Fills in environment with information about messages.
985 void SMSD_RunOnReceiveEnvironment(GSM_MultiSMSMessage
*sms
, GSM_SMSDConfig
*Config
, const char *locations
)
987 GSM_MultiPartSMSInfo SMSInfo
;
988 char buffer
[100], name
[100];
991 /* Raw message data */
992 sprintf(buffer
, "%d", sms
->Number
);
993 setenv("SMS_MESSAGES", buffer
, 1);
994 for (i
= 0; i
< sms
->Number
; i
++) {
995 sprintf(buffer
, "%d", sms
->SMS
[i
].Class
);
996 sprintf(name
, "SMS_%d_CLASS", i
+ 1);
997 setenv(name
, buffer
, 1);
998 sprintf(name
, "SMS_%d_NUMBER", i
+ 1);
999 setenv(name
, DecodeUnicodeConsole(sms
->SMS
[i
].Number
), 1);
1000 if (sms
->SMS
[i
].Coding
!= SMS_Coding_8bit
) {
1001 sprintf(name
, "SMS_%d_TEXT", i
+ 1);
1002 setenv(name
, DecodeUnicodeConsole(sms
->SMS
[i
].Text
), 1);
1006 /* Decoded message data */
1007 if (GSM_DecodeMultiPartSMS(GSM_GetDebug(Config
->gsm
), &SMSInfo
, sms
, TRUE
)) {
1008 sprintf(buffer
, "%d", SMSInfo
.EntriesNum
);
1009 setenv("DECODED_PARTS", buffer
, 1);
1010 for (i
= 0; i
< SMSInfo
.EntriesNum
; i
++) {
1011 switch (SMSInfo
.Entries
[i
].ID
) {
1012 case SMS_ConcatenatedTextLong
:
1013 case SMS_ConcatenatedAutoTextLong
:
1014 case SMS_ConcatenatedTextLong16bit
:
1015 case SMS_ConcatenatedAutoTextLong16bit
:
1016 case SMS_NokiaVCARD21Long
:
1017 case SMS_NokiaVCALENDAR10Long
:
1018 sprintf(name
, "DECODED_%d_TEXT", i
);
1019 setenv(name
, DecodeUnicodeConsole(SMSInfo
.Entries
[i
].Buffer
), 1);
1021 case SMS_MMSIndicatorLong
:
1022 sprintf(name
, "DECODED_%d_MMS_SENDER", i
+ 1);
1023 setenv(name
, SMSInfo
.Entries
[i
].MMSIndicator
->Sender
, 1);
1024 sprintf(name
, "DECODED_%d_MMS_TITLE", i
+ 1);
1025 setenv(name
, SMSInfo
.Entries
[i
].MMSIndicator
->Title
, 1);
1026 sprintf(name
, "DECODED_%d_MMS_ADDRESS", i
+ 1);
1027 setenv(name
, SMSInfo
.Entries
[i
].MMSIndicator
->Address
, 1);
1028 sprintf(name
, "DECODED_%d_MMS_SIZE", i
+ 1);
1029 sprintf(buffer
, "%ld", (long)SMSInfo
.Entries
[i
].MMSIndicator
->MessageSize
);
1030 setenv(name
, buffer
, 1);
1033 /* We ignore others for now */
1038 setenv("DECODED_PARTS", "0", 1);
1040 GSM_FreeMultiPartSMSInfo(&SMSInfo
);
1046 * Executes external command.
1048 * This is Windows variant.
1050 gboolean
SMSD_RunOn(const char *command
, GSM_MultiSMSMessage
*sms
, GSM_SMSDConfig
*Config
, const char *locations
)
1054 PROCESS_INFORMATION pi
;
1057 cmdline
= SMSD_RunOnCommand(locations
, command
);
1059 /* Prepare environment */
1061 SMSD_RunOnReceiveEnvironment(sms
, Config
, locations
);
1064 ZeroMemory(&si
, sizeof(si
));
1066 ZeroMemory(&pi
, sizeof(pi
));
1068 SMSD_Log(DEBUG_INFO
, Config
, "Starting run on command: %s", cmdline
);
1070 ret
= CreateProcess(NULL
, /* No module name (use command line) */
1071 cmdline
, /* Command line */
1072 NULL
, /* Process handle not inheritable*/
1073 NULL
, /* Thread handle not inheritable*/
1074 FALSE
, /* Set handle inheritance to FALSE*/
1075 0, /* No creation flags*/
1076 NULL
, /* Use parent's environment block*/
1077 NULL
, /* Use parent's starting directory */
1078 &si
, /* Pointer to STARTUPINFO structure*/
1079 &pi
); /* Pointer to PROCESS_INFORMATION structure*/
1082 SMSD_LogErrno(Config
, "CreateProcess failed");
1084 /* We don't need handles at all */
1085 CloseHandle(pi
.hProcess
);
1086 CloseHandle(pi
.hThread
);
1093 * Executes external command.
1095 * This is POSIX variant.
1097 gboolean
SMSD_RunOn(const char *command
, GSM_MultiSMSMessage
*sms
, GSM_SMSDConfig
*Config
, const char *locations
)
1108 SMSD_LogErrno(Config
, "Error spawning new process");
1113 /* We are the parent, wait for child */
1116 w
= waitpid(pid
, &status
, WUNTRACED
| WCONTINUED
);
1118 SMSD_Log(DEBUG_INFO
, Config
, "Failed to wait for process");
1122 if (WIFEXITED(status
)) {
1123 if (WEXITSTATUS(status
) == 0) {
1124 SMSD_Log(DEBUG_INFO
, Config
, "Process finished successfully");
1126 SMSD_Log(DEBUG_ERROR
, Config
, "Process failed with exit status %d", WEXITSTATUS(status
));
1128 return (WEXITSTATUS(status
) == 0);
1129 } else if (WIFSIGNALED(status
)) {
1130 SMSD_Log(DEBUG_ERROR
, Config
, "Process killed by signal %d", WTERMSIG(status
));
1132 } else if (WIFSTOPPED(status
)) {
1133 SMSD_Log(DEBUG_INFO
, Config
, "Process stopped by signal %d", WSTOPSIG(status
));
1134 } else if (WIFCONTINUED(status
)) {
1135 SMSD_Log(DEBUG_INFO
, Config
, "Process continued");
1140 SMSD_Log(DEBUG_INFO
, Config
, "Waited two minutes for child process, giving up");
1143 } while (!WIFEXITED(status
) && !WIFSIGNALED(status
));
1148 /* we are the child */
1150 /* Prepare environment */
1152 SMSD_RunOnReceiveEnvironment(sms
, Config
, locations
);
1155 /* Calculate command line */
1156 cmdline
= SMSD_RunOnCommand(locations
, command
);
1157 SMSD_Log(DEBUG_INFO
, Config
, "Starting run on receive: %s", cmdline
);
1159 /* Close all file descriptors */
1160 for (i
= 0; i
< 255; i
++) {
1164 /* Run the program */
1165 status
= system(cmdline
);
1167 /* Propagate error code */
1168 if (WIFEXITED(status
)) {
1169 exit(WEXITSTATUS(status
));
1177 * Checks whether we are allowed to accept a message from number.
1179 gboolean
SMSD_CheckRemoteNumber(GSM_SMSDConfig
*Config
, const char *number
)
1181 if (Config
->IncludeNumbersList
.used
> 0) {
1182 if (GSM_StringArray_Find(&(Config
->IncludeNumbersList
), number
)) {
1183 SMSD_Log(DEBUG_NOTICE
, Config
, "Number %s matched IncludeNumbers", number
);
1187 } else if (Config
->ExcludeNumbersList
.used
> 0) {
1188 if (GSM_StringArray_Find(&(Config
->ExcludeNumbersList
), number
)) {
1189 SMSD_Log(DEBUG_NOTICE
, Config
, "Number %s matched ExcludeNumbers", number
);
1199 * Checks whether we are allowed to accept a message from number.
1201 gboolean
SMSD_CheckSMSCNumber(GSM_SMSDConfig
*Config
, const char *number
)
1203 if (Config
->IncludeSMSCList
.used
> 0) {
1204 if (GSM_StringArray_Find(&(Config
->IncludeSMSCList
), number
)) {
1205 SMSD_Log(DEBUG_NOTICE
, Config
, "Number %s matched IncludeSMSC", number
);
1209 } else if (Config
->ExcludeSMSCList
.used
> 0) {
1210 if (GSM_StringArray_Find(&(Config
->ExcludeSMSCList
), number
)) {
1211 SMSD_Log(DEBUG_NOTICE
, Config
, "Number %s matched ExcludeSMSC", number
);
1221 * Performs checks whether given message is valid to be received by SMSD.
1223 gboolean
SMSD_ValidMessage(GSM_SMSDConfig
*Config
, GSM_MultiSMSMessage
*sms
)
1227 /* Not Inbox SMS - exit */
1228 if (!sms
->SMS
[0].InboxFolder
) {
1231 /* Check SMSC number if we want to handle it */
1232 DecodeUnicode(sms
->SMS
[0].SMSC
.Number
, buffer
);
1233 if (!SMSD_CheckSMSCNumber(Config
, buffer
)) {
1234 SMSD_Log(DEBUG_NOTICE
, Config
, "Message excluded because of SMSC: %s", buffer
);
1237 /* Check sender number if we want to handle it */
1238 DecodeUnicode(sms
->SMS
[0].Number
, buffer
);
1239 if (!SMSD_CheckRemoteNumber(Config
, buffer
)) {
1240 SMSD_Log(DEBUG_NOTICE
, Config
, "Message excluded because of sender: %s", buffer
);
1243 /* Finally process the message */
1244 SMSD_Log(DEBUG_NOTICE
, Config
, "Received message from: %s", buffer
);
1249 * Does any processing is required for single message after it has been accepted.
1251 * Stores message in the backend and executes RunOnReceive.
1253 GSM_Error
SMSD_ProcessSMS(GSM_SMSDConfig
*Config
, GSM_MultiSMSMessage
*sms
)
1255 GSM_Error error
= ERR_NONE
;
1256 char *locations
= NULL
;
1258 /* Increase message counter */
1259 Config
->Status
->Received
+= sms
->Number
;
1260 /* Send message to the backend */
1261 error
= Config
->Service
->SaveInboxSMS(sms
, Config
, &locations
);
1262 /* RunOnReceive handling */
1263 if (Config
->RunOnReceive
!= NULL
&& error
== ERR_NONE
) {
1264 SMSD_RunOn(Config
->RunOnReceive
, sms
, Config
, locations
);
1266 /* Free memory allocated by SaveInboxSMS */
1272 * Checks whether to process current (possibly) multipart message.
1274 gboolean
SMSD_CheckMultipart(GSM_SMSDConfig
*Config
, GSM_MultiSMSMessage
*MultiSMS
)
1279 /* Does the message have UDH (is multipart)? */
1280 if (MultiSMS
->SMS
[0].UDH
.Type
== UDH_NoUDH
|| MultiSMS
->SMS
[0].UDH
.AllParts
== -1) {
1284 /* Grab current id */
1285 if (MultiSMS
->SMS
[0].UDH
.ID16bit
!= -1) {
1286 current_id
= MultiSMS
->SMS
[0].UDH
.ID16bit
;
1288 current_id
= MultiSMS
->SMS
[0].UDH
.ID8bit
;
1291 /* Do we have same id as last incomplete? */
1292 same_id
= (Config
->IncompleteMessageID
!= -1 && Config
->IncompleteMessageID
== current_id
);
1295 SMSD_Log(DEBUG_INFO
, Config
, "Multipart message 0x%02X, %d parts of %d",
1296 current_id
, MultiSMS
->Number
, MultiSMS
->SMS
[0].UDH
.AllParts
);
1298 /* Check if we have all parts */
1299 if (MultiSMS
->SMS
[0].UDH
.AllParts
== MultiSMS
->Number
) {
1303 /* Have we seen this message recently? */
1305 if (Config
->IncompleteMessageTime
!= 0 && difftime(time(NULL
), Config
->IncompleteMessageTime
) >= Config
->multiparttimeout
) {
1306 SMSD_Log(DEBUG_INFO
, Config
, "Incomplete multipart message 0x%02X, processing after timeout",
1307 Config
->IncompleteMessageID
);
1308 Config
->IncompleteMessageID
= -1;
1310 SMSD_Log(DEBUG_INFO
, Config
, "Incomplete multipart message 0x%02X, waiting for other parts (waited %.0f seconds)",
1311 Config
->IncompleteMessageID
,
1312 difftime(time(NULL
), Config
->IncompleteMessageTime
));
1316 if (Config
->IncompleteMessageTime
== 0) {
1317 if (MultiSMS
->SMS
[0].UDH
.ID16bit
!= -1) {
1318 Config
->IncompleteMessageID
= MultiSMS
->SMS
[0].UDH
.ID16bit
;
1320 Config
->IncompleteMessageID
= MultiSMS
->SMS
[0].UDH
.ID8bit
;
1322 Config
->IncompleteMessageTime
= time(NULL
);
1323 SMSD_Log(DEBUG_INFO
, Config
, "Incomplete multipart message 0x%02X, waiting for other parts",
1324 Config
->IncompleteMessageID
);
1327 SMSD_Log(DEBUG_INFO
, Config
, "Incomplete multipart message 0x%02X, but waiting for other one",
1328 Config
->IncompleteMessageID
);
1334 /* Clean multipart wait flag */
1336 Config
->IncompleteMessageTime
= 0;
1337 Config
->IncompleteMessageID
= -1;
1343 * Reads message from phone, processes it and delete it from phone afterwards.
1345 * It tries to link multipart messages together if possible.
1347 gboolean
SMSD_ReadDeleteSMS(GSM_SMSDConfig
*Config
)
1350 GSM_MultiSMSMessage sms
;
1351 GSM_MultiSMSMessage
**GetSMSData
= NULL
, **SortedSMS
;
1353 GSM_Error error
= ERR_NONE
;
1354 int GetSMSNumber
= 0;
1357 /* Read messages from phone */
1360 sms
.SMS
[0].Location
= 0;
1361 while (error
== ERR_NONE
&& !Config
->shutdown
) {
1362 sms
.SMS
[0].Folder
= 0;
1363 error
= GSM_GetNextSMS(Config
->gsm
, &sms
, start
);
1368 if (SMSD_ValidMessage(Config
, &sms
)) {
1369 if (allocated
<= GetSMSNumber
+ 2) {
1370 GetSMSData
= (GSM_MultiSMSMessage
**)realloc(GetSMSData
, (allocated
+ 20) * sizeof(GSM_MultiSMSMessage
*));
1371 if (GetSMSData
== NULL
) {
1372 SMSD_Log(DEBUG_ERROR
, Config
, "Failed to allocate memory");
1377 GetSMSData
[GetSMSNumber
] = malloc(sizeof(GSM_MultiSMSMessage
));
1379 if (GetSMSData
[GetSMSNumber
] == NULL
) {
1380 SMSD_Log(DEBUG_ERROR
, Config
, "Failed to allocate memory");
1384 *(GetSMSData
[GetSMSNumber
]) = sms
;
1386 GetSMSData
[GetSMSNumber
] = NULL
;
1390 SMSD_LogError(DEBUG_INFO
, Config
, "Error getting SMS", error
);
1396 /* Log how many messages were read */
1397 SMSD_Log(DEBUG_INFO
, Config
, "Read %d messages", GetSMSNumber
);
1399 /* No messages to process */
1400 if (GetSMSNumber
== 0) {
1404 /* Allocate memory for sorted messages */
1405 SortedSMS
= (GSM_MultiSMSMessage
**)malloc(allocated
* sizeof(GSM_MultiSMSMessage
*));
1406 if (SortedSMS
== NULL
) {
1407 SMSD_Log(DEBUG_ERROR
, Config
, "Failed to allocate memory for linking messages");
1408 SMSD_Log(DEBUG_ERROR
, Config
, "Skipping linking messages, long messages will not be connected");
1409 SortedSMS
= GetSMSData
;
1412 error
= GSM_LinkSMS(GSM_GetDebug(Config
->gsm
), GetSMSData
, SortedSMS
, TRUE
);
1413 if (error
!= ERR_NONE
) return FALSE
;
1416 for (i
= 0; GetSMSData
[i
] != NULL
; i
++) {
1417 free(GetSMSData
[i
]);
1418 GetSMSData
[i
] = NULL
;
1423 /* Process messages */
1424 for (i
= 0; SortedSMS
[i
] != NULL
; i
++) {
1425 /* Check multipart message parts */
1426 if (!SMSD_CheckMultipart(Config
, SortedSMS
[i
])) {
1430 /* Actually process the message */
1431 error
= SMSD_ProcessSMS(Config
, SortedSMS
[i
]);
1432 if (error
!= ERR_NONE
) {
1433 SMSD_LogError(DEBUG_INFO
, Config
, "Error processing SMS", error
);
1437 /* Delete processed messages */
1438 for (j
= 0; j
< SortedSMS
[i
]->Number
; j
++) {
1439 SortedSMS
[i
]->SMS
[j
].Folder
= 0;
1440 error
= GSM_DeleteSMS(Config
->gsm
, &SortedSMS
[i
]->SMS
[j
]);
1446 SMSD_LogError(DEBUG_INFO
, Config
, "Error deleting SMS", error
);
1453 SortedSMS
[i
] = NULL
;
1460 * Checks whether there are some messages to process and calls
1461 * SMSD_ReadDeleteSMS to process them.
1463 gboolean
SMSD_CheckSMSStatus(GSM_SMSDConfig
*Config
)
1465 GSM_SMSMemoryStatus SMSStatus
;
1467 gboolean new_message
= FALSE
;
1468 GSM_MultiSMSMessage sms
;
1470 /* Do we have any SMS in phone ? */
1472 /* First try SMS status */
1473 error
= GSM_GetSMSStatus(Config
->gsm
,&SMSStatus
);
1474 if (error
== ERR_NONE
) {
1475 new_message
= (SMSStatus
.SIMUsed
+ SMSStatus
.PhoneUsed
> 0);
1476 } else if (error
== ERR_NOTSUPPORTED
|| error
== ERR_NOTIMPLEMENTED
) {
1477 /* Fallback to GetNext */
1479 sms
.SMS
[0].Location
= 0;
1480 sms
.SMS
[0].Folder
= 0;
1481 error
= GSM_GetNextSMS(Config
->gsm
, &sms
, TRUE
);
1482 new_message
= (error
== ERR_NONE
);
1484 SMSD_LogError(DEBUG_INFO
, Config
, "Error getting SMS status", error
);
1488 /* Yes. We have SMS in phone */
1490 return SMSD_ReadDeleteSMS(Config
);
1497 * Reads status from phone to configuration.
1499 void SMSD_PhoneStatus(GSM_SMSDConfig
*Config
) {
1502 if (Config
->checkbattery
) {
1503 error
= GSM_GetBatteryCharge(Config
->gsm
, &Config
->Status
->Charge
);
1505 error
= ERR_UNKNOWN
;
1507 if (error
!= ERR_NONE
) {
1508 memset(&(Config
->Status
->Charge
), 0, sizeof(Config
->Status
->Charge
));
1510 if (Config
->checksignal
) {
1511 error
= GSM_GetSignalQuality(Config
->gsm
, &Config
->Status
->Network
);
1513 error
= ERR_UNKNOWN
;
1515 if (error
!= ERR_NONE
) {
1516 memset(&(Config
->Status
->Network
), 0, sizeof(Config
->Status
->Network
));
1521 * Sends a sms message which is provided by the service backend.
1523 GSM_Error
SMSD_SendSMS(GSM_SMSDConfig
*Config
)
1525 GSM_MultiSMSMessage sms
;
1531 /* Clean structure before use */
1532 for (i
= 0; i
< GSM_MAX_MULTI_SMS
; i
++) {
1533 GSM_SetDefaultSMSData(&sms
.SMS
[i
]);
1536 error
= Config
->Service
->FindOutboxSMS(&sms
, Config
, Config
->SMSID
);
1538 if (error
== ERR_EMPTY
|| error
== ERR_NOTSUPPORTED
) {
1542 if (error
!= ERR_NONE
) {
1543 /* Unknown error - escape */
1544 SMSD_Log(DEBUG_INFO
, Config
, "Error in outbox on '%s'", Config
->SMSID
);
1545 for (i
= 0; i
< sms
.Number
; i
++) {
1546 Config
->Status
->Failed
++;
1547 Config
->Service
->AddSentSMSInfo(&sms
, Config
, Config
->SMSID
, i
+1, SMSD_SEND_ERROR
, -1);
1549 Config
->Service
->MoveSMS(&sms
,Config
, Config
->SMSID
, TRUE
,FALSE
);
1553 if (Config
->shutdown
) {
1557 if (Config
->SMSID
[0] != 0 && strcmp(Config
->prevSMSID
, Config
->SMSID
) == 0) {
1558 SMSD_Log(DEBUG_NOTICE
, Config
, "Same message as previous one: %s", Config
->SMSID
);
1560 if (Config
->retries
> Config
->maxretries
) {
1561 Config
->retries
= 0;
1562 strcpy(Config
->prevSMSID
, "");
1563 SMSD_Log(DEBUG_INFO
, Config
, "Moved to errorbox: %s", Config
->SMSID
);
1564 for (i
=0;i
<sms
.Number
;i
++) {
1565 Config
->Status
->Failed
++;
1566 Config
->Service
->AddSentSMSInfo(&sms
, Config
, Config
->SMSID
, i
+1, SMSD_SEND_ERROR
, -1);
1568 Config
->Service
->MoveSMS(&sms
,Config
, Config
->SMSID
, TRUE
,FALSE
);
1572 SMSD_Log(DEBUG_NOTICE
, Config
, "New message to send: %s", Config
->SMSID
);
1573 Config
->retries
= 0;
1574 strcpy(Config
->prevSMSID
, Config
->SMSID
);
1577 for (i
= 0; i
< sms
.Number
; i
++) {
1578 if (sms
.SMS
[i
].SMSC
.Location
== 0 && UnicodeLength(sms
.SMS
[i
].SMSC
.Number
) == 0 && Config
->SMSC
.Location
== 0) {
1579 SMSD_Log(DEBUG_INFO
, Config
, "Message without SMSC, using configured one");
1580 memcpy(&sms
.SMS
[i
].SMSC
,&Config
->SMSC
,sizeof(GSM_SMSC
));
1581 sms
.SMS
[i
].SMSC
.Location
= 0;
1582 if (Config
->relativevalidity
!= -1) {
1583 sms
.SMS
[i
].SMSC
.Validity
.Format
= SMS_Validity_RelativeFormat
;
1584 sms
.SMS
[i
].SMSC
.Validity
.Relative
= Config
->relativevalidity
;
1588 if (sms
.SMS
[i
].SMSC
.Location
== 0 && UnicodeLength(sms
.SMS
[i
].SMSC
.Number
) == 0) {
1589 SMSD_Log(DEBUG_INFO
, Config
, "Message without SMSC, assuming you want to use the one from phone");
1590 sms
.SMS
[i
].SMSC
.Location
= 1;
1592 if (sms
.SMS
[i
].SMSC
.Location
!= 0) {
1593 if (Config
->SMSCCache
.Location
!= sms
.SMS
[i
].SMSC
.Location
) {
1594 Config
->SMSCCache
.Location
= sms
.SMS
[i
].SMSC
.Location
;
1595 error
= GSM_GetSMSC(Config
->gsm
,&Config
->SMSCCache
);
1596 if (error
!=ERR_NONE
) {
1597 SMSD_Log(DEBUG_ERROR
, Config
, "Error getting SMSC from phone");
1602 memcpy(&sms
.SMS
[i
].SMSC
,&Config
->SMSCCache
,sizeof(GSM_SMSC
));
1603 sms
.SMS
[i
].SMSC
.Location
= 0;
1604 if (Config
->relativevalidity
!= -1) {
1605 sms
.SMS
[i
].SMSC
.Validity
.Format
= SMS_Validity_RelativeFormat
;
1606 sms
.SMS
[i
].SMSC
.Validity
.Relative
= Config
->relativevalidity
;
1610 if (Config
->currdeliveryreport
== 1) {
1611 sms
.SMS
[i
].PDU
= SMS_Status_Report
;
1612 } else if (Config
->currdeliveryreport
== -1 && strcmp(Config
->deliveryreport
, "no") != 0) {
1613 sms
.SMS
[i
].PDU
= SMS_Status_Report
;
1616 SMSD_PhoneStatus(Config
);
1618 Config
->SendingSMSStatus
= ERR_TIMEOUT
;
1619 error
= GSM_SendSMS(Config
->gsm
, &sms
.SMS
[i
]);
1620 if (error
!= ERR_NONE
) {
1621 SMSD_LogError(DEBUG_INFO
, Config
, "Error sending SMS", error
);
1623 goto failure_unsent
;
1626 while (!Config
->shutdown
) {
1627 /* Update timestamp for SMS in backend */
1628 Config
->Service
->RefreshSendStatus(Config
, Config
->SMSID
);
1630 GSM_GetCurrentDateTime(&Date
);
1632 while (z
== Date
.Second
) {
1634 GSM_GetCurrentDateTime(&Date
);
1635 GSM_ReadDevice(Config
->gsm
, TRUE
);
1636 if (Config
->SendingSMSStatus
!= ERR_TIMEOUT
) {
1640 if (Config
->SendingSMSStatus
!= ERR_TIMEOUT
) {
1644 if (j
> Config
->sendtimeout
) {
1648 if (Config
->SendingSMSStatus
!= ERR_NONE
) {
1649 SMSD_LogError(DEBUG_INFO
, Config
, "Error getting send status of message", Config
->SendingSMSStatus
);
1650 goto failure_unsent
;
1652 Config
->Status
->Sent
++;
1653 error
= Config
->Service
->AddSentSMSInfo(&sms
, Config
, Config
->SMSID
, i
+1, SMSD_SEND_OK
, Config
->TPMR
);
1654 if (error
!= ERR_NONE
) {
1658 strcpy(Config
->prevSMSID
, "");
1659 error
= Config
->Service
->MoveSMS(&sms
,Config
, Config
->SMSID
, FALSE
, TRUE
);
1660 if (error
!= ERR_NONE
) {
1661 SMSD_LogError(DEBUG_ERROR
, Config
, "Error moving message", error
);
1662 Config
->Service
->MoveSMS(&sms
,Config
, Config
->SMSID
, TRUE
, FALSE
);
1666 if (Config
->RunOnFailure
!= NULL
) {
1667 SMSD_RunOn(Config
->RunOnFailure
, NULL
, Config
, Config
->SMSID
);
1669 Config
->Status
->Failed
++;
1670 Config
->Service
->AddSentSMSInfo(&sms
, Config
, Config
->SMSID
, i
+ 1, SMSD_SEND_SENDING_ERROR
, Config
->TPMR
);
1671 Config
->Service
->MoveSMS(&sms
,Config
, Config
->SMSID
, TRUE
, FALSE
);
1674 if (Config
->Service
->MoveSMS(&sms
,Config
, Config
->SMSID
, FALSE
, TRUE
) != ERR_NONE
) {
1675 Config
->Service
->MoveSMS(&sms
,Config
, Config
->SMSID
, TRUE
, FALSE
);
1681 * Initializes shared memory segment, writable if asked for it.
1683 GSM_Error
SMSD_InitSharedMemory(GSM_SMSDConfig
*Config
, gboolean writable
)
1686 /* Allocate world redable SHM segment */
1687 Config
->shm_handle
= shmget(Config
->shm_key
, sizeof(GSM_SMSDStatus
), writable
? (IPC_CREAT
| S_IRWXU
| S_IRGRP
| S_IROTH
) : 0);
1688 if (Config
->shm_handle
== -1) {
1689 SMSD_Terminate(Config
, "Failed to allocate shared memory segment!", ERR_NONE
, TRUE
, -1);
1692 Config
->Status
= shmat(Config
->shm_handle
, NULL
, 0);
1693 if (Config
->Status
== (void *) -1) {
1694 SMSD_Terminate(Config
, "Failed to map shared memory segment!", ERR_NONE
, TRUE
, -1);
1697 if (!writable
&& Config
->Status
->Version
!= SMSD_SHM_VERSION
) {
1698 shmdt(Config
->Status
);
1699 return ERR_WRONGCRC
;
1702 SMSD_Log(DEBUG_INFO
, Config
, "Created POSIX RW shared memory at %p", Config
->Status
);
1704 SMSD_Log(DEBUG_INFO
, Config
, "Mapped POSIX RO shared memory at %p", Config
->Status
);
1706 #elif defined(WIN32)
1707 Config
->map_handle
= CreateFileMapping(INVALID_HANDLE_VALUE
, NULL
, writable
? PAGE_READWRITE
: PAGE_READONLY
, 0, sizeof(GSM_SMSDStatus
), Config
->map_key
);
1708 if (Config
->map_handle
== NULL
) {
1710 SMSD_Terminate(Config
, "Failed to allocate shared memory segment!", ERR_NONE
, TRUE
, -1);
1713 SMSD_LogErrno(Config
, "Can not CreateFileMapping");
1714 return ERR_NOTRUNNING
;
1717 Config
->Status
= MapViewOfFile(Config
->map_handle
, writable
? FILE_MAP_ALL_ACCESS
: FILE_MAP_READ
, 0, 0, sizeof(GSM_SMSDStatus
));
1718 if (Config
->Status
== NULL
) {
1720 SMSD_Terminate(Config
, "Failed to map shared memory!", ERR_NONE
, TRUE
, -1);
1723 SMSD_LogErrno(Config
, "Failet to map shared memory!");
1724 return ERR_NOTRUNNING
;
1728 SMSD_Log(DEBUG_INFO
, Config
, "Created Windows RW shared memory at %p", Config
->Status
);
1730 SMSD_Log(DEBUG_INFO
, Config
, "Mapped Windows RO shared memory at %p", Config
->Status
);
1734 return ERR_NOTSUPPORTED
;
1736 Config
->Status
= malloc(sizeof(GSM_SMSDStatus
));
1737 if (Config
->Status
== NULL
) {
1738 SMSD_Terminate(Config
, "Failed to map shared memory segment!", ERR_NONE
, TRUE
, -1);
1742 SMSD_Log(DEBUG_INFO
, Config
, "No shared memory, using standard malloc %p", Config
->Status
);
1745 /* Initial shared memory content */
1747 Config
->Status
->Version
= SMSD_SHM_VERSION
;
1748 strcpy(Config
->Status
->PhoneID
, Config
->PhoneID
);
1749 sprintf(Config
->Status
->Client
, "Gammu %s on %s compiler %s",
1753 memset(&Config
->Status
->Charge
, 0, sizeof(GSM_BatteryCharge
));
1754 memset(&Config
->Status
->Network
, 0, sizeof(GSM_SignalQuality
));
1755 Config
->Status
->Received
= 0;
1756 Config
->Status
->Failed
= 0;
1757 Config
->Status
->Sent
= 0;
1758 Config
->Status
->IMEI
[0] = 0;
1764 * Frees shared memory segment, writable if asked for it.
1766 GSM_Error
SMSD_FreeSharedMemory(GSM_SMSDConfig
*Config
, gboolean writable
)
1769 shmdt(Config
->Status
);
1771 shmctl(Config
->shm_handle
, IPC_RMID
, NULL
);
1773 #elif defined(WIN32)
1774 UnmapViewOfFile(Config
->Status
);
1775 CloseHandle(Config
->map_handle
);
1778 free(Config
->Status
);
1781 Config
->Status
= NULL
;
1785 * Main loop which takes care of connection to phone and processing of
1788 GSM_Error
SMSD_MainLoop(GSM_SMSDConfig
*Config
, gboolean exit_on_failure
, int max_failures
)
1791 int errors
= -1, initerrors
=0;
1792 time_t lastreceive
= 0, lastreset
= time(NULL
), lasthardreset
= time(NULL
), lastnothingsent
= 0, laststatus
= 0;
1793 time_t lastloop
= 0, current_time
;
1795 gboolean first_start
= TRUE
, force_reset
= FALSE
, force_hard_reset
= FALSE
;
1797 Config
->failure
= ERR_NONE
;
1798 Config
->exit_on_failure
= exit_on_failure
;
1801 error
= SMSD_Init(Config
);
1802 if (error
!=ERR_NONE
) {
1803 SMSD_Terminate(Config
, "Initialisation failed, stopping Gammu smsd", error
, TRUE
, -1);
1807 /* Init shared memory */
1808 error
= SMSD_InitSharedMemory(Config
, TRUE
);
1809 if (error
!= ERR_NONE
) {
1813 Config
->running
= TRUE
;
1815 Config
->SendingSMSStatus
= ERR_NONE
;
1817 while (!Config
->shutdown
) {
1818 lastloop
= time(NULL
);
1819 /* There were errors in communication - try to recover */
1820 if (errors
> 2 || first_start
|| force_reset
|| force_hard_reset
) {
1821 /* Should we disconnect from phone? */
1822 if (GSM_IsConnected(Config
->gsm
)) {
1823 if (! force_reset
&& ! force_hard_reset
) {
1824 SMSD_Log(DEBUG_INFO
, Config
, "Already hit %d errors", errors
);
1826 SMSD_LogError(DEBUG_INFO
, Config
, "Terminating communication", error
);
1827 GSM_TerminateConnection(Config
->gsm
);
1829 /* Did we reach limit for errors? */
1830 if (max_failures
!= 0 && initerrors
> max_failures
) {
1831 Config
->failure
= ERR_TIMEOUT
;
1832 SMSD_Log(DEBUG_INFO
, Config
, "Reached maximal number of failures (%d), terminating", max_failures
);
1835 if (initerrors
++ > 3) {
1836 SMSD_Log(DEBUG_INFO
, Config
, "Going to 30 seconds sleep because of too much connection errors");
1838 for (i
= 0; i
< 60; i
++) {
1839 if (Config
->shutdown
)
1844 SMSD_Log(DEBUG_INFO
, Config
, "Starting phone communication...");
1845 error
= GSM_InitConnection_Log(Config
->gsm
, 2, SMSD_Log_Function
, Config
);
1847 if (error
!= ERR_NONE
&& Config
->RunOnFailure
!= NULL
) {
1848 SMSD_RunOn(Config
->RunOnFailure
, NULL
, Config
, "INIT");
1852 if (Config
->checksecurity
&& !SMSD_CheckSecurity(Config
)) {
1857 GSM_SetSendSMSStatusCallback(Config
->gsm
, SMSD_SendSMSStatusCallback
, Config
);
1858 /* On first start we need to initialize some variables */
1860 if (GSM_GetIMEI(Config
->gsm
, Config
->Status
->IMEI
) != ERR_NONE
) {
1864 error
= Config
->Service
->InitAfterConnect(Config
);
1865 if (error
!=ERR_NONE
) {
1866 if (Config
->RunOnFailure
!= NULL
) {
1867 SMSD_RunOn(Config
->RunOnFailure
, NULL
, Config
, "INIT");
1869 SMSD_Terminate(Config
, "Post initialisation failed, stopping Gammu smsd", error
, TRUE
, -1);
1870 goto done_connected
;
1872 GSM_SetFastSMSSending(Config
->gsm
, TRUE
);
1874 first_start
= FALSE
;
1879 if (initerrors
> 3 || force_reset
) {
1880 error
= GSM_Reset(Config
->gsm
, FALSE
); /* soft reset */
1881 SMSD_LogError(DEBUG_INFO
, Config
, "Soft reset return code", error
);
1882 lastreset
= time(NULL
);
1884 force_reset
= FALSE
;
1886 if (force_hard_reset
) {
1887 error
= GSM_Reset(Config
->gsm
, TRUE
); /* hard reset */
1888 SMSD_LogError(DEBUG_INFO
, Config
, "Hard reset return code", error
);
1889 lasthardreset
= time(NULL
);
1891 force_hard_reset
= FALSE
;
1894 case ERR_DEVICEOPENERROR
:
1895 SMSD_Terminate(Config
, "Can't open device",
1899 SMSD_LogError(DEBUG_INFO
, Config
, "Error at init connection", error
);
1906 /* Should we receive? */
1907 if (Config
->enable_receive
&& ((difftime(time(NULL
), lastreceive
) >= Config
->receivefrequency
) || (Config
->SendingSMSStatus
!= ERR_NONE
))) {
1908 lastreceive
= time(NULL
);
1910 /* Do we need to check security? */
1911 if (Config
->checksecurity
&& !SMSD_CheckSecurity(Config
)) {
1921 /* read all incoming SMS */
1922 if (!SMSD_CheckSMSStatus(Config
)) {
1932 /* time for preventive reset */
1933 current_time
= time(NULL
);
1934 if (Config
->resetfrequency
> 0 && difftime(current_time
, lastreset
) >= Config
->resetfrequency
) {
1938 if (Config
->hardresetfrequency
> 0 && difftime(current_time
, lasthardreset
) >= Config
->hardresetfrequency
) {
1939 force_hard_reset
= TRUE
;
1943 /* Send any queued messages */
1944 current_time
= time(NULL
);
1945 if (Config
->enable_send
&& (difftime(current_time
, lastnothingsent
) >= Config
->commtimeout
)) {
1946 error
= SMSD_SendSMS(Config
);
1947 if (error
== ERR_EMPTY
) {
1948 lastnothingsent
= current_time
;
1950 /* We don't care about other errors here, they are handled in SMSD_SendSMS */
1953 /* Refresh phone status in shared memory and in service */
1954 current_time
= time(NULL
);
1955 if ((Config
->statusfrequency
> 0) && (difftime(current_time
, laststatus
) >= Config
->statusfrequency
)) {
1956 SMSD_PhoneStatus(Config
);
1957 laststatus
= current_time
;
1958 Config
->Service
->RefreshPhoneStatus(Config
);
1961 /* Sleep some time before another loop */
1962 current_time
= time(NULL
);
1963 if (Config
->loopsleep
== 1) {
1965 } else if (difftime(current_time
, lastloop
) < Config
->loopsleep
) {
1966 sleep(Config
->loopsleep
- difftime(current_time
, lastloop
));
1969 Config
->Service
->Free(Config
);
1972 /* Free shared memory */
1973 error
= SMSD_FreeSharedMemory(Config
, TRUE
);
1974 if (error
!= ERR_NONE
) {
1978 GSM_SetFastSMSSending(Config
->gsm
,FALSE
);
1980 SMSD_Terminate(Config
, "Stopping Gammu smsd", ERR_NONE
, FALSE
, 0);
1981 return Config
->failure
;
1985 * Function to inject message to service backend.
1987 GSM_Error
SMSD_InjectSMS(GSM_SMSDConfig
*Config
, GSM_MultiSMSMessage
*sms
, char *NewID
)
1991 /* Initialize service */
1992 error
= SMSD_Init(Config
);
1993 if (error
!= ERR_NONE
) {
1997 /* Store message in outbox */
1998 error
= Config
->Service
->CreateOutboxSMS(sms
, Config
, NewID
);
2003 * Returns current status of SMSD, either from shared memory segment or
2004 * from process memory if SMSD is running in same process.
2006 GSM_Error
SMSD_GetStatus(GSM_SMSDConfig
*Config
, GSM_SMSDStatus
*status
)
2009 /* Check for local instance */
2010 if (Config
->running
) {
2011 memcpy(status
, Config
->Status
, sizeof(GSM_SMSDStatus
));
2015 /* Init shared memory */
2016 error
= SMSD_InitSharedMemory(Config
, FALSE
);
2017 if (error
!= ERR_NONE
) {
2021 /* Copy data from shared memory */
2022 memcpy(status
, Config
->Status
, sizeof(GSM_SMSDStatus
));
2024 /* Free shared memory */
2025 error
= SMSD_FreeSharedMemory(Config
, FALSE
);
2026 if (error
!= ERR_NONE
) {
2032 GSM_Error
SMSD_NoneFunction(void)
2037 GSM_Error
SMSD_EmptyFunction(void)
2042 GSM_Error
SMSD_NotImplementedFunction(void)
2044 return ERR_NOTIMPLEMENTED
;
2047 GSM_Error
SMSD_NotSupportedFunction(void)
2049 return ERR_NOTSUPPORTED
;
2051 /* How should editor hadle tabs in this file? Add editor commands here.
2052 * vim: noexpandtab sw=8 ts=8 sts=8: