Translation update done using Pootle.
[gammu.git] / smsd / core.c
blob76607ed0a8a6ee2235d4e452ec537b378b7518d6
1 /* Copyright (c) 2002-2004 by Marcin Wiacek and Joergen Thomsen */
2 /* Copyright (c) 2009 - 2011 Michal Cihar <michal@cihar.com> */
4 #include <string.h>
5 #include <signal.h>
6 #include <time.h>
7 #include <assert.h>
8 #ifndef WIN32
9 #include <sys/types.h>
10 #include <sys/wait.h>
11 #endif
12 #include <gammu-config.h>
13 #ifdef HAVE_SYSLOG
14 #include <syslog.h>
15 #endif
16 #include <stdarg.h>
17 #include <stdlib.h>
19 #include <gammu-smsd.h>
21 #ifdef HAVE_UNISTD_H
22 #include <unistd.h>
23 #endif
25 #ifdef HAVE_DUP_IO_H
26 #include <io.h>
27 #endif
29 #ifdef HAVE_SHM
30 #include <sys/types.h>
31 #include <sys/ipc.h>
32 #include <sys/shm.h>
33 #include <sys/stat.h>
34 #include <limits.h>
35 #include <stdlib.h>
36 #endif
38 #include <ctype.h>
39 #include <errno.h>
41 /* Some systems let waitpid(2) tell callers about stopped children. */
42 #if !defined (WCONTINUED)
43 # define WCONTINUED 0
44 #endif
45 #if !defined (WIFCONTINUED)
46 # define WIFCONTINUED(s) (0)
47 #endif
49 #include "core.h"
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"
54 #endif
56 #ifdef HAVE_WINDOWS_EVENT_LOG
57 #include "log-event.h"
58 #endif
60 #include "../helper/string.h"
62 #ifndef PATH_MAX
63 #ifdef MAX_PATH
64 #define PATH_MAX (MAX_PATH)
65 #else
66 #define PATH_MAX (4069)
67 #endif
68 #endif
70 const char smsd_name[] = "gammu-smsd";
72 /**
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");
82 return ERR_UNKNOWN;
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");
87 return ERR_UNKNOWN;
89 return ERR_NONE;
92 /**
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;
101 return ERR_NONE;
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,
113 status,
114 mr);
115 /* Remember message reference */
116 Config->TPMR = mr;
117 /* Was message sent okay? */
118 if (status == 0) {
119 Config->SendingSMSStatus = ERR_NONE;
120 } else {
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;
135 break;
136 #endif
137 case SMSD_LOG_FILE:
138 if (Config->log_handle != NULL) {
139 fclose(Config->log_handle);
140 Config->log_handle = NULL;
142 break;
143 default:
144 break;
146 Config->log_type = SMSD_LOG_NONE;
150 * Logs current errno (or equivalent) details.
152 void SMSD_LogErrno(GSM_SMSDConfig *Config, const char *message)
154 #ifdef WIN32
155 char *lpMsgBuf;
157 FormatMessage(
158 FORMAT_MESSAGE_ALLOCATE_BUFFER |
159 FORMAT_MESSAGE_FROM_SYSTEM |
160 FORMAT_MESSAGE_IGNORE_INSERTS,
161 NULL,
162 GetLastError(),
163 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */
164 (LPTSTR) &lpMsgBuf,
166 NULL
168 SMSD_Log(DEBUG_ERROR, Config, "%s, Error %d: %s\n", message, (int)GetLastError(), lpMsgBuf);
170 LocalFree(lpMsgBuf);
171 #else
172 SMSD_Log(DEBUG_ERROR, Config, "%s, Error %d: %s\n", message, errno, strerror(errno));
173 #endif
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])",
182 message,
183 GSM_ErrorString(error),
184 GSM_ErrorName(error),
185 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? */
218 if (exitprogram) {
219 if (rc == 0) {
220 Config->running = FALSE;
221 SMSD_CloseLog(Config);
223 if (Config->exit_on_failure) {
224 exit(rc);
225 } else if (error != ERR_NONE) {
226 Config->failure = error;
231 GSM_Error SMSD_Init(GSM_SMSDConfig *Config) {
232 GSM_Error error;
234 if (Config->connected) return ERR_NONE;
236 error = Config->Service->Init(Config);
237 if (error == ERR_NONE) {
238 Config->connected = TRUE;
241 return error;
244 PRINTF_STYLE(3, 4)
245 void SMSD_Log(SMSD_DebugLevel level, GSM_SMSDConfig *Config, const char *format, ...)
247 GSM_DateTime date_time;
248 char Buffer[65535];
249 va_list argp;
250 #ifdef HAVE_SYSLOG
251 int priority;
252 #endif
254 va_start(argp, format);
255 vsprintf(Buffer,format, argp);
256 va_end(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);
262 #endif
263 break;
264 case SMSD_LOG_SYSLOG:
265 #ifdef HAVE_SYSLOG
266 switch (level) {
267 case -1:
268 priority = LOG_ERR;
269 break;
270 case 0:
271 priority = LOG_NOTICE;
272 break;
273 case 1:
274 priority = LOG_INFO;
275 break;
276 default:
277 priority = LOG_DEBUG;
278 break;
280 syslog(priority, "%s", Buffer);
281 #endif
282 break;
283 case SMSD_LOG_FILE:
284 if (level != DEBUG_ERROR &&
285 level != DEBUG_INFO &&
286 (level & Config->debug_level) == 0) {
287 return;
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);
298 #ifdef HAVE_GETPID
299 fprintf(Config->log_handle, "%s[%ld]: ", Config->program_name, (long)getpid());
300 #else
301 fprintf(Config->log_handle, "%s: ", Config->program_name);
302 #endif
303 fprintf(Config->log_handle,"%s\n",Buffer);
304 fflush(Config->log_handle);
305 break;
306 case SMSD_LOG_NONE:
307 break;
310 if (Config->use_stderr && level == -1) {
311 #ifdef HAVE_GETPID
312 fprintf(stderr, "%s[%ld]: ", Config->program_name, (long)getpid());
313 #else
314 fprintf(stderr, "%s: ", Config->program_name);
315 #endif
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;
326 size_t pos;
327 size_t newsize;
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;
333 return;
336 /* Find out current position in the buffer */
337 if (Config->gammu_log_buffer == NULL) {
338 pos = 0;
339 } else {
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) {
348 newsize += 50;
349 Config->gammu_log_buffer = realloc(Config->gammu_log_buffer, newsize);
350 if (Config->gammu_log_buffer == NULL) {
351 return;
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;
373 Config->gsm = NULL;
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;
385 /* Prepare lists */
386 GSM_StringArray_New(&(Config->IncludeNumbersList));
387 GSM_StringArray_New(&(Config->ExcludeNumbersList));
388 GSM_StringArray_New(&(Config->IncludeSMSCList));
389 GSM_StringArray_New(&(Config->ExcludeSMSCList));
391 if (name == NULL) {
392 Config->program_name = smsd_name;
393 } else {
394 Config->program_name = name;
397 return Config;
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);
420 #else
421 SMSD_Log(DEBUG_ERROR, Config, "SQL service was not compiled in!");
422 return ERR_DISABLED;
423 #endif
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) {
427 #ifdef LIBDBI_FOUND
428 Config->Service = &SMSDSQL;
429 Config->driver = INI_GetValue(Config->smsdcfgfile, "smsd", "driver", FALSE);
430 #else
431 SMSD_Log(DEBUG_ERROR, Config, "DBI service was not compiled in!");
432 return ERR_DISABLED;
433 #endif
434 } else if (strcasecmp(Config->ServiceName, "MYSQL") == 0) {
435 #ifdef HAVE_MYSQL_MYSQL_H
436 Config->Service = &SMSDSQL;
437 Config->driver = "native_mysql";
438 #else
439 SMSD_Log(DEBUG_ERROR, Config, "MYSQL service was not compiled in!");
440 return ERR_DISABLED;
441 #endif
442 } else if (strcasecmp(Config->ServiceName, "PGSQL") == 0) {
443 #ifdef HAVE_POSTGRESQL_LIBPQ_FE_H
444 Config->Service = &SMSDSQL;
445 Config->driver = "native_pgsql";
446 #else
447 SMSD_Log(DEBUG_ERROR, Config, "PGSQL service was not compiled in!");
448 return ERR_DISABLED;
449 #endif
451 } else {
452 SMSD_Log(DEBUG_ERROR, Config, "Unknown SMSD service type: \"%s\"", Config->ServiceName);
453 return ERR_UNCONFIGURED;
455 return ERR_NONE;
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);
482 free(Config);
486 * Loads list of numbers from defined config file section.
488 GSM_Error SMSD_LoadIniNumbersList(GSM_SMSDConfig *Config, GSM_StringArray *Array, const char *section)
490 INI_Entry *e;
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;
498 return ERR_NONE;
502 * Loads lines from file defined by configuration key.
504 GSM_Error SMSD_LoadNumbersFile(GSM_SMSDConfig *Config, GSM_StringArray *Array, const char *configkey)
506 size_t len;
507 char *listfilename;
508 FILE *listfd;
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])) {
522 buffer[len - 1] = 0;
523 len--;
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;
532 fclose(listfd);
534 return ERR_NONE;
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)
545 int fd;
546 #ifdef HAVE_SYSLOG
547 int facility;
548 #endif
550 /* No logging configured */
551 if (Config->logfilename == NULL) {
552 return ERR_NONE;
555 if (!uselog) {
556 Config->log_type = SMSD_LOG_FILE;
557 Config->use_stderr = FALSE;
558 fd = dup(1);
559 if (fd < 0) {
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;
569 #endif
570 #ifdef HAVE_SYSLOG
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")) {
577 facility = LOG_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;
594 } else {
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;
601 #endif
602 } else {
603 Config->log_type = SMSD_LOG_FILE;
604 if (strcmp(Config->logfilename, "stderr") == 0) {
605 fd = dup(2);
606 if (fd < 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) {
612 fd = dup(1);
613 if (fd < 0) {
614 return ERR_CANTOPENFILE;
616 Config->log_handle = fdopen(fd, "a");
617 Config->use_stderr = FALSE;
618 } else {
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);
628 return ERR_NONE;
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)
636 GSM_Config smsdcfg;
637 GSM_Config *gammucfg;
638 unsigned char *str;
639 GSM_Error error;
640 #ifdef HAVE_SHM
641 char fullpath[PATH_MAX + 1];
642 #endif
643 #ifdef WIN32
644 size_t i;
645 size_t len;
646 char config_name[MAX_PATH];
647 #endif
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;
671 #ifdef HAVE_SHM
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);
678 #endif
679 #ifdef WIN32
680 if (GetFullPathName(filename, sizeof(config_name), config_name, NULL) == 0) {
681 return FALSE;
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] = '_';
691 #endif
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);
697 } else {
698 fprintf(stderr, "Can't find file \"%s\"\n",filename);
700 return ERR_CANTOPENFILE;
703 str = INI_GetValue(Config->smsdcfgfile, "smsd", "debuglevel", FALSE);
704 if (str) {
705 Config->debug_level = atoi(str);
706 } else {
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) {
715 return error;
718 Config->ServiceName = INI_GetValue(Config->smsdcfgfile, "smsd", "service", FALSE);
720 /* Get service object */
721 error = SMSGetService(Config);
722 if (error != ERR_NONE) {
723 return error;
726 SMSD_Log(DEBUG_NOTICE, Config, "Configuring Gammu SMSD...");
727 #ifdef HAVE_SHM
728 SMSD_Log(DEBUG_NOTICE, Config, "SHM token: 0x%llx (%lld)", (long long)Config->shm_key, (long long)Config->shm_key);
729 #endif
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);
751 } else {
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);
806 if (str) {
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));
815 } else {
816 Config->SMSC.Location = -1;
819 /* Clear cache */
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");
847 } else {
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");
873 } else {
874 SMSD_Log(DEBUG_INFO, Config, "Exclude smsc available, but IGNORED");
878 Config->retries = 0;
879 Config->prevSMSID[0] = 0;
880 Config->relativevalidity = -1;
881 Config->Status = NULL;
882 Config->IncompleteMessageID = -1;
883 Config->IncompleteMessageTime = 0;
885 return ERR_NONE;
889 * Checks whether phone does not need to enter some PIN.
891 gboolean SMSD_CheckSecurity(GSM_SMSDConfig *Config)
893 GSM_SecurityCode SecurityCode;
894 GSM_Error error;
895 const char *code = NULL;
897 /* Need PIN ? */
898 error = GSM_GetSecurityStatus(Config->gsm, &SecurityCode.Type);
900 /* No supported - do not check more */
901 if (error == ERR_NOTSUPPORTED) {
902 return TRUE;
905 /* Unknown error */
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");
909 return FALSE;
912 /* If PIN, try to enter */
913 switch (SecurityCode.Type) {
914 case SEC_None:
915 return TRUE;
916 case SEC_Pin:
917 code = Config->PINCode;
918 break;
919 case SEC_Phone:
920 code = Config->PhoneCode;
921 break;
922 case SEC_Network:
923 code = Config->NetworkCode;
924 break;
925 case SEC_SecurityCode:
926 case SEC_Pin2:
927 case SEC_Puk:
928 case SEC_Puk2:
929 SMSD_Terminate(Config, "ERROR: phone requires not supported code type", ERR_UNKNOWN, TRUE, -1);
930 return FALSE;
933 /* Check if the PIN was configured */
934 if (code == NULL) {
935 SMSD_Log(DEBUG_INFO, Config, "Warning: no code in config when phone might want one!");
936 return FALSE;
939 /* Enter the PIN */
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);
945 return FALSE;
947 if (error != ERR_NONE) {
948 SMSD_LogError(DEBUG_ERROR, Config, "Error entering PIN", error);
949 return FALSE;
951 return TRUE;
955 * Prepares a command line for RunOn() function to execute user command.
957 char *SMSD_RunOnCommand(const char *locations, const char *command)
959 char *result;
960 int len;
962 assert(command != NULL);
964 if (locations == NULL) {
965 result = strdup(command);
966 assert(result != NULL);
967 return result;
970 len = strlen(locations) + strlen(command) + 4;
971 result = (char *)malloc(len);
972 assert(result != NULL);
974 snprintf(result, len, "%s %s", command, locations);
975 return result;
978 #ifdef WIN32
979 #define setenv(var, value, force) SetEnvironmentVariable(var, value)
980 #endif
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];
989 int i;
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);
1020 break;
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);
1031 break;
1032 default:
1033 /* We ignore others for now */
1034 break;
1037 } else {
1038 setenv("DECODED_PARTS", "0", 1);
1040 GSM_FreeMultiPartSMSInfo(&SMSInfo);
1043 #ifdef WIN32
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)
1052 BOOL ret;
1053 STARTUPINFO si;
1054 PROCESS_INFORMATION pi;
1055 char *cmdline;
1057 cmdline = SMSD_RunOnCommand(locations, command);
1059 /* Prepare environment */
1060 if (sms != NULL) {
1061 SMSD_RunOnReceiveEnvironment(sms, Config, locations);
1064 ZeroMemory(&si, sizeof(si));
1065 si.cb = 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*/
1080 free(cmdline);
1081 if (! ret) {
1082 SMSD_LogErrno(Config, "CreateProcess failed");
1083 } else {
1084 /* We don't need handles at all */
1085 CloseHandle(pi.hProcess);
1086 CloseHandle(pi.hThread);
1088 return ret;
1090 #else
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)
1099 int pid;
1100 int i;
1101 pid_t w;
1102 int status;
1103 char *cmdline;
1105 pid = fork();
1107 if (pid == -1) {
1108 SMSD_LogErrno(Config, "Error spawning new process");
1109 return FALSE;
1112 if (pid != 0) {
1113 /* We are the parent, wait for child */
1114 i = 0;
1115 do {
1116 w = waitpid(pid, &status, WUNTRACED | WCONTINUED);
1117 if (w == -1) {
1118 SMSD_Log(DEBUG_INFO, Config, "Failed to wait for process");
1119 return FALSE;
1122 if (WIFEXITED(status)) {
1123 if (WEXITSTATUS(status) == 0) {
1124 SMSD_Log(DEBUG_INFO, Config, "Process finished successfully");
1125 } else {
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));
1131 return FALSE;
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");
1137 usleep(100000);
1139 if (i++ > 1200) {
1140 SMSD_Log(DEBUG_INFO, Config, "Waited two minutes for child process, giving up");
1141 return TRUE;
1143 } while (!WIFEXITED(status) && !WIFSIGNALED(status));
1145 return TRUE;
1148 /* we are the child */
1150 /* Prepare environment */
1151 if (sms != NULL) {
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++) {
1161 close(i);
1164 /* Run the program */
1165 status = system(cmdline);
1167 /* Propagate error code */
1168 if (WIFEXITED(status)) {
1169 exit(WEXITSTATUS(status));
1170 } else {
1171 exit(127);
1174 #endif
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);
1184 return TRUE;
1186 return FALSE;
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);
1190 return FALSE;
1192 return TRUE;
1195 return TRUE;
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);
1206 return TRUE;
1208 return FALSE;
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);
1212 return FALSE;
1214 return TRUE;
1217 return TRUE;
1221 * Performs checks whether given message is valid to be received by SMSD.
1223 gboolean SMSD_ValidMessage(GSM_SMSDConfig *Config, GSM_MultiSMSMessage *sms)
1225 char buffer[100];
1227 /* Not Inbox SMS - exit */
1228 if (!sms->SMS[0].InboxFolder) {
1229 return FALSE;
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);
1235 return FALSE;
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);
1241 return FALSE;
1243 /* Finally process the message */
1244 SMSD_Log(DEBUG_NOTICE, Config, "Received message from: %s", buffer);
1245 return TRUE;
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 */
1267 free(locations);
1268 return error;
1272 * Checks whether to process current (possibly) multipart message.
1274 gboolean SMSD_CheckMultipart(GSM_SMSDConfig *Config, GSM_MultiSMSMessage *MultiSMS)
1276 gboolean same_id;
1277 int current_id;
1279 /* Does the message have UDH (is multipart)? */
1280 if (MultiSMS->SMS[0].UDH.Type == UDH_NoUDH || MultiSMS->SMS[0].UDH.AllParts == -1) {
1281 return TRUE;
1284 /* Grab current id */
1285 if (MultiSMS->SMS[0].UDH.ID16bit != -1) {
1286 current_id = MultiSMS->SMS[0].UDH.ID16bit;
1287 } else {
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);
1294 /* Some logging */
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) {
1300 goto success;
1303 /* Have we seen this message recently? */
1304 if (same_id) {
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;
1309 } else {
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));
1313 return FALSE;
1315 } else {
1316 if (Config->IncompleteMessageTime == 0) {
1317 if (MultiSMS->SMS[0].UDH.ID16bit != -1) {
1318 Config->IncompleteMessageID = MultiSMS->SMS[0].UDH.ID16bit;
1319 } else {
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);
1325 return FALSE;
1326 } else {
1327 SMSD_Log(DEBUG_INFO, Config, "Incomplete multipart message 0x%02X, but waiting for other one",
1328 Config->IncompleteMessageID);
1329 return FALSE;
1333 success:
1334 /* Clean multipart wait flag */
1335 if (same_id) {
1336 Config->IncompleteMessageTime = 0;
1337 Config->IncompleteMessageID = -1;
1339 return TRUE;
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)
1349 gboolean start;
1350 GSM_MultiSMSMessage sms;
1351 GSM_MultiSMSMessage **GetSMSData = NULL, **SortedSMS;
1352 int allocated = 0;
1353 GSM_Error error = ERR_NONE;
1354 int GetSMSNumber = 0;
1355 int i, j;
1357 /* Read messages from phone */
1358 start=TRUE;
1359 sms.Number = 0;
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);
1364 switch (error) {
1365 case ERR_EMPTY:
1366 break;
1367 case ERR_NONE:
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");
1373 return FALSE;
1375 allocated += 20;
1377 GetSMSData[GetSMSNumber] = malloc(sizeof(GSM_MultiSMSMessage));
1379 if (GetSMSData[GetSMSNumber] == NULL) {
1380 SMSD_Log(DEBUG_ERROR, Config, "Failed to allocate memory");
1381 return FALSE;
1384 *(GetSMSData[GetSMSNumber]) = sms;
1385 GetSMSNumber++;
1386 GetSMSData[GetSMSNumber] = NULL;
1388 break;
1389 default:
1390 SMSD_LogError(DEBUG_INFO, Config, "Error getting SMS", error);
1391 return FALSE;
1393 start = FALSE;
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) {
1401 return TRUE;
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;
1410 } else {
1411 /* Link messages */
1412 error = GSM_LinkSMS(GSM_GetDebug(Config->gsm), GetSMSData, SortedSMS, TRUE);
1413 if (error != ERR_NONE) return FALSE;
1415 /* Free memory */
1416 for (i = 0; GetSMSData[i] != NULL; i++) {
1417 free(GetSMSData[i]);
1418 GetSMSData[i] = NULL;
1420 free(GetSMSData);
1423 /* Process messages */
1424 for (i = 0; SortedSMS[i] != NULL; i++) {
1425 /* Check multipart message parts */
1426 if (!SMSD_CheckMultipart(Config, SortedSMS[i])) {
1427 goto cleanup;
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);
1434 return FALSE;
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]);
1441 switch (error) {
1442 case ERR_NONE:
1443 case ERR_EMPTY:
1444 break;
1445 default:
1446 SMSD_LogError(DEBUG_INFO, Config, "Error deleting SMS", error);
1447 return FALSE;
1451 cleanup:
1452 free(SortedSMS[i]);
1453 SortedSMS[i] = NULL;
1455 free(SortedSMS);
1456 return TRUE;
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;
1466 GSM_Error error;
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 */
1478 sms.Number = 0;
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);
1483 } else {
1484 SMSD_LogError(DEBUG_INFO, Config, "Error getting SMS status", error);
1485 return FALSE;
1488 /* Yes. We have SMS in phone */
1489 if (new_message) {
1490 return SMSD_ReadDeleteSMS(Config);
1493 return TRUE;
1497 * Reads status from phone to configuration.
1499 void SMSD_PhoneStatus(GSM_SMSDConfig *Config) {
1500 GSM_Error error;
1502 if (Config->checkbattery) {
1503 error = GSM_GetBatteryCharge(Config->gsm, &Config->Status->Charge);
1504 } else {
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);
1512 } else {
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;
1526 GSM_DateTime Date;
1527 GSM_Error error;
1528 unsigned int j;
1529 int i, z;
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) {
1539 /* No outbox sms */
1540 return error;
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);
1550 return error;
1553 if (Config->shutdown) {
1554 return ERR_NONE;
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);
1559 Config->retries++;
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);
1569 return ERR_UNKNOWN;
1571 } else {
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");
1598 return ERR_UNKNOWN;
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);
1617 Config->TPMR = -1;
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);
1622 Config->TPMR = -1;
1623 goto failure_unsent;
1625 j = 0;
1626 while (!Config->shutdown) {
1627 /* Update timestamp for SMS in backend */
1628 Config->Service->RefreshSendStatus(Config, Config->SMSID);
1630 GSM_GetCurrentDateTime(&Date);
1631 z = Date.Second;
1632 while (z == Date.Second) {
1633 usleep(10000);
1634 GSM_GetCurrentDateTime(&Date);
1635 GSM_ReadDevice(Config->gsm, TRUE);
1636 if (Config->SendingSMSStatus != ERR_TIMEOUT) {
1637 break;
1640 if (Config->SendingSMSStatus != ERR_TIMEOUT) {
1641 break;
1643 j++;
1644 if (j > Config->sendtimeout) {
1645 break;
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) {
1655 goto failure_sent;
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);
1664 return ERR_NONE;
1665 failure_unsent:
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);
1672 return ERR_UNKNOWN;
1673 failure_sent:
1674 if (Config->Service->MoveSMS(&sms,Config, Config->SMSID, FALSE, TRUE) != ERR_NONE) {
1675 Config->Service->MoveSMS(&sms,Config, Config->SMSID, TRUE, FALSE);
1677 return ERR_UNKNOWN;
1681 * Initializes shared memory segment, writable if asked for it.
1683 GSM_Error SMSD_InitSharedMemory(GSM_SMSDConfig *Config, gboolean writable)
1685 #ifdef HAVE_SHM
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);
1690 return ERR_UNKNOWN;
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);
1695 return ERR_UNKNOWN;
1697 if (!writable && Config->Status->Version != SMSD_SHM_VERSION) {
1698 shmdt(Config->Status);
1699 return ERR_WRONGCRC;
1701 if (writable) {
1702 SMSD_Log(DEBUG_INFO, Config, "Created POSIX RW shared memory at %p", Config->Status);
1703 } else {
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) {
1709 if (writable) {
1710 SMSD_Terminate(Config, "Failed to allocate shared memory segment!", ERR_NONE, TRUE, -1);
1711 return ERR_UNKNOWN;
1712 } else {
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) {
1719 if (writable) {
1720 SMSD_Terminate(Config, "Failed to map shared memory!", ERR_NONE, TRUE, -1);
1721 return ERR_UNKNOWN;
1722 } else {
1723 SMSD_LogErrno(Config, "Failet to map shared memory!");
1724 return ERR_NOTRUNNING;
1727 if (writable) {
1728 SMSD_Log(DEBUG_INFO, Config, "Created Windows RW shared memory at %p", Config->Status);
1729 } else {
1730 SMSD_Log(DEBUG_INFO, Config, "Mapped Windows RO shared memory at %p", Config->Status);
1732 #else
1733 if (writable) {
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);
1739 return ERR_UNKNOWN;
1741 if (writable) {
1742 SMSD_Log(DEBUG_INFO, Config, "No shared memory, using standard malloc %p", Config->Status);
1744 #endif
1745 /* Initial shared memory content */
1746 if (writable) {
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",
1750 GAMMU_VERSION,
1751 GetOS(),
1752 GetCompiler());
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;
1760 return ERR_NONE;
1764 * Frees shared memory segment, writable if asked for it.
1766 GSM_Error SMSD_FreeSharedMemory(GSM_SMSDConfig *Config, gboolean writable)
1768 #ifdef HAVE_SHM
1769 shmdt(Config->Status);
1770 if (writable) {
1771 shmctl(Config->shm_handle, IPC_RMID, NULL);
1773 #elif defined(WIN32)
1774 UnmapViewOfFile(Config->Status);
1775 CloseHandle(Config->map_handle);
1776 #else
1777 if (writable) {
1778 free(Config->Status);
1780 #endif
1781 Config->Status = NULL;
1782 return ERR_NONE;
1785 * Main loop which takes care of connection to phone and processing of
1786 * messages.
1788 GSM_Error SMSD_MainLoop(GSM_SMSDConfig *Config, gboolean exit_on_failure, int max_failures)
1790 GSM_Error error;
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;
1794 int i;
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;
1800 /* Init service */
1801 error = SMSD_Init(Config);
1802 if (error!=ERR_NONE) {
1803 SMSD_Terminate(Config, "Initialisation failed, stopping Gammu smsd", error, TRUE, -1);
1804 goto done;
1807 /* Init shared memory */
1808 error = SMSD_InitSharedMemory(Config, TRUE);
1809 if (error != ERR_NONE) {
1810 goto done;
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);
1833 break;
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)
1840 break;
1841 usleep(500000);
1844 SMSD_Log(DEBUG_INFO, Config, "Starting phone communication...");
1845 error = GSM_InitConnection_Log(Config->gsm, 2, SMSD_Log_Function, Config);
1846 /* run on error */
1847 if (error != ERR_NONE && Config->RunOnFailure != NULL) {
1848 SMSD_RunOn(Config->RunOnFailure, NULL, Config, "INIT");
1850 switch (error) {
1851 case ERR_NONE:
1852 if (Config->checksecurity && !SMSD_CheckSecurity(Config)) {
1853 errors++;
1854 initerrors++;
1855 continue;
1857 GSM_SetSendSMSStatusCallback(Config->gsm, SMSD_SendSMSStatusCallback, Config);
1858 /* On first start we need to initialize some variables */
1859 if (first_start) {
1860 if (GSM_GetIMEI(Config->gsm, Config->Status->IMEI) != ERR_NONE) {
1861 errors++;
1862 } else {
1863 errors = 0;
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;
1875 } else {
1876 errors = 0;
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);
1883 sleep(5);
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);
1890 sleep(5);
1891 force_hard_reset = FALSE;
1893 break;
1894 case ERR_DEVICEOPENERROR:
1895 SMSD_Terminate(Config, "Can't open device",
1896 error, TRUE, -1);
1897 goto done;
1898 default:
1899 SMSD_LogError(DEBUG_INFO, Config, "Error at init connection", error);
1900 errors = 250;
1901 break;
1903 continue;
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)) {
1912 errors++;
1913 initerrors++;
1914 continue;
1915 } else {
1916 errors = 0;
1919 initerrors = 0;
1921 /* read all incoming SMS */
1922 if (!SMSD_CheckSMSStatus(Config)) {
1923 errors++;
1924 continue;
1925 } else {
1926 errors = 0;
1932 /* time for preventive reset */
1933 current_time = time(NULL);
1934 if (Config->resetfrequency > 0 && difftime(current_time, lastreset) >= Config->resetfrequency) {
1935 force_reset = TRUE;
1936 continue;
1938 if (Config->hardresetfrequency > 0 && difftime(current_time, lasthardreset) >= Config->hardresetfrequency) {
1939 force_hard_reset = TRUE;
1940 continue;
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) {
1964 sleep(1);
1965 } else if (difftime(current_time, lastloop) < Config->loopsleep) {
1966 sleep(Config->loopsleep - difftime(current_time, lastloop));
1969 Config->Service->Free(Config);
1971 done_connected:
1972 /* Free shared memory */
1973 error = SMSD_FreeSharedMemory(Config, TRUE);
1974 if (error != ERR_NONE) {
1975 return error;
1978 GSM_SetFastSMSSending(Config->gsm,FALSE);
1979 done:
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)
1989 GSM_Error error;
1991 /* Initialize service */
1992 error = SMSD_Init(Config);
1993 if (error != ERR_NONE) {
1994 return error;
1997 /* Store message in outbox */
1998 error = Config->Service->CreateOutboxSMS(sms, Config, NewID);
1999 return error;
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)
2008 GSM_Error error;
2009 /* Check for local instance */
2010 if (Config->running) {
2011 memcpy(status, Config->Status, sizeof(GSM_SMSDStatus));
2012 return ERR_NONE;
2015 /* Init shared memory */
2016 error = SMSD_InitSharedMemory(Config, FALSE);
2017 if (error != ERR_NONE) {
2018 return error;
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) {
2027 return error;
2029 return ERR_NONE;
2032 GSM_Error SMSD_NoneFunction(void)
2034 return ERR_NONE;
2037 GSM_Error SMSD_EmptyFunction(void)
2039 return ERR_EMPTY;
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: