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
)
547 /* No logging configured */
548 if (Config
->logfilename
== NULL
) {
553 Config
->log_type
= SMSD_LOG_FILE
;
554 Config
->use_stderr
= FALSE
;
557 return ERR_CANTOPENFILE
;
559 Config
->log_handle
= fdopen(fd
, "a");
560 Config
->use_timestamps
= FALSE
;
561 #ifdef HAVE_WINDOWS_EVENT_LOG
562 } else if (strcmp(Config
->logfilename
, "eventlog") == 0) {
563 Config
->log_type
= SMSD_LOG_EVENTLOG
;
564 Config
->log_handle
= eventlog_init();
565 Config
->use_stderr
= TRUE
;
568 } else if (strcmp(Config
->logfilename
, "syslog") == 0) {
569 Config
->log_type
= SMSD_LOG_SYSLOG
;
570 openlog(Config
->program_name
, LOG_PID
, LOG_DAEMON
);
571 Config
->use_stderr
= TRUE
;
574 Config
->log_type
= SMSD_LOG_FILE
;
575 if (strcmp(Config
->logfilename
, "stderr") == 0) {
578 return ERR_CANTOPENFILE
;
580 Config
->log_handle
= fdopen(fd
, "a");
581 Config
->use_stderr
= FALSE
;
582 } else if (strcmp(Config
->logfilename
, "stdout") == 0) {
585 return ERR_CANTOPENFILE
;
587 Config
->log_handle
= fdopen(fd
, "a");
588 Config
->use_stderr
= FALSE
;
590 Config
->log_handle
= fopen(Config
->logfilename
, "a");
591 Config
->use_stderr
= TRUE
;
593 if (Config
->log_handle
== NULL
) {
594 fprintf(stderr
, "Can't open log file \"%s\"\n", Config
->logfilename
);
595 return ERR_CANTOPENFILE
;
597 fprintf(stderr
, "Log filename is \"%s\"\n",Config
->logfilename
);
603 * Reads configuration file and feeds it's content into SMSD configuration structure.
605 GSM_Error
SMSD_ReadConfig(const char *filename
, GSM_SMSDConfig
*Config
, gboolean uselog
)
608 GSM_Config
*gammucfg
;
612 char fullpath
[PATH_MAX
+ 1];
617 char config_name
[MAX_PATH
];
620 memset(&smsdcfg
, 0, sizeof(smsdcfg
));
622 Config
->shutdown
= FALSE
;
623 Config
->running
= FALSE
;
624 Config
->connected
= FALSE
;
625 Config
->failure
= ERR_NONE
;
626 Config
->exit_on_failure
= TRUE
;
627 Config
->gsm
= GSM_AllocStateMachine();
628 if (Config
->gsm
== NULL
) {
629 fprintf(stderr
, "Failed to allocate memory for state machine!\n");
630 return ERR_MOREMEMORY
;
632 Config
->gammu_log_buffer
= NULL
;
633 Config
->gammu_log_buffer_size
= 0;
634 Config
->logfilename
= NULL
;
635 Config
->smsdcfgfile
= NULL
;
636 Config
->use_timestamps
= TRUE
;
637 Config
->log_type
= SMSD_LOG_NONE
;
638 Config
->log_handle
= NULL
;
639 Config
->use_stderr
= TRUE
;
642 /* Calculate key for shared memory */
643 if (realpath(filename
, fullpath
) == NULL
) {
644 strncpy(fullpath
, filename
, PATH_MAX
);
645 fullpath
[PATH_MAX
] = 0;
647 Config
->shm_key
= ftok(fullpath
, SMSD_SHM_KEY
);
650 if (GetFullPathName(filename
, sizeof(config_name
), config_name
, NULL
) == 0) {
654 len
= sprintf(Config
->map_key
, "Gammu-smsd-%s", config_name
);
655 /* Replace some possibly dangerous chars */
656 for (i
= 0; i
< len
; i
++) {
657 if (!isalpha(Config
->map_key
[i
]) && !isdigit(Config
->map_key
[i
])) {
658 Config
->map_key
[i
] = '_';
663 error
= INI_ReadFile(filename
, FALSE
, &Config
->smsdcfgfile
);
664 if (Config
->smsdcfgfile
== NULL
|| error
!= ERR_NONE
) {
665 if (error
== ERR_FILENOTSUPPORTED
) {
666 fprintf(stderr
, "Could not parse config file \"%s\"\n",filename
);
668 fprintf(stderr
, "Can't find file \"%s\"\n",filename
);
670 return ERR_CANTOPENFILE
;
673 str
= INI_GetValue(Config
->smsdcfgfile
, "smsd", "debuglevel", FALSE
);
675 Config
->debug_level
= atoi(str
);
677 Config
->debug_level
= 0;
680 Config
->logfilename
=INI_GetValue(Config
->smsdcfgfile
, "smsd", "logfile", FALSE
);
681 error
= SMSD_ConfigureLogging(Config
, uselog
);
682 if (error
!= ERR_NONE
) {
686 Config
->ServiceName
= INI_GetValue(Config
->smsdcfgfile
, "smsd", "service", FALSE
);
688 /* Get service object */
689 error
= SMSGetService(Config
);
690 if (error
!= ERR_NONE
) {
694 SMSD_Log(DEBUG_NOTICE
, Config
, "Configuring Gammu SMSD...");
696 SMSD_Log(DEBUG_NOTICE
, Config
, "SHM token: 0x%llx (%lld)", (long long)Config
->shm_key
, (long long)Config
->shm_key
);
699 /* Does our config file contain gammu section? */
700 if (INI_FindLastSectionEntry(Config
->smsdcfgfile
, "gammu", FALSE
) == NULL
) {
701 SMSD_Log(DEBUG_ERROR
, Config
, "No gammu configuration found (no [gammu] section in SMSD config file)!");
702 return ERR_UNCONFIGURED
;
705 gammucfg
= GSM_GetConfig(Config
->gsm
, 0);
706 GSM_ReadConfig(Config
->smsdcfgfile
, gammucfg
, 0);
707 GSM_SetConfigNum(Config
->gsm
, 1);
708 gammucfg
->UseGlobalDebugFile
= FALSE
;
710 /* Force debug level in Gammu */
711 if ((DEBUG_GAMMU
& Config
->debug_level
) != 0) {
712 strcpy(gammucfg
->DebugLevel
, "textall");
713 GSM_SetDebugLevel("textall", GSM_GetGlobalDebug());
716 Config
->PINCode
=INI_GetValue(Config
->smsdcfgfile
, "smsd", "PIN", FALSE
);
717 if (Config
->PINCode
== NULL
) {
718 SMSD_Log(DEBUG_INFO
, Config
, "Warning: No PIN code in %s file",filename
);
720 SMSD_Log(DEBUG_NOTICE
, Config
, "PIN code is \"%s\"",Config
->PINCode
);
723 Config
->NetworkCode
= INI_GetValue(Config
->smsdcfgfile
, "smsd", "NetworkCode", FALSE
);
724 if (Config
->NetworkCode
!= NULL
) {
725 SMSD_Log(DEBUG_NOTICE
, Config
, "Network code is \"%s\"",Config
->NetworkCode
);
728 Config
->PhoneCode
= INI_GetValue(Config
->smsdcfgfile
, "smsd", "PhoneCode", FALSE
);
729 if (Config
->PhoneCode
!= NULL
) {
730 SMSD_Log(DEBUG_NOTICE
, Config
, "Phone code is \"%s\"",Config
->PhoneCode
);
733 Config
->commtimeout
= INI_GetInt(Config
->smsdcfgfile
, "smsd", "commtimeout", 30);
734 Config
->deliveryreportdelay
= INI_GetInt(Config
->smsdcfgfile
, "smsd", "deliveryreportdelay", 600);
735 Config
->sendtimeout
= INI_GetInt(Config
->smsdcfgfile
, "smsd", "sendtimeout", 30);
736 Config
->receivefrequency
= INI_GetInt(Config
->smsdcfgfile
, "smsd", "receivefrequency", 0);
737 Config
->statusfrequency
= INI_GetInt(Config
->smsdcfgfile
, "smsd", "statusfrequency", 15);
738 Config
->loopsleep
= INI_GetInt(Config
->smsdcfgfile
, "smsd", "loopsleep", 1);
739 Config
->checksecurity
= INI_GetBool(Config
->smsdcfgfile
, "smsd", "checksecurity", TRUE
);
740 Config
->checksignal
= INI_GetBool(Config
->smsdcfgfile
, "smsd", "checksignal", TRUE
);
741 Config
->checkbattery
= INI_GetBool(Config
->smsdcfgfile
, "smsd", "checkbattery", TRUE
);
742 Config
->enable_send
= INI_GetBool(Config
->smsdcfgfile
, "smsd", "send", TRUE
);
743 Config
->enable_receive
= INI_GetBool(Config
->smsdcfgfile
, "smsd", "receive", TRUE
);
744 Config
->resetfrequency
= INI_GetInt(Config
->smsdcfgfile
, "smsd", "resetfrequency", 0);
745 Config
->hardresetfrequency
= INI_GetInt(Config
->smsdcfgfile
, "smsd", "hardresetfrequency", 0);
746 Config
->multiparttimeout
= INI_GetInt(Config
->smsdcfgfile
, "smsd", "multiparttimeout", 600);
747 Config
->maxretries
= INI_GetInt(Config
->smsdcfgfile
, "smsd", "maxretries", 1);
748 Config
->backend_retries
= INI_GetInt(Config
->smsdcfgfile
, "smsd", "backendretries", 10);
750 SMSD_Log(DEBUG_NOTICE
, Config
, "CommTimeout=%i, SendTimeout=%i, ReceiveFrequency=%i, ResetFrequency=%i, HardResetFrequency=%i",
751 Config
->commtimeout
, Config
->sendtimeout
, Config
->receivefrequency
, Config
->resetfrequency
, Config
->hardresetfrequency
);
752 SMSD_Log(DEBUG_NOTICE
, Config
, "checks: CheckSecurity=%d, CheckBattery=%d, CheckSignal=%d",
753 Config
->checksecurity
, Config
->checkbattery
, Config
->checksignal
);
754 SMSD_Log(DEBUG_NOTICE
, Config
, "mode: Send=%d, Receive=%d",
755 Config
->enable_send
, Config
->enable_receive
);
757 Config
->skipsmscnumber
= INI_GetValue(Config
->smsdcfgfile
, "smsd", "skipsmscnumber", FALSE
);
758 if (Config
->skipsmscnumber
== NULL
) Config
->skipsmscnumber
="";
760 Config
->deliveryreport
= INI_GetValue(Config
->smsdcfgfile
, "smsd", "deliveryreport", FALSE
);
761 if (Config
->deliveryreport
== NULL
|| (strcasecmp(Config
->deliveryreport
, "log") != 0 && strcasecmp(Config
->deliveryreport
, "sms") != 0)) {
762 Config
->deliveryreport
= "no";
764 SMSD_Log(DEBUG_NOTICE
, Config
, "deliveryreport = %s", Config
->deliveryreport
);
766 Config
->PhoneID
= INI_GetValue(Config
->smsdcfgfile
, "smsd", "phoneid", FALSE
);
767 if (Config
->PhoneID
== NULL
) Config
->PhoneID
= "";
768 SMSD_Log(DEBUG_NOTICE
, Config
, "phoneid = %s", Config
->PhoneID
);
770 Config
->RunOnReceive
= INI_GetValue(Config
->smsdcfgfile
, "smsd", "runonreceive", FALSE
);
771 Config
->RunOnFailure
= INI_GetValue(Config
->smsdcfgfile
, "smsd", "runonfailure", FALSE
);
773 str
= INI_GetValue(Config
->smsdcfgfile
, "smsd", "smsc", FALSE
);
775 Config
->SMSC
.Location
= 1;
776 Config
->SMSC
.DefaultNumber
[0] = 0;
777 Config
->SMSC
.DefaultNumber
[1] = 0;
778 Config
->SMSC
.Name
[0] = 0;
779 Config
->SMSC
.Name
[1] = 0;
780 Config
->SMSC
.Validity
.Format
= SMS_Validity_NotAvailable
;
781 Config
->SMSC
.Format
= SMS_FORMAT_Text
;
782 EncodeUnicode(Config
->SMSC
.Number
, str
, strlen(str
));
784 Config
->SMSC
.Location
= 0;
787 /* Read service specific configuration */
788 error
= Config
->Service
->ReadConfiguration(Config
);
789 if (error
!= ERR_NONE
) return error
;
791 /* Process include section in config file */
792 error
= SMSD_LoadIniNumbersList(Config
, &(Config
->IncludeNumbersList
), "include_numbers");
793 if (error
!= ERR_NONE
) return error
;
794 /* Process exclude section in config file */
795 error
= SMSD_LoadIniNumbersList(Config
, &(Config
->ExcludeNumbersList
), "exclude_numbers");
796 if (error
!= ERR_NONE
) return error
;
798 /* Load include numbers from external file */
799 error
= SMSD_LoadNumbersFile(Config
, &(Config
->IncludeNumbersList
), "includenumbersfile");
800 if (error
!= ERR_NONE
) return error
;
802 /* Load exclude numbers from external file */
803 error
= SMSD_LoadNumbersFile(Config
, &(Config
->ExcludeNumbersList
), "excludenumbersfile");
804 if (error
!= ERR_NONE
) return error
;
806 if (Config
->IncludeNumbersList
.used
> 0) {
807 SMSD_Log(DEBUG_NOTICE
, Config
, "Include numbers available");
809 if (Config
->ExcludeNumbersList
.used
> 0) {
810 if (Config
->IncludeNumbersList
.used
== 0) {
811 SMSD_Log(DEBUG_NOTICE
, Config
, "Exclude numbers available");
813 SMSD_Log(DEBUG_INFO
, Config
, "Exclude numbers available, but IGNORED");
817 /* Process include section in config file */
818 error
= SMSD_LoadIniNumbersList(Config
, &(Config
->IncludeSMSCList
), "include_smsc");
819 if (error
!= ERR_NONE
) return error
;
820 /* Process exclude section in config file */
821 error
= SMSD_LoadIniNumbersList(Config
, &(Config
->ExcludeSMSCList
), "exclude_smsc");
822 if (error
!= ERR_NONE
) return error
;
824 /* Load include smsc from external file */
825 error
= SMSD_LoadNumbersFile(Config
, &(Config
->IncludeSMSCList
), "includesmscfile");
826 if (error
!= ERR_NONE
) return error
;
828 /* Load exclude smsc from external file */
829 error
= SMSD_LoadNumbersFile(Config
, &(Config
->ExcludeSMSCList
), "excludesmscfile");
830 if (error
!= ERR_NONE
) return error
;
832 if (Config
->IncludeSMSCList
.used
> 0) {
833 SMSD_Log(DEBUG_NOTICE
, Config
, "Include smsc available");
835 if (Config
->ExcludeSMSCList
.used
> 0) {
836 if (Config
->IncludeSMSCList
.used
== 0) {
837 SMSD_Log(DEBUG_NOTICE
, Config
, "Exclude smsc available");
839 SMSD_Log(DEBUG_INFO
, Config
, "Exclude smsc available, but IGNORED");
844 Config
->prevSMSID
[0] = 0;
845 Config
->relativevalidity
= -1;
846 Config
->Status
= NULL
;
847 Config
->IncompleteMessageID
= 0;
848 Config
->IncompleteMessageTime
= 0;
854 * Checks whether phone does not need to enter some PIN.
856 gboolean
SMSD_CheckSecurity(GSM_SMSDConfig
*Config
)
858 GSM_SecurityCode SecurityCode
;
860 const char *code
= NULL
;
863 error
= GSM_GetSecurityStatus(Config
->gsm
, &SecurityCode
.Type
);
865 /* No supported - do not check more */
866 if (error
== ERR_NOTSUPPORTED
) {
871 if (error
!= ERR_NONE
) {
872 SMSD_LogError(DEBUG_ERROR
, Config
, "Error getting security status", error
);
873 SMSD_Log(DEBUG_ERROR
, Config
, "You might want to set CheckSecurity = 0 to avoid checking security status");
877 /* If PIN, try to enter */
878 switch (SecurityCode
.Type
) {
882 code
= Config
->PINCode
;
885 code
= Config
->PhoneCode
;
888 code
= Config
->NetworkCode
;
890 case SEC_SecurityCode
:
894 SMSD_Terminate(Config
, "ERROR: phone requires not supported code type", ERR_UNKNOWN
, TRUE
, -1);
898 /* Check if the PIN was configured */
900 SMSD_Log(DEBUG_INFO
, Config
, "Warning: no code in config when phone might want one!");
905 SMSD_Log(DEBUG_NOTICE
, Config
, "Trying to enter code");
906 strcpy(SecurityCode
.Code
, code
);
907 error
= GSM_EnterSecurityCode(Config
->gsm
, &SecurityCode
);
908 if (error
== ERR_SECURITYERROR
) {
909 SMSD_Terminate(Config
, "ERROR: incorrect PIN", error
, TRUE
, -1);
912 if (error
!= ERR_NONE
) {
913 SMSD_LogError(DEBUG_ERROR
, Config
, "Error entering PIN", error
);
920 * Prepares a command line for RunOn() function to execute user command.
922 char *SMSD_RunOnCommand(const char *locations
, const char *command
)
927 assert(command
!= NULL
);
929 if (locations
== NULL
) {
930 result
= strdup(command
);
931 assert(result
!= NULL
);
935 len
= strlen(locations
) + strlen(command
) + 4;
936 result
= (char *)malloc(len
);
937 assert(result
!= NULL
);
939 snprintf(result
, len
, "%s %s", command
, locations
);
944 #define setenv(var, value, force) SetEnvironmentVariable(var, value)
948 * Fills in environment with information about messages.
950 void SMSD_RunOnReceiveEnvironment(GSM_MultiSMSMessage
*sms
, GSM_SMSDConfig
*Config
, const char *locations
)
952 GSM_MultiPartSMSInfo SMSInfo
;
953 char buffer
[100], name
[100];
956 /* Raw message data */
957 sprintf(buffer
, "%d", sms
->Number
);
958 setenv("SMS_MESSAGES", buffer
, 1);
959 for (i
= 0; i
< sms
->Number
; i
++) {
960 sprintf(buffer
, "%d", sms
->SMS
[i
].Class
);
961 sprintf(name
, "SMS_%d_CLASS", i
+ 1);
962 setenv(name
, buffer
, 1);
963 sprintf(name
, "SMS_%d_NUMBER", i
+ 1);
964 setenv(name
, DecodeUnicodeConsole(sms
->SMS
[i
].Number
), 1);
965 if (sms
->SMS
[i
].Coding
!= SMS_Coding_8bit
) {
966 sprintf(name
, "SMS_%d_TEXT", i
+ 1);
967 setenv(name
, DecodeUnicodeConsole(sms
->SMS
[i
].Text
), 1);
971 /* Decoded message data */
972 if (GSM_DecodeMultiPartSMS(GSM_GetDebug(Config
->gsm
), &SMSInfo
, sms
, TRUE
)) {
973 sprintf(buffer
, "%d", SMSInfo
.EntriesNum
);
974 setenv("DECODED_PARTS", buffer
, 1);
975 for (i
= 0; i
< SMSInfo
.EntriesNum
; i
++) {
976 switch (SMSInfo
.Entries
[i
].ID
) {
977 case SMS_ConcatenatedTextLong
:
978 case SMS_ConcatenatedAutoTextLong
:
979 case SMS_ConcatenatedTextLong16bit
:
980 case SMS_ConcatenatedAutoTextLong16bit
:
981 case SMS_NokiaVCARD21Long
:
982 case SMS_NokiaVCALENDAR10Long
:
983 sprintf(name
, "DECODED_%d_TEXT", i
);
984 setenv(name
, DecodeUnicodeConsole(SMSInfo
.Entries
[i
].Buffer
), 1);
986 case SMS_MMSIndicatorLong
:
987 sprintf(name
, "DECODED_%d_MMS_SENDER", i
+ 1);
988 setenv(name
, SMSInfo
.Entries
[i
].MMSIndicator
->Sender
, 1);
989 sprintf(name
, "DECODED_%d_MMS_TITLE", i
+ 1);
990 setenv(name
, SMSInfo
.Entries
[i
].MMSIndicator
->Title
, 1);
991 sprintf(name
, "DECODED_%d_MMS_ADDRESS", i
+ 1);
992 setenv(name
, SMSInfo
.Entries
[i
].MMSIndicator
->Address
, 1);
993 sprintf(name
, "DECODED_%d_MMS_SIZE", i
+ 1);
994 sprintf(buffer
, "%ld", (long)SMSInfo
.Entries
[i
].MMSIndicator
->MessageSize
);
995 setenv(name
, buffer
, 1);
998 /* We ignore others for now */
1003 setenv("DECODED_PARTS", "0", 1);
1005 GSM_FreeMultiPartSMSInfo(&SMSInfo
);
1011 * Executes external command.
1013 * This is Windows variant.
1015 gboolean
SMSD_RunOn(const char *command
, GSM_MultiSMSMessage
*sms
, GSM_SMSDConfig
*Config
, const char *locations
)
1019 PROCESS_INFORMATION pi
;
1022 cmdline
= SMSD_RunOnCommand(locations
, command
);
1024 /* Prepare environment */
1026 SMSD_RunOnReceiveEnvironment(sms
, Config
, locations
);
1029 ZeroMemory(&si
, sizeof(si
));
1031 ZeroMemory(&pi
, sizeof(pi
));
1033 SMSD_Log(DEBUG_INFO
, Config
, "Starting run on command: %s", cmdline
);
1035 ret
= CreateProcess(NULL
, /* No module name (use command line) */
1036 cmdline
, /* Command line */
1037 NULL
, /* Process handle not inheritable*/
1038 NULL
, /* Thread handle not inheritable*/
1039 FALSE
, /* Set handle inheritance to FALSE*/
1040 0, /* No creation flags*/
1041 NULL
, /* Use parent's environment block*/
1042 NULL
, /* Use parent's starting directory */
1043 &si
, /* Pointer to STARTUPINFO structure*/
1044 &pi
); /* Pointer to PROCESS_INFORMATION structure*/
1047 SMSD_LogErrno(Config
, "CreateProcess failed");
1049 /* We don't need handles at all */
1050 CloseHandle(pi
.hProcess
);
1051 CloseHandle(pi
.hThread
);
1058 * Executes external command.
1060 * This is POSIX variant.
1062 gboolean
SMSD_RunOn(const char *command
, GSM_MultiSMSMessage
*sms
, GSM_SMSDConfig
*Config
, const char *locations
)
1073 SMSD_LogErrno(Config
, "Error spawning new process");
1078 /* We are the parent, wait for child */
1081 w
= waitpid(pid
, &status
, WUNTRACED
| WCONTINUED
);
1083 SMSD_Log(DEBUG_INFO
, Config
, "Failed to wait for process");
1087 if (WIFEXITED(status
)) {
1088 if (WEXITSTATUS(status
) == 0) {
1089 SMSD_Log(DEBUG_INFO
, Config
, "Process finished successfully");
1091 SMSD_Log(DEBUG_ERROR
, Config
, "Process failed with exit status %d", WEXITSTATUS(status
));
1093 return (WEXITSTATUS(status
) == 0);
1094 } else if (WIFSIGNALED(status
)) {
1095 SMSD_Log(DEBUG_ERROR
, Config
, "Process killed by signal %d", WTERMSIG(status
));
1097 } else if (WIFSTOPPED(status
)) {
1098 SMSD_Log(DEBUG_INFO
, Config
, "Process stopped by signal %d", WSTOPSIG(status
));
1099 } else if (WIFCONTINUED(status
)) {
1100 SMSD_Log(DEBUG_INFO
, Config
, "Process continued");
1105 SMSD_Log(DEBUG_INFO
, Config
, "Waited two minutes for child process, giving up");
1108 } while (!WIFEXITED(status
) && !WIFSIGNALED(status
));
1113 /* we are the child */
1115 /* Prepare environment */
1117 SMSD_RunOnReceiveEnvironment(sms
, Config
, locations
);
1120 /* Calculate command line */
1121 cmdline
= SMSD_RunOnCommand(locations
, command
);
1122 SMSD_Log(DEBUG_INFO
, Config
, "Starting run on receive: %s", cmdline
);
1124 /* Close all file descriptors */
1125 for (i
= 0; i
< 255; i
++) {
1129 /* Run the program */
1130 status
= system(cmdline
);
1132 /* Propagate error code */
1133 if (WIFEXITED(status
)) {
1134 exit(WEXITSTATUS(status
));
1142 * Checks whether we are allowed to accept a message from number.
1144 gboolean
SMSD_CheckRemoteNumber(GSM_SMSDConfig
*Config
, const char *number
)
1146 if (Config
->IncludeNumbersList
.used
> 0) {
1147 if (GSM_StringArray_Find(&(Config
->IncludeNumbersList
), number
)) {
1148 SMSD_Log(DEBUG_NOTICE
, Config
, "Number %s matched IncludeNumbers", number
);
1152 } else if (Config
->ExcludeNumbersList
.used
> 0) {
1153 if (GSM_StringArray_Find(&(Config
->ExcludeNumbersList
), number
)) {
1154 SMSD_Log(DEBUG_NOTICE
, Config
, "Number %s matched ExcludeNumbers", number
);
1164 * Checks whether we are allowed to accept a message from number.
1166 gboolean
SMSD_CheckSMSCNumber(GSM_SMSDConfig
*Config
, const char *number
)
1168 if (Config
->IncludeSMSCList
.used
> 0) {
1169 if (GSM_StringArray_Find(&(Config
->IncludeSMSCList
), number
)) {
1170 SMSD_Log(DEBUG_NOTICE
, Config
, "Number %s matched IncludeSMSC", number
);
1174 } else if (Config
->ExcludeSMSCList
.used
> 0) {
1175 if (GSM_StringArray_Find(&(Config
->ExcludeSMSCList
), number
)) {
1176 SMSD_Log(DEBUG_NOTICE
, Config
, "Number %s matched ExcludeSMSC", number
);
1186 * Performs checks whether given message is valid to be received by SMSD.
1188 gboolean
SMSD_ValidMessage(GSM_SMSDConfig
*Config
, GSM_MultiSMSMessage
*sms
)
1192 /* Not Inbox SMS - exit */
1193 if (!sms
->SMS
[0].InboxFolder
) {
1196 /* Check SMSC number if we want to handle it */
1197 DecodeUnicode(sms
->SMS
[0].SMSC
.Number
, buffer
);
1198 if (!SMSD_CheckSMSCNumber(Config
, buffer
)) {
1199 SMSD_Log(DEBUG_NOTICE
, Config
, "Message excluded because of SMSC: %s", buffer
);
1202 /* Check sender number if we want to handle it */
1203 DecodeUnicode(sms
->SMS
[0].Number
, buffer
);
1204 if (!SMSD_CheckRemoteNumber(Config
, buffer
)) {
1205 SMSD_Log(DEBUG_NOTICE
, Config
, "Message excluded because of sender: %s", buffer
);
1208 /* Finally process the message */
1209 SMSD_Log(DEBUG_NOTICE
, Config
, "Received message from: %s", buffer
);
1214 * Does any processing is required for single message after it has been accepted.
1216 * Stores message in the backend and executes RunOnReceive.
1218 GSM_Error
SMSD_ProcessSMS(GSM_SMSDConfig
*Config
, GSM_MultiSMSMessage
*sms
)
1220 GSM_Error error
= ERR_NONE
;
1221 char *locations
= NULL
;
1223 /* Increase message counter */
1224 Config
->Status
->Received
+= sms
->Number
;
1225 /* Send message to the backend */
1226 error
= Config
->Service
->SaveInboxSMS(sms
, Config
, &locations
);
1227 /* RunOnReceive handling */
1228 if (Config
->RunOnReceive
!= NULL
&& error
== ERR_NONE
) {
1229 SMSD_RunOn(Config
->RunOnReceive
, sms
, Config
, locations
);
1231 /* Free memory allocated by SaveInboxSMS */
1237 * Checks whether to process current (possibly) multipart message.
1239 gboolean
SMSD_CheckMultipart(GSM_SMSDConfig
*Config
, GSM_MultiSMSMessage
*MultiSMS
)
1243 /* Does the message have UDH (is multipart)? */
1244 if (MultiSMS
->SMS
[0].UDH
.Type
== UDH_NoUDH
|| MultiSMS
->SMS
[0].UDH
.AllParts
== -1) {
1248 /* Do we have same id as last incomplete? */
1249 same_id
= (Config
->IncompleteMessageID
== MultiSMS
->SMS
[0].UDH
.ID16bit
|| Config
->IncompleteMessageID
== MultiSMS
->SMS
[0].UDH
.ID8bit
);
1251 /* Check if we have all parts */
1252 if (MultiSMS
->SMS
[0].UDH
.AllParts
== MultiSMS
->Number
) {
1256 /* Have we seen this message recently? */
1258 if (Config
->IncompleteMessageTime
!= 0 && difftime(time(NULL
), Config
->IncompleteMessageTime
) > Config
->multiparttimeout
) {
1259 SMSD_Log(DEBUG_INFO
, Config
, "Incomplete multipart message 0x%02X, processing after timeout",
1260 Config
->IncompleteMessageID
);
1262 SMSD_Log(DEBUG_INFO
, Config
, "Incomplete multipart message 0x%02X, waiting for other parts (waited %.0f seconds)",
1263 Config
->IncompleteMessageID
,
1264 difftime(time(NULL
), Config
->IncompleteMessageTime
));
1268 if (Config
->IncompleteMessageTime
== 0) {
1269 if (MultiSMS
->SMS
[0].UDH
.ID16bit
!= -1) {
1270 Config
->IncompleteMessageID
= MultiSMS
->SMS
[0].UDH
.ID16bit
;
1272 Config
->IncompleteMessageID
= MultiSMS
->SMS
[0].UDH
.ID8bit
;
1274 Config
->IncompleteMessageTime
= time(NULL
);
1275 SMSD_Log(DEBUG_INFO
, Config
, "Incomplete multipart message 0x%02X, waiting for other parts",
1276 Config
->IncompleteMessageID
);
1279 SMSD_Log(DEBUG_INFO
, Config
, "Incomplete multipart message 0x%02X, but waiting for other one",
1280 Config
->IncompleteMessageID
);
1286 /* Clean multipart wait flag */
1288 Config
->IncompleteMessageTime
= 0;
1294 * Reads message from phone, processes it and delete it from phone afterwards.
1296 * It tries to link multipart messages together if possible.
1298 gboolean
SMSD_ReadDeleteSMS(GSM_SMSDConfig
*Config
)
1301 GSM_MultiSMSMessage sms
;
1302 GSM_MultiSMSMessage
**GetSMSData
= NULL
, **SortedSMS
;
1304 GSM_Error error
= ERR_NONE
;
1305 int GetSMSNumber
= 0;
1308 /* Read messages from phone */
1311 sms
.SMS
[0].Location
= 0;
1312 while (error
== ERR_NONE
&& !Config
->shutdown
) {
1313 sms
.SMS
[0].Folder
= 0;
1314 error
= GSM_GetNextSMS(Config
->gsm
, &sms
, start
);
1319 if (SMSD_ValidMessage(Config
, &sms
)) {
1320 if (allocated
<= GetSMSNumber
+ 2) {
1321 GetSMSData
= (GSM_MultiSMSMessage
**)realloc(GetSMSData
, (allocated
+ 20) * sizeof(GSM_MultiSMSMessage
*));
1322 if (GetSMSData
== NULL
) {
1323 SMSD_Log(DEBUG_ERROR
, Config
, "Failed to allocate memory");
1328 GetSMSData
[GetSMSNumber
] = malloc(sizeof(GSM_MultiSMSMessage
));
1330 if (GetSMSData
[GetSMSNumber
] == NULL
) {
1331 SMSD_Log(DEBUG_ERROR
, Config
, "Failed to allocate memory");
1335 *(GetSMSData
[GetSMSNumber
]) = sms
;
1337 GetSMSData
[GetSMSNumber
] = NULL
;
1341 SMSD_LogError(DEBUG_INFO
, Config
, "Error getting SMS", error
);
1347 /* Log how many messages were read */
1348 SMSD_Log(DEBUG_INFO
, Config
, "Read %d messages", GetSMSNumber
);
1350 /* No messages to process */
1351 if (GetSMSNumber
== 0) {
1355 /* Allocate memory for sorted messages */
1356 SortedSMS
= (GSM_MultiSMSMessage
**)malloc(allocated
* sizeof(GSM_MultiSMSMessage
*));
1357 if (SortedSMS
== NULL
) {
1358 SMSD_Log(DEBUG_ERROR
, Config
, "Failed to allocate memory for linking messages");
1359 SMSD_Log(DEBUG_ERROR
, Config
, "Skipping linking messages, long messages will not be connected");
1360 SortedSMS
= GetSMSData
;
1363 error
= GSM_LinkSMS(GSM_GetDebug(Config
->gsm
), GetSMSData
, SortedSMS
, TRUE
);
1364 if (error
!= ERR_NONE
) return FALSE
;
1367 for (i
= 0; GetSMSData
[i
] != NULL
; i
++) {
1368 free(GetSMSData
[i
]);
1369 GetSMSData
[i
] = NULL
;
1374 /* Process messages */
1375 for (i
= 0; SortedSMS
[i
] != NULL
; i
++) {
1376 /* Check multipart message parts */
1377 if (!SMSD_CheckMultipart(Config
, SortedSMS
[i
])) {
1381 /* Actually process the message */
1382 error
= SMSD_ProcessSMS(Config
, SortedSMS
[i
]);
1383 if (error
!= ERR_NONE
) {
1384 SMSD_LogError(DEBUG_INFO
, Config
, "Error processing SMS", error
);
1388 /* Delete processed messages */
1389 for (j
= 0; j
< SortedSMS
[i
]->Number
; j
++) {
1390 SortedSMS
[i
]->SMS
[j
].Folder
= 0;
1391 error
= GSM_DeleteSMS(Config
->gsm
, &SortedSMS
[i
]->SMS
[j
]);
1397 SMSD_LogError(DEBUG_INFO
, Config
, "Error deleting SMS", error
);
1404 SortedSMS
[i
] = NULL
;
1411 * Checks whether there are some messages to process and calls
1412 * SMSD_ReadDeleteSMS to process them.
1414 gboolean
SMSD_CheckSMSStatus(GSM_SMSDConfig
*Config
)
1416 GSM_SMSMemoryStatus SMSStatus
;
1418 gboolean new_message
= FALSE
;
1419 GSM_MultiSMSMessage sms
;
1421 /* Do we have any SMS in phone ? */
1423 /* First try SMS status */
1424 error
= GSM_GetSMSStatus(Config
->gsm
,&SMSStatus
);
1425 if (error
== ERR_NONE
) {
1426 new_message
= (SMSStatus
.SIMUsed
+ SMSStatus
.PhoneUsed
> 0);
1427 } else if (error
== ERR_NOTSUPPORTED
|| error
== ERR_NOTIMPLEMENTED
) {
1428 /* Fallback to GetNext */
1430 sms
.SMS
[0].Location
= 0;
1431 sms
.SMS
[0].Folder
= 0;
1432 error
= GSM_GetNextSMS(Config
->gsm
, &sms
, TRUE
);
1433 new_message
= (error
== ERR_NONE
);
1435 SMSD_LogError(DEBUG_INFO
, Config
, "Error getting SMS status", error
);
1439 /* Yes. We have SMS in phone */
1441 return SMSD_ReadDeleteSMS(Config
);
1448 * Reads status from phone to configuration.
1450 void SMSD_PhoneStatus(GSM_SMSDConfig
*Config
) {
1453 if (Config
->checkbattery
) {
1454 error
= GSM_GetBatteryCharge(Config
->gsm
, &Config
->Status
->Charge
);
1456 error
= ERR_UNKNOWN
;
1458 if (error
!= ERR_NONE
) {
1459 memset(&(Config
->Status
->Charge
), 0, sizeof(Config
->Status
->Charge
));
1461 if (Config
->checksignal
) {
1462 error
= GSM_GetSignalQuality(Config
->gsm
, &Config
->Status
->Network
);
1464 error
= ERR_UNKNOWN
;
1466 if (error
!= ERR_NONE
) {
1467 memset(&(Config
->Status
->Network
), 0, sizeof(Config
->Status
->Network
));
1472 * Sends a sms message which is provided by the service backend.
1474 GSM_Error
SMSD_SendSMS(GSM_SMSDConfig
*Config
)
1476 GSM_MultiSMSMessage sms
;
1482 /* Clean structure before use */
1483 for (i
= 0; i
< GSM_MAX_MULTI_SMS
; i
++) {
1484 GSM_SetDefaultSMSData(&sms
.SMS
[i
]);
1487 error
= Config
->Service
->FindOutboxSMS(&sms
, Config
, Config
->SMSID
);
1489 if (error
== ERR_EMPTY
|| error
== ERR_NOTSUPPORTED
) {
1493 if (error
!= ERR_NONE
) {
1494 /* Unknown error - escape */
1495 SMSD_Log(DEBUG_INFO
, Config
, "Error in outbox on '%s'", Config
->SMSID
);
1496 for (i
=0;i
<sms
.Number
;i
++) {
1497 Config
->Status
->Failed
++;
1498 Config
->Service
->AddSentSMSInfo(&sms
, Config
, Config
->SMSID
, i
+1, SMSD_SEND_ERROR
, -1);
1500 Config
->Service
->MoveSMS(&sms
,Config
, Config
->SMSID
, TRUE
,FALSE
);
1504 if (Config
->shutdown
) {
1508 if (Config
->SMSID
[0] != 0 && strcmp(Config
->prevSMSID
, Config
->SMSID
) == 0) {
1509 SMSD_Log(DEBUG_NOTICE
, Config
, "Same message as previous one: %s", Config
->SMSID
);
1511 if (Config
->retries
> Config
->maxretries
) {
1512 Config
->retries
= 0;
1513 strcpy(Config
->prevSMSID
, "");
1514 SMSD_Log(DEBUG_INFO
, Config
, "Moved to errorbox: %s", Config
->SMSID
);
1515 for (i
=0;i
<sms
.Number
;i
++) {
1516 Config
->Status
->Failed
++;
1517 Config
->Service
->AddSentSMSInfo(&sms
, Config
, Config
->SMSID
, i
+1, SMSD_SEND_ERROR
, -1);
1519 Config
->Service
->MoveSMS(&sms
,Config
, Config
->SMSID
, TRUE
,FALSE
);
1523 SMSD_Log(DEBUG_NOTICE
, Config
, "New message to send: %s", Config
->SMSID
);
1524 Config
->retries
= 0;
1525 strcpy(Config
->prevSMSID
, Config
->SMSID
);
1528 for (i
= 0; i
< sms
.Number
; i
++) {
1529 if (sms
.SMS
[i
].SMSC
.Location
== 0 && UnicodeLength(sms
.SMS
[i
].SMSC
.Number
) == 0) {
1530 SMSD_Log(DEBUG_INFO
, Config
, "Message without SMSC, assuming you want to use the one from phone");
1531 sms
.SMS
[i
].SMSC
.Location
= 1;
1533 if (sms
.SMS
[i
].SMSC
.Location
!= 0) {
1534 if (Config
->SMSC
.Location
!= sms
.SMS
[i
].SMSC
.Location
) {
1535 Config
->SMSC
.Location
= sms
.SMS
[i
].SMSC
.Location
;
1536 error
= GSM_GetSMSC(Config
->gsm
,&Config
->SMSC
);
1537 if (error
!=ERR_NONE
) {
1538 SMSD_Log(DEBUG_ERROR
, Config
, "Error getting SMSC from phone");
1543 memcpy(&sms
.SMS
[i
].SMSC
,&Config
->SMSC
,sizeof(GSM_SMSC
));
1544 sms
.SMS
[i
].SMSC
.Location
= 0;
1545 if (Config
->relativevalidity
!= -1) {
1546 sms
.SMS
[i
].SMSC
.Validity
.Format
= SMS_Validity_RelativeFormat
;
1547 sms
.SMS
[i
].SMSC
.Validity
.Relative
= Config
->relativevalidity
;
1551 if (Config
->currdeliveryreport
== 1) {
1552 sms
.SMS
[i
].PDU
= SMS_Status_Report
;
1553 } else if (Config
->currdeliveryreport
== -1 && strcmp(Config
->deliveryreport
, "no") != 0) {
1554 sms
.SMS
[i
].PDU
= SMS_Status_Report
;
1557 SMSD_PhoneStatus(Config
);
1559 Config
->SendingSMSStatus
= ERR_TIMEOUT
;
1560 error
= GSM_SendSMS(Config
->gsm
, &sms
.SMS
[i
]);
1561 if (error
!= ERR_NONE
) {
1562 SMSD_LogError(DEBUG_INFO
, Config
, "Error sending SMS", error
);
1564 goto failure_unsent
;
1567 while (!Config
->shutdown
) {
1568 /* Update timestamp for SMS in backend */
1569 Config
->Service
->RefreshSendStatus(Config
, Config
->SMSID
);
1571 GSM_GetCurrentDateTime(&Date
);
1573 while (z
== Date
.Second
) {
1575 GSM_GetCurrentDateTime(&Date
);
1576 GSM_ReadDevice(Config
->gsm
, TRUE
);
1577 if (Config
->SendingSMSStatus
!= ERR_TIMEOUT
) {
1581 if (Config
->SendingSMSStatus
!= ERR_TIMEOUT
) {
1585 if (j
> Config
->sendtimeout
) {
1589 if (Config
->SendingSMSStatus
!= ERR_NONE
) {
1590 SMSD_LogError(DEBUG_INFO
, Config
, "Error getting send status of message", Config
->SendingSMSStatus
);
1591 goto failure_unsent
;
1593 Config
->Status
->Sent
++;
1594 error
= Config
->Service
->AddSentSMSInfo(&sms
, Config
, Config
->SMSID
, i
+1, SMSD_SEND_OK
, Config
->TPMR
);
1595 if (error
!= ERR_NONE
) {
1599 strcpy(Config
->prevSMSID
, "");
1600 error
= Config
->Service
->MoveSMS(&sms
,Config
, Config
->SMSID
, FALSE
, TRUE
);
1601 if (error
!= ERR_NONE
) {
1602 SMSD_LogError(DEBUG_ERROR
, Config
, "Error moving message", error
);
1603 Config
->Service
->MoveSMS(&sms
,Config
, Config
->SMSID
, TRUE
, FALSE
);
1607 if (Config
->RunOnFailure
!= NULL
) {
1608 SMSD_RunOn(Config
->RunOnFailure
, NULL
, Config
, Config
->SMSID
);
1610 Config
->Status
->Failed
++;
1611 Config
->Service
->AddSentSMSInfo(&sms
, Config
, Config
->SMSID
, i
+ 1, SMSD_SEND_SENDING_ERROR
, Config
->TPMR
);
1612 Config
->Service
->MoveSMS(&sms
,Config
, Config
->SMSID
, TRUE
, FALSE
);
1615 if (Config
->Service
->MoveSMS(&sms
,Config
, Config
->SMSID
, FALSE
, TRUE
) != ERR_NONE
) {
1616 Config
->Service
->MoveSMS(&sms
,Config
, Config
->SMSID
, TRUE
, FALSE
);
1622 * Initializes shared memory segment, writable if asked for it.
1624 GSM_Error
SMSD_InitSharedMemory(GSM_SMSDConfig
*Config
, gboolean writable
)
1627 /* Allocate world redable SHM segment */
1628 Config
->shm_handle
= shmget(Config
->shm_key
, sizeof(GSM_SMSDStatus
), writable
? (IPC_CREAT
| S_IRWXU
| S_IRGRP
| S_IROTH
) : 0);
1629 if (Config
->shm_handle
== -1) {
1630 SMSD_Terminate(Config
, "Failed to allocate shared memory segment!", ERR_NONE
, TRUE
, -1);
1633 Config
->Status
= shmat(Config
->shm_handle
, NULL
, 0);
1634 if (Config
->Status
== (void *) -1) {
1635 SMSD_Terminate(Config
, "Failed to map shared memory segment!", ERR_NONE
, TRUE
, -1);
1638 if (!writable
&& Config
->Status
->Version
!= SMSD_SHM_VERSION
) {
1639 shmdt(Config
->Status
);
1640 return ERR_WRONGCRC
;
1643 SMSD_Log(DEBUG_INFO
, Config
, "Created POSIX RW shared memory at %p", Config
->Status
);
1645 SMSD_Log(DEBUG_INFO
, Config
, "Mapped POSIX RO shared memory at %p", Config
->Status
);
1647 #elif defined(WIN32)
1648 Config
->map_handle
= CreateFileMapping(INVALID_HANDLE_VALUE
, NULL
, writable
? PAGE_READWRITE
: PAGE_READONLY
, 0, sizeof(GSM_SMSDStatus
), Config
->map_key
);
1649 if (Config
->map_handle
== NULL
) {
1651 SMSD_Terminate(Config
, "Failed to allocate shared memory segment!", ERR_NONE
, TRUE
, -1);
1654 SMSD_LogErrno(Config
, "Can not CreateFileMapping");
1655 return ERR_NOTRUNNING
;
1658 Config
->Status
= MapViewOfFile(Config
->map_handle
, writable
? FILE_MAP_ALL_ACCESS
: FILE_MAP_READ
, 0, 0, sizeof(GSM_SMSDStatus
));
1659 if (Config
->Status
== NULL
) {
1661 SMSD_Terminate(Config
, "Failed to map shared memory!", ERR_NONE
, TRUE
, -1);
1664 SMSD_LogErrno(Config
, "Failet to map shared memory!");
1665 return ERR_NOTRUNNING
;
1669 SMSD_Log(DEBUG_INFO
, Config
, "Created Windows RW shared memory at %p", Config
->Status
);
1671 SMSD_Log(DEBUG_INFO
, Config
, "Mapped Windows RO shared memory at %p", Config
->Status
);
1675 return ERR_NOTSUPPORTED
;
1677 Config
->Status
= malloc(sizeof(GSM_SMSDStatus
));
1678 if (Config
->Status
== NULL
) {
1679 SMSD_Terminate(Config
, "Failed to map shared memory segment!", ERR_NONE
, TRUE
, -1);
1683 SMSD_Log(DEBUG_INFO
, Config
, "No shared memory, using standard malloc %p", Config
->Status
);
1686 /* Initial shared memory content */
1688 Config
->Status
->Version
= SMSD_SHM_VERSION
;
1689 strcpy(Config
->Status
->PhoneID
, Config
->PhoneID
);
1690 sprintf(Config
->Status
->Client
, "Gammu %s on %s compiler %s",
1694 memset(&Config
->Status
->Charge
, 0, sizeof(GSM_BatteryCharge
));
1695 memset(&Config
->Status
->Network
, 0, sizeof(GSM_SignalQuality
));
1696 Config
->Status
->Received
= 0;
1697 Config
->Status
->Failed
= 0;
1698 Config
->Status
->Sent
= 0;
1699 Config
->Status
->IMEI
[0] = 0;
1705 * Frees shared memory segment, writable if asked for it.
1707 GSM_Error
SMSD_FreeSharedMemory(GSM_SMSDConfig
*Config
, gboolean writable
)
1710 shmdt(Config
->Status
);
1712 shmctl(Config
->shm_handle
, IPC_RMID
, NULL
);
1714 #elif defined(WIN32)
1715 UnmapViewOfFile(Config
->Status
);
1716 CloseHandle(Config
->map_handle
);
1719 free(Config
->Status
);
1722 Config
->Status
= NULL
;
1726 * Main loop which takes care of connection to phone and processing of
1729 GSM_Error
SMSD_MainLoop(GSM_SMSDConfig
*Config
, gboolean exit_on_failure
, int max_failures
)
1732 int errors
= -1, initerrors
=0;
1733 time_t lastreceive
= 0, lastreset
= time(NULL
), lasthardreset
= time(NULL
), lastnothingsent
= 0, laststatus
= 0;
1734 time_t lastloop
= 0, current_time
;
1736 gboolean first_start
= TRUE
, force_reset
= FALSE
, force_hard_reset
= FALSE
;
1738 Config
->failure
= ERR_NONE
;
1739 Config
->exit_on_failure
= exit_on_failure
;
1742 error
= SMSD_Init(Config
);
1743 if (error
!=ERR_NONE
) {
1744 SMSD_Terminate(Config
, "Initialisation failed, stopping Gammu smsd", error
, TRUE
, -1);
1748 /* Init shared memory */
1749 error
= SMSD_InitSharedMemory(Config
, TRUE
);
1750 if (error
!= ERR_NONE
) {
1754 Config
->running
= TRUE
;
1756 Config
->SendingSMSStatus
= ERR_NONE
;
1758 while (!Config
->shutdown
) {
1759 lastloop
= time(NULL
);
1760 /* There were errors in communication - try to recover */
1761 if (errors
> 2 || first_start
|| force_reset
|| force_hard_reset
) {
1762 /* Should we disconnect from phone? */
1763 if (GSM_IsConnected(Config
->gsm
)) {
1764 if (! force_reset
&& ! force_hard_reset
) {
1765 SMSD_Log(DEBUG_INFO
, Config
, "Already hit %d errors", errors
);
1767 SMSD_LogError(DEBUG_INFO
, Config
, "Terminating communication", error
);
1768 GSM_TerminateConnection(Config
->gsm
);
1770 /* Did we reach limit for errors? */
1771 if (max_failures
!= 0 && initerrors
> max_failures
) {
1772 Config
->failure
= ERR_TIMEOUT
;
1773 SMSD_Log(DEBUG_INFO
, Config
, "Reached maximal number of failures (%d), terminating", max_failures
);
1776 if (initerrors
++ > 3) {
1777 SMSD_Log(DEBUG_INFO
, Config
, "Going to 30 seconds sleep because of too much connection errors");
1779 for (i
= 0; i
< 60; i
++) {
1780 if (Config
->shutdown
)
1785 SMSD_Log(DEBUG_INFO
, Config
, "Starting phone communication...");
1786 error
= GSM_InitConnection_Log(Config
->gsm
, 2, SMSD_Log_Function
, Config
);
1788 if (error
!= ERR_NONE
&& Config
->RunOnFailure
!= NULL
) {
1789 SMSD_RunOn(Config
->RunOnFailure
, NULL
, Config
, "INIT");
1793 if (Config
->checksecurity
&& !SMSD_CheckSecurity(Config
)) {
1798 GSM_SetSendSMSStatusCallback(Config
->gsm
, SMSD_SendSMSStatusCallback
, Config
);
1799 /* On first start we need to initialize some variables */
1801 if (GSM_GetIMEI(Config
->gsm
, Config
->Status
->IMEI
) != ERR_NONE
) {
1805 error
= Config
->Service
->InitAfterConnect(Config
);
1806 if (error
!=ERR_NONE
) {
1807 if (Config
->RunOnFailure
!= NULL
) {
1808 SMSD_RunOn(Config
->RunOnFailure
, NULL
, Config
, "INIT");
1810 SMSD_Terminate(Config
, "Post initialisation failed, stopping Gammu smsd", error
, TRUE
, -1);
1811 goto done_connected
;
1813 GSM_SetFastSMSSending(Config
->gsm
, TRUE
);
1815 first_start
= FALSE
;
1820 if (initerrors
> 3 || force_reset
) {
1821 error
= GSM_Reset(Config
->gsm
, FALSE
); /* soft reset */
1822 SMSD_LogError(DEBUG_INFO
, Config
, "Soft reset return code", error
);
1823 lastreset
= time(NULL
);
1825 force_reset
= FALSE
;
1827 if (force_hard_reset
) {
1828 error
= GSM_Reset(Config
->gsm
, TRUE
); /* hard reset */
1829 SMSD_LogError(DEBUG_INFO
, Config
, "Hard reset return code", error
);
1830 lasthardreset
= time(NULL
);
1832 force_hard_reset
= FALSE
;
1835 case ERR_DEVICEOPENERROR
:
1836 SMSD_Terminate(Config
, "Can't open device",
1840 SMSD_LogError(DEBUG_INFO
, Config
, "Error at init connection", error
);
1847 /* Should we receive? */
1848 if (Config
->enable_receive
&& ((difftime(time(NULL
), lastreceive
) >= Config
->receivefrequency
) || (Config
->SendingSMSStatus
!= ERR_NONE
))) {
1849 lastreceive
= time(NULL
);
1851 /* Do we need to check security? */
1852 if (Config
->checksecurity
&& !SMSD_CheckSecurity(Config
)) {
1862 /* read all incoming SMS */
1863 if (!SMSD_CheckSMSStatus(Config
)) {
1873 /* time for preventive reset */
1874 current_time
= time(NULL
);
1875 if (Config
->resetfrequency
> 0 && difftime(current_time
, lastreset
) >= Config
->resetfrequency
) {
1879 if (Config
->hardresetfrequency
> 0 && difftime(current_time
, lasthardreset
) >= Config
->hardresetfrequency
) {
1880 force_hard_reset
= TRUE
;
1884 /* Send any queued messages */
1885 current_time
= time(NULL
);
1886 if (Config
->enable_send
&& (difftime(current_time
, lastnothingsent
) >= Config
->commtimeout
)) {
1887 error
= SMSD_SendSMS(Config
);
1888 if (error
== ERR_EMPTY
) {
1889 lastnothingsent
= current_time
;
1891 /* We don't care about other errors here, they are handled in SMSD_SendSMS */
1894 /* Refresh phone status in shared memory and in service */
1895 current_time
= time(NULL
);
1896 if ((Config
->statusfrequency
> 0) && (difftime(current_time
, laststatus
) >= Config
->statusfrequency
)) {
1897 SMSD_PhoneStatus(Config
);
1898 laststatus
= current_time
;
1899 Config
->Service
->RefreshPhoneStatus(Config
);
1902 /* Sleep some time before another loop */
1903 current_time
= time(NULL
);
1904 if (Config
->loopsleep
<= 1) {
1906 } else if (difftime(current_time
, lastloop
) < Config
->loopsleep
) {
1907 sleep(Config
->loopsleep
- difftime(current_time
, lastloop
));
1910 Config
->Service
->Free(Config
);
1913 /* Free shared memory */
1914 error
= SMSD_FreeSharedMemory(Config
, TRUE
);
1915 if (error
!= ERR_NONE
) {
1919 GSM_SetFastSMSSending(Config
->gsm
,FALSE
);
1921 SMSD_Terminate(Config
, "Stopping Gammu smsd", ERR_NONE
, FALSE
, 0);
1922 return Config
->failure
;
1926 * Function to inject message to service backend.
1928 GSM_Error
SMSD_InjectSMS(GSM_SMSDConfig
*Config
, GSM_MultiSMSMessage
*sms
, char *NewID
)
1932 /* Initialize service */
1933 error
= SMSD_Init(Config
);
1934 if (error
!= ERR_NONE
) {
1938 /* Store message in outbox */
1939 error
= Config
->Service
->CreateOutboxSMS(sms
, Config
, NewID
);
1944 * Returns current status of SMSD, either from shared memory segment or
1945 * from process memory if SMSD is running in same process.
1947 GSM_Error
SMSD_GetStatus(GSM_SMSDConfig
*Config
, GSM_SMSDStatus
*status
)
1950 /* Check for local instance */
1951 if (Config
->running
) {
1952 memcpy(status
, Config
->Status
, sizeof(GSM_SMSDStatus
));
1956 /* Init shared memory */
1957 error
= SMSD_InitSharedMemory(Config
, FALSE
);
1958 if (error
!= ERR_NONE
) {
1962 /* Copy data from shared memory */
1963 memcpy(status
, Config
->Status
, sizeof(GSM_SMSDStatus
));
1965 /* Free shared memory */
1966 error
= SMSD_FreeSharedMemory(Config
, FALSE
);
1967 if (error
!= ERR_NONE
) {
1973 GSM_Error
SMSD_NoneFunction(void)
1978 GSM_Error
SMSD_EmptyFunction(void)
1983 GSM_Error
SMSD_NotImplementedFunction(void)
1985 return ERR_NOTIMPLEMENTED
;
1988 GSM_Error
SMSD_NotSupportedFunction(void)
1990 return ERR_NOTSUPPORTED
;
1992 /* How should editor hadle tabs in this file? Add editor commands here.
1993 * vim: noexpandtab sw=8 ts=8 sts=8: