Include hack for converting sms to backup
[gammu.git] / smsd / core.c
blobb308d4209248bc62655fd4e6f091f5d73c685fa2
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;
547 /* No logging configured */
548 if (Config->logfilename == NULL) {
549 return ERR_NONE;
552 if (!uselog) {
553 Config->log_type = SMSD_LOG_FILE;
554 Config->use_stderr = FALSE;
555 fd = dup(1);
556 if (fd < 0) {
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;
566 #endif
567 #ifdef HAVE_SYSLOG
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;
572 #endif
573 } else {
574 Config->log_type = SMSD_LOG_FILE;
575 if (strcmp(Config->logfilename, "stderr") == 0) {
576 fd = dup(2);
577 if (fd < 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) {
583 fd = dup(1);
584 if (fd < 0) {
585 return ERR_CANTOPENFILE;
587 Config->log_handle = fdopen(fd, "a");
588 Config->use_stderr = FALSE;
589 } else {
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);
599 return ERR_NONE;
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)
607 GSM_Config smsdcfg;
608 GSM_Config *gammucfg;
609 unsigned char *str;
610 GSM_Error error;
611 #ifdef HAVE_SHM
612 char fullpath[PATH_MAX + 1];
613 #endif
614 #ifdef WIN32
615 size_t i;
616 size_t len;
617 char config_name[MAX_PATH];
618 #endif
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;
641 #ifdef HAVE_SHM
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);
648 #endif
649 #ifdef WIN32
650 if (GetFullPathName(filename, sizeof(config_name), config_name, NULL) == 0) {
651 return FALSE;
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] = '_';
661 #endif
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);
667 } else {
668 fprintf(stderr, "Can't find file \"%s\"\n",filename);
670 return ERR_CANTOPENFILE;
673 str = INI_GetValue(Config->smsdcfgfile, "smsd", "debuglevel", FALSE);
674 if (str) {
675 Config->debug_level = atoi(str);
676 } else {
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) {
683 return error;
686 Config->ServiceName = INI_GetValue(Config->smsdcfgfile, "smsd", "service", FALSE);
688 /* Get service object */
689 error = SMSGetService(Config);
690 if (error != ERR_NONE) {
691 return error;
694 SMSD_Log(DEBUG_NOTICE, Config, "Configuring Gammu SMSD...");
695 #ifdef HAVE_SHM
696 SMSD_Log(DEBUG_NOTICE, Config, "SHM token: 0x%llx (%lld)", (long long)Config->shm_key, (long long)Config->shm_key);
697 #endif
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);
719 } else {
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);
774 if (str) {
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));
783 } else {
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");
812 } else {
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");
838 } else {
839 SMSD_Log(DEBUG_INFO, Config, "Exclude smsc available, but IGNORED");
843 Config->retries = 0;
844 Config->prevSMSID[0] = 0;
845 Config->relativevalidity = -1;
846 Config->Status = NULL;
847 Config->IncompleteMessageID = 0;
848 Config->IncompleteMessageTime = 0;
850 return ERR_NONE;
854 * Checks whether phone does not need to enter some PIN.
856 gboolean SMSD_CheckSecurity(GSM_SMSDConfig *Config)
858 GSM_SecurityCode SecurityCode;
859 GSM_Error error;
860 const char *code = NULL;
862 /* Need PIN ? */
863 error = GSM_GetSecurityStatus(Config->gsm, &SecurityCode.Type);
865 /* No supported - do not check more */
866 if (error == ERR_NOTSUPPORTED) {
867 return TRUE;
870 /* Unknown error */
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");
874 return FALSE;
877 /* If PIN, try to enter */
878 switch (SecurityCode.Type) {
879 case SEC_None:
880 return TRUE;
881 case SEC_Pin:
882 code = Config->PINCode;
883 break;
884 case SEC_Phone:
885 code = Config->PhoneCode;
886 break;
887 case SEC_Network:
888 code = Config->NetworkCode;
889 break;
890 case SEC_SecurityCode:
891 case SEC_Pin2:
892 case SEC_Puk:
893 case SEC_Puk2:
894 SMSD_Terminate(Config, "ERROR: phone requires not supported code type", ERR_UNKNOWN, TRUE, -1);
895 return FALSE;
898 /* Check if the PIN was configured */
899 if (code == NULL) {
900 SMSD_Log(DEBUG_INFO, Config, "Warning: no code in config when phone might want one!");
901 return FALSE;
904 /* Enter the PIN */
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);
910 return FALSE;
912 if (error != ERR_NONE) {
913 SMSD_LogError(DEBUG_ERROR, Config, "Error entering PIN", error);
914 return FALSE;
916 return TRUE;
920 * Prepares a command line for RunOn() function to execute user command.
922 char *SMSD_RunOnCommand(const char *locations, const char *command)
924 char *result;
925 int len;
927 assert(command != NULL);
929 if (locations == NULL) {
930 result = strdup(command);
931 assert(result != NULL);
932 return result;
935 len = strlen(locations) + strlen(command) + 4;
936 result = (char *)malloc(len);
937 assert(result != NULL);
939 snprintf(result, len, "%s %s", command, locations);
940 return result;
943 #ifdef WIN32
944 #define setenv(var, value, force) SetEnvironmentVariable(var, value)
945 #endif
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];
954 int i;
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);
985 break;
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);
996 break;
997 default:
998 /* We ignore others for now */
999 break;
1002 } else {
1003 setenv("DECODED_PARTS", "0", 1);
1005 GSM_FreeMultiPartSMSInfo(&SMSInfo);
1008 #ifdef WIN32
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)
1017 BOOL ret;
1018 STARTUPINFO si;
1019 PROCESS_INFORMATION pi;
1020 char *cmdline;
1022 cmdline = SMSD_RunOnCommand(locations, command);
1024 /* Prepare environment */
1025 if (sms != NULL) {
1026 SMSD_RunOnReceiveEnvironment(sms, Config, locations);
1029 ZeroMemory(&si, sizeof(si));
1030 si.cb = 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*/
1045 free(cmdline);
1046 if (! ret) {
1047 SMSD_LogErrno(Config, "CreateProcess failed");
1048 } else {
1049 /* We don't need handles at all */
1050 CloseHandle(pi.hProcess);
1051 CloseHandle(pi.hThread);
1053 return ret;
1055 #else
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)
1064 int pid;
1065 int i;
1066 pid_t w;
1067 int status;
1068 char *cmdline;
1070 pid = fork();
1072 if (pid == -1) {
1073 SMSD_LogErrno(Config, "Error spawning new process");
1074 return FALSE;
1077 if (pid != 0) {
1078 /* We are the parent, wait for child */
1079 i = 0;
1080 do {
1081 w = waitpid(pid, &status, WUNTRACED | WCONTINUED);
1082 if (w == -1) {
1083 SMSD_Log(DEBUG_INFO, Config, "Failed to wait for process");
1084 return FALSE;
1087 if (WIFEXITED(status)) {
1088 if (WEXITSTATUS(status) == 0) {
1089 SMSD_Log(DEBUG_INFO, Config, "Process finished successfully");
1090 } else {
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));
1096 return FALSE;
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");
1102 usleep(100000);
1104 if (i++ > 1200) {
1105 SMSD_Log(DEBUG_INFO, Config, "Waited two minutes for child process, giving up");
1106 return TRUE;
1108 } while (!WIFEXITED(status) && !WIFSIGNALED(status));
1110 return TRUE;
1113 /* we are the child */
1115 /* Prepare environment */
1116 if (sms != NULL) {
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++) {
1126 close(i);
1129 /* Run the program */
1130 status = system(cmdline);
1132 /* Propagate error code */
1133 if (WIFEXITED(status)) {
1134 exit(WEXITSTATUS(status));
1135 } else {
1136 exit(127);
1139 #endif
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);
1149 return TRUE;
1151 return FALSE;
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);
1155 return FALSE;
1157 return TRUE;
1160 return TRUE;
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);
1171 return TRUE;
1173 return FALSE;
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);
1177 return FALSE;
1179 return TRUE;
1182 return TRUE;
1186 * Performs checks whether given message is valid to be received by SMSD.
1188 gboolean SMSD_ValidMessage(GSM_SMSDConfig *Config, GSM_MultiSMSMessage *sms)
1190 char buffer[100];
1192 /* Not Inbox SMS - exit */
1193 if (!sms->SMS[0].InboxFolder) {
1194 return FALSE;
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);
1200 return FALSE;
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);
1206 return FALSE;
1208 /* Finally process the message */
1209 SMSD_Log(DEBUG_NOTICE, Config, "Received message from: %s", buffer);
1210 return TRUE;
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 */
1232 free(locations);
1233 return error;
1237 * Checks whether to process current (possibly) multipart message.
1239 gboolean SMSD_CheckMultipart(GSM_SMSDConfig *Config, GSM_MultiSMSMessage *MultiSMS)
1241 gboolean same_id;
1243 /* Does the message have UDH (is multipart)? */
1244 if (MultiSMS->SMS[0].UDH.Type == UDH_NoUDH || MultiSMS->SMS[0].UDH.AllParts == -1) {
1245 return TRUE;
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) {
1253 goto success;
1256 /* Have we seen this message recently? */
1257 if (same_id) {
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);
1261 } else {
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));
1265 return FALSE;
1267 } else {
1268 if (Config->IncompleteMessageTime == 0) {
1269 if (MultiSMS->SMS[0].UDH.ID16bit != -1) {
1270 Config->IncompleteMessageID = MultiSMS->SMS[0].UDH.ID16bit;
1271 } else {
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);
1277 return FALSE;
1278 } else {
1279 SMSD_Log(DEBUG_INFO, Config, "Incomplete multipart message 0x%02X, but waiting for other one",
1280 Config->IncompleteMessageID);
1281 return FALSE;
1285 success:
1286 /* Clean multipart wait flag */
1287 if (same_id) {
1288 Config->IncompleteMessageTime = 0;
1290 return TRUE;
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)
1300 gboolean start;
1301 GSM_MultiSMSMessage sms;
1302 GSM_MultiSMSMessage **GetSMSData = NULL, **SortedSMS;
1303 int allocated = 0;
1304 GSM_Error error = ERR_NONE;
1305 int GetSMSNumber = 0;
1306 int i, j;
1308 /* Read messages from phone */
1309 start=TRUE;
1310 sms.Number = 0;
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);
1315 switch (error) {
1316 case ERR_EMPTY:
1317 break;
1318 case ERR_NONE:
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");
1324 return FALSE;
1326 allocated += 20;
1328 GetSMSData[GetSMSNumber] = malloc(sizeof(GSM_MultiSMSMessage));
1330 if (GetSMSData[GetSMSNumber] == NULL) {
1331 SMSD_Log(DEBUG_ERROR, Config, "Failed to allocate memory");
1332 return FALSE;
1335 *(GetSMSData[GetSMSNumber]) = sms;
1336 GetSMSNumber++;
1337 GetSMSData[GetSMSNumber] = NULL;
1339 break;
1340 default:
1341 SMSD_LogError(DEBUG_INFO, Config, "Error getting SMS", error);
1342 return FALSE;
1344 start = FALSE;
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) {
1352 return TRUE;
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;
1361 } else {
1362 /* Link messages */
1363 error = GSM_LinkSMS(GSM_GetDebug(Config->gsm), GetSMSData, SortedSMS, TRUE);
1364 if (error != ERR_NONE) return FALSE;
1366 /* Free memory */
1367 for (i = 0; GetSMSData[i] != NULL; i++) {
1368 free(GetSMSData[i]);
1369 GetSMSData[i] = NULL;
1371 free(GetSMSData);
1374 /* Process messages */
1375 for (i = 0; SortedSMS[i] != NULL; i++) {
1376 /* Check multipart message parts */
1377 if (!SMSD_CheckMultipart(Config, SortedSMS[i])) {
1378 goto cleanup;
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);
1385 return FALSE;
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]);
1392 switch (error) {
1393 case ERR_NONE:
1394 case ERR_EMPTY:
1395 break;
1396 default:
1397 SMSD_LogError(DEBUG_INFO, Config, "Error deleting SMS", error);
1398 return FALSE;
1402 cleanup:
1403 free(SortedSMS[i]);
1404 SortedSMS[i] = NULL;
1406 free(SortedSMS);
1407 return TRUE;
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;
1417 GSM_Error error;
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 */
1429 sms.Number = 0;
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);
1434 } else {
1435 SMSD_LogError(DEBUG_INFO, Config, "Error getting SMS status", error);
1436 return FALSE;
1439 /* Yes. We have SMS in phone */
1440 if (new_message) {
1441 return SMSD_ReadDeleteSMS(Config);
1444 return TRUE;
1448 * Reads status from phone to configuration.
1450 void SMSD_PhoneStatus(GSM_SMSDConfig *Config) {
1451 GSM_Error error;
1453 if (Config->checkbattery) {
1454 error = GSM_GetBatteryCharge(Config->gsm, &Config->Status->Charge);
1455 } else {
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);
1463 } else {
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;
1477 GSM_DateTime Date;
1478 GSM_Error error;
1479 unsigned int j;
1480 int i, z;
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) {
1490 /* No outbox sms */
1491 return error;
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);
1501 return error;
1504 if (Config->shutdown) {
1505 return ERR_NONE;
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);
1510 Config->retries++;
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);
1520 return ERR_UNKNOWN;
1522 } else {
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");
1539 return ERR_UNKNOWN;
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);
1558 Config->TPMR = -1;
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);
1563 Config->TPMR = -1;
1564 goto failure_unsent;
1566 j = 0;
1567 while (!Config->shutdown) {
1568 /* Update timestamp for SMS in backend */
1569 Config->Service->RefreshSendStatus(Config, Config->SMSID);
1571 GSM_GetCurrentDateTime(&Date);
1572 z = Date.Second;
1573 while (z == Date.Second) {
1574 usleep(10000);
1575 GSM_GetCurrentDateTime(&Date);
1576 GSM_ReadDevice(Config->gsm, TRUE);
1577 if (Config->SendingSMSStatus != ERR_TIMEOUT) {
1578 break;
1581 if (Config->SendingSMSStatus != ERR_TIMEOUT) {
1582 break;
1584 j++;
1585 if (j > Config->sendtimeout) {
1586 break;
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) {
1596 goto failure_sent;
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);
1605 return ERR_NONE;
1606 failure_unsent:
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);
1613 return ERR_UNKNOWN;
1614 failure_sent:
1615 if (Config->Service->MoveSMS(&sms,Config, Config->SMSID, FALSE, TRUE) != ERR_NONE) {
1616 Config->Service->MoveSMS(&sms,Config, Config->SMSID, TRUE, FALSE);
1618 return ERR_UNKNOWN;
1622 * Initializes shared memory segment, writable if asked for it.
1624 GSM_Error SMSD_InitSharedMemory(GSM_SMSDConfig *Config, gboolean writable)
1626 #ifdef HAVE_SHM
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);
1631 return ERR_UNKNOWN;
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);
1636 return ERR_UNKNOWN;
1638 if (!writable && Config->Status->Version != SMSD_SHM_VERSION) {
1639 shmdt(Config->Status);
1640 return ERR_WRONGCRC;
1642 if (writable) {
1643 SMSD_Log(DEBUG_INFO, Config, "Created POSIX RW shared memory at %p", Config->Status);
1644 } else {
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) {
1650 if (writable) {
1651 SMSD_Terminate(Config, "Failed to allocate shared memory segment!", ERR_NONE, TRUE, -1);
1652 return ERR_UNKNOWN;
1653 } else {
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) {
1660 if (writable) {
1661 SMSD_Terminate(Config, "Failed to map shared memory!", ERR_NONE, TRUE, -1);
1662 return ERR_UNKNOWN;
1663 } else {
1664 SMSD_LogErrno(Config, "Failet to map shared memory!");
1665 return ERR_NOTRUNNING;
1668 if (writable) {
1669 SMSD_Log(DEBUG_INFO, Config, "Created Windows RW shared memory at %p", Config->Status);
1670 } else {
1671 SMSD_Log(DEBUG_INFO, Config, "Mapped Windows RO shared memory at %p", Config->Status);
1673 #else
1674 if (writable) {
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);
1680 return ERR_UNKNOWN;
1682 if (writable) {
1683 SMSD_Log(DEBUG_INFO, Config, "No shared memory, using standard malloc %p", Config->Status);
1685 #endif
1686 /* Initial shared memory content */
1687 if (writable) {
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",
1691 GAMMU_VERSION,
1692 GetOS(),
1693 GetCompiler());
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;
1701 return ERR_NONE;
1705 * Frees shared memory segment, writable if asked for it.
1707 GSM_Error SMSD_FreeSharedMemory(GSM_SMSDConfig *Config, gboolean writable)
1709 #ifdef HAVE_SHM
1710 shmdt(Config->Status);
1711 if (writable) {
1712 shmctl(Config->shm_handle, IPC_RMID, NULL);
1714 #elif defined(WIN32)
1715 UnmapViewOfFile(Config->Status);
1716 CloseHandle(Config->map_handle);
1717 #else
1718 if (writable) {
1719 free(Config->Status);
1721 #endif
1722 Config->Status = NULL;
1723 return ERR_NONE;
1726 * Main loop which takes care of connection to phone and processing of
1727 * messages.
1729 GSM_Error SMSD_MainLoop(GSM_SMSDConfig *Config, gboolean exit_on_failure, int max_failures)
1731 GSM_Error error;
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;
1735 int i;
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;
1741 /* Init service */
1742 error = SMSD_Init(Config);
1743 if (error!=ERR_NONE) {
1744 SMSD_Terminate(Config, "Initialisation failed, stopping Gammu smsd", error, TRUE, -1);
1745 goto done;
1748 /* Init shared memory */
1749 error = SMSD_InitSharedMemory(Config, TRUE);
1750 if (error != ERR_NONE) {
1751 goto done;
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);
1774 break;
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)
1781 break;
1782 usleep(500000);
1785 SMSD_Log(DEBUG_INFO, Config, "Starting phone communication...");
1786 error = GSM_InitConnection_Log(Config->gsm, 2, SMSD_Log_Function, Config);
1787 /* run on error */
1788 if (error != ERR_NONE && Config->RunOnFailure != NULL) {
1789 SMSD_RunOn(Config->RunOnFailure, NULL, Config, "INIT");
1791 switch (error) {
1792 case ERR_NONE:
1793 if (Config->checksecurity && !SMSD_CheckSecurity(Config)) {
1794 errors++;
1795 initerrors++;
1796 continue;
1798 GSM_SetSendSMSStatusCallback(Config->gsm, SMSD_SendSMSStatusCallback, Config);
1799 /* On first start we need to initialize some variables */
1800 if (first_start) {
1801 if (GSM_GetIMEI(Config->gsm, Config->Status->IMEI) != ERR_NONE) {
1802 errors++;
1803 } else {
1804 errors = 0;
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;
1816 } else {
1817 errors = 0;
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);
1824 sleep(5);
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);
1831 sleep(5);
1832 force_hard_reset = FALSE;
1834 break;
1835 case ERR_DEVICEOPENERROR:
1836 SMSD_Terminate(Config, "Can't open device",
1837 error, TRUE, -1);
1838 goto done;
1839 default:
1840 SMSD_LogError(DEBUG_INFO, Config, "Error at init connection", error);
1841 errors = 250;
1842 break;
1844 continue;
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)) {
1853 errors++;
1854 initerrors++;
1855 continue;
1856 } else {
1857 errors = 0;
1860 initerrors = 0;
1862 /* read all incoming SMS */
1863 if (!SMSD_CheckSMSStatus(Config)) {
1864 errors++;
1865 continue;
1866 } else {
1867 errors = 0;
1873 /* time for preventive reset */
1874 current_time = time(NULL);
1875 if (Config->resetfrequency > 0 && difftime(current_time, lastreset) >= Config->resetfrequency) {
1876 force_reset = TRUE;
1877 continue;
1879 if (Config->hardresetfrequency > 0 && difftime(current_time, lasthardreset) >= Config->hardresetfrequency) {
1880 force_hard_reset = TRUE;
1881 continue;
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) {
1905 sleep(1);
1906 } else if (difftime(current_time, lastloop) < Config->loopsleep) {
1907 sleep(Config->loopsleep - difftime(current_time, lastloop));
1910 Config->Service->Free(Config);
1912 done_connected:
1913 /* Free shared memory */
1914 error = SMSD_FreeSharedMemory(Config, TRUE);
1915 if (error != ERR_NONE) {
1916 return error;
1919 GSM_SetFastSMSSending(Config->gsm,FALSE);
1920 done:
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)
1930 GSM_Error error;
1932 /* Initialize service */
1933 error = SMSD_Init(Config);
1934 if (error != ERR_NONE) {
1935 return error;
1938 /* Store message in outbox */
1939 error = Config->Service->CreateOutboxSMS(sms, Config, NewID);
1940 return error;
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)
1949 GSM_Error error;
1950 /* Check for local instance */
1951 if (Config->running) {
1952 memcpy(status, Config->Status, sizeof(GSM_SMSDStatus));
1953 return ERR_NONE;
1956 /* Init shared memory */
1957 error = SMSD_InitSharedMemory(Config, FALSE);
1958 if (error != ERR_NONE) {
1959 return error;
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) {
1968 return error;
1970 return ERR_NONE;
1973 GSM_Error SMSD_NoneFunction(void)
1975 return ERR_NONE;
1978 GSM_Error SMSD_EmptyFunction(void)
1980 return ERR_EMPTY;
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: