summaryrefslogtreecommitdiffabout
path: root/gammu/emb/gammu/smsd/smsdcore.c
Side-by-side diff
Diffstat (limited to 'gammu/emb/gammu/smsd/smsdcore.c') (more/less context) (ignore whitespace changes)
-rw-r--r--gammu/emb/gammu/smsd/smsdcore.c507
1 files changed, 507 insertions, 0 deletions
diff --git a/gammu/emb/gammu/smsd/smsdcore.c b/gammu/emb/gammu/smsd/smsdcore.c
new file mode 100644
index 0000000..fbc55d3
--- a/dev/null
+++ b/gammu/emb/gammu/smsd/smsdcore.c
@@ -0,0 +1,507 @@
+/* (c) 2002-2003 by Marcin Wiacek and Joergen Thomsen */
+
+#include <string.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <time.h>
+
+#include "../../common/misc/coding/coding.h"
+#include "../gammu.h"
+#include "smsdcore.h"
+#include "s_files.h"
+#ifdef HAVE_MYSQL_MYSQL_H
+# include "s_mysql.h"
+#endif
+
+FILE *smsd_log_file = NULL;
+static GSM_Error SendingSMSStatus;
+static void SMSSendingSMSStatus (char *Device, int status, int mr)
+{
+ dbgprintf("Incoming SMS device: \"%s\" status=%d, reference=%d\n",Device, status, mr);
+ if (status==0) {
+ SendingSMSStatus = ERR_NONE;
+ } else {
+ SendingSMSStatus = ERR_UNKNOWN;
+ }
+}
+
+void GSM_Terminate_SMSD(char *msg, int error, bool exitprogram, int rc)
+{
+ int ret = ERR_NONE;
+
+ if (s.opened) {
+ WriteSMSDLog("Terminating communication");
+ ret=GSM_TerminateConnection(&s);
+ if (ret!=ERR_NONE) {
+ printf("%s\n",print_error(error,s.di.df,s.msg));
+ if (s.opened) GSM_TerminateConnection(&s);
+ }
+ }
+ if (error != 0) {
+ WriteSMSDLog(msg, error, print_error(error,s.di.df,s.msg));
+ fprintf(stderr, msg, error, print_error(error,s.di.df,s.msg));
+ fprintf(stderr, "\n");
+ }
+ if (exitprogram) {
+ if (smsd_log_file!=NULL) fclose(smsd_log_file);
+ exit(rc);
+ }
+}
+
+#ifdef __GNUC__
+__attribute__((format(printf, 1, 2)))
+#endif
+void WriteSMSDLog(char *format, ...)
+{
+ GSM_DateTime date_time;
+ char Buffer[2000];
+ va_list argp;
+ int result;
+
+ if (smsd_log_file != NULL) {
+ va_start(argp, format);
+ result = vsprintf(Buffer,GetMsg(s.msg,format),argp);
+ va_end(argp);
+
+ GSM_GetCurrentDateTime(&date_time);
+
+ fprintf(smsd_log_file,"%s %4d/%02d/%02d %02d:%02d:%02d : %s\n",
+ DayOfWeek(date_time.Year, date_time.Month, date_time.Day),
+ date_time.Year, date_time.Month, date_time.Day,
+ date_time.Hour, date_time.Minute, date_time.Second,Buffer);
+ fflush(smsd_log_file);
+ }
+}
+
+void SMSD_ReadConfig(char *filename, GSM_SMSDConfig *Config, bool log)
+{
+ INI_Section *smsdcfgfile = NULL;
+ GSM_Config smsdcfg;
+ unsigned char *str;
+ static unsigned char emptyPath[1] = "\0";
+
+ smsdcfgfile=INI_ReadFile(filename, false);
+ if (smsdcfgfile==NULL) {
+ fprintf(stderr,"Can't find file \"%s\"\n",filename);
+ exit(-1);
+ }
+
+ Config->logfilename=INI_GetValue(smsdcfgfile, "smsd", "logfile", false);
+ if (Config->logfilename != NULL) {
+ smsd_log_file=fopen(Config->logfilename,"ab");
+ if (smsd_log_file == NULL) {
+ fprintf(stderr,"Can't open file \"%s\"\n",Config->logfilename);
+ exit(-1);
+ }
+ fprintf(stderr,"Log filename is \"%s\"\n",Config->logfilename);
+ }
+ if (log) WriteSMSDLog("Start GAMMU smsd");
+
+ /* Include Numbers used, because we don't want create new variable */
+ Config->IncludeNumbers=INI_FindLastSectionEntry(smsdcfgfile, "gammu", false);
+ if (Config->IncludeNumbers) {
+ GSM_ReadConfig(smsdcfgfile, &smsdcfg, 0);
+ memcpy(&s.Config,&smsdcfg,sizeof(GSM_Config));
+ }
+
+ Config->PINCode=INI_GetValue(smsdcfgfile, "smsd", "PIN", false);
+ if (Config->PINCode == NULL) {
+ if (log) WriteSMSDLog("No PIN code in %s file",filename);
+ fprintf(stderr,"No PIN code in %s file\n",filename);
+ exit(-1);
+ }
+ if (log) WriteSMSDLog("PIN code is \"%s\"",Config->PINCode);
+
+ Config->user = INI_GetValue(smsdcfgfile, "smsd", "user", false);
+ if (Config->user == NULL) Config->user="root";
+ Config->password = INI_GetValue(smsdcfgfile, "smsd", "password", false);
+ if (Config->password == NULL) Config->password="";
+ Config->PC = INI_GetValue(smsdcfgfile, "smsd", "pc", false);
+ if (Config->PC == NULL) Config->PC="localhost";
+ Config->database = INI_GetValue(smsdcfgfile, "smsd", "database", false);
+ if (Config->database == NULL) Config->database="sms";
+
+ str = INI_GetValue(smsdcfgfile, "smsd", "commtimeout", false);
+ if (str) Config->commtimeout=atoi(str); else Config->commtimeout = 1;
+ str = INI_GetValue(smsdcfgfile, "smsd", "sendtimeout", false);
+ if (str) Config->sendtimeout=atoi(str); else Config->sendtimeout = 10;
+ str = INI_GetValue(smsdcfgfile, "smsd", "receivefrequency", false);
+ if (str) Config->receivefrequency=atoi(str); else Config->receivefrequency = 0;
+ if (log) WriteSMSDLog("commtimeout=%i, sendtimeout=%i, receivefrequency=%i", Config->commtimeout, Config->sendtimeout, Config->receivefrequency);
+
+ Config->deliveryreport = INI_GetValue(smsdcfgfile, "smsd", "deliveryreport", false);
+ if (Config->deliveryreport == NULL || (!mystrncasecmp(Config->deliveryreport, "log", 3) && !mystrncasecmp(Config->deliveryreport, "sms", 3))) {
+ Config->deliveryreport = "no";
+ }
+ if (log) WriteSMSDLog("deliveryreport = %s", Config->deliveryreport);
+
+ Config->inboxpath=INI_GetValue(smsdcfgfile, "smsd", "inboxpath", false);
+ if (Config->inboxpath == NULL) Config->inboxpath = emptyPath;
+
+ Config->inboxformat=INI_GetValue(smsdcfgfile, "smsd", "inboxformat", false);
+ if (Config->inboxformat == NULL || (!mystrncasecmp(Config->inboxformat, "detail", 6) && !mystrncasecmp(Config->inboxformat, "unicode", 7))) {
+ Config->inboxformat = "standard";
+ }
+ if (log) WriteSMSDLog("Inbox is \"%s\" with format \"%s\"", Config->inboxpath, Config->inboxformat);
+
+ Config->outboxpath=INI_GetValue(smsdcfgfile, "smsd", "outboxpath", false);
+ if (Config->outboxpath == NULL) Config->outboxpath = emptyPath;
+
+ Config->transmitformat=INI_GetValue(smsdcfgfile, "smsd", "transmitformat", false);
+ if (Config->transmitformat == NULL || (!mystrncasecmp(Config->transmitformat, "auto", 4) && !mystrncasecmp(Config->transmitformat, "unicode", 7))) {
+ Config->transmitformat = "7bit";
+ }
+ if (log) WriteSMSDLog("Outbox is \"%s\" with transmission format \"%s\"", Config->outboxpath, Config->transmitformat);
+
+ Config->sentsmspath=INI_GetValue(smsdcfgfile, "smsd", "sentsmspath", false);
+ if (Config->sentsmspath == NULL) Config->sentsmspath = Config->outboxpath;
+ if (log) WriteSMSDLog("Sent SMS moved to \"%s\"",Config->sentsmspath);
+
+ Config->errorsmspath=INI_GetValue(smsdcfgfile, "smsd", "errorsmspath", false);
+ if (Config->errorsmspath == NULL) Config->errorsmspath = Config->sentsmspath;
+ if (log) WriteSMSDLog("SMS with errors moved to \"%s\"",Config->errorsmspath);
+
+ Config->IncludeNumbers=INI_FindLastSectionEntry(smsdcfgfile, "include_numbers", false);
+ Config->ExcludeNumbers=INI_FindLastSectionEntry(smsdcfgfile, "exclude_numbers", false);
+ if (Config->IncludeNumbers != NULL) {
+ if (log) WriteSMSDLog("Include numbers available");
+ }
+ if (Config->ExcludeNumbers != NULL) {
+ if (Config->IncludeNumbers == NULL) {
+ if (log) WriteSMSDLog("Exclude numbers available");
+ } else {
+ if (log) WriteSMSDLog("Exclude numbers available, but IGNORED");
+ }
+ }
+
+ Config->retries = 0;
+ Config->prevSMSID[0] = 0;
+}
+
+bool SMSD_CheckSecurity(GSM_SMSDConfig *Config)
+{
+ GSM_SecurityCode SecurityCode;
+ GSM_Error error;
+
+ /* Need PIN ? */
+ error=Phone->GetSecurityStatus(&s,&SecurityCode.Type);
+ /* Unknown error */
+ if (error != ERR_NOTSUPPORTED && error != ERR_NONE) {
+ WriteSMSDLog("Error getting security status (%i)", error);
+ return false;
+ }
+ /* No supported - do not check more */
+ if (error == ERR_NOTSUPPORTED) return true;
+ /* If PIN, try to enter */
+ switch (SecurityCode.Type) {
+ case SEC_Pin:
+ WriteSMSDLog("Trying to enter PIN");
+ strcpy(SecurityCode.Code,Config->PINCode);
+ error=Phone->EnterSecurityCode(&s,SecurityCode);
+ if (error == ERR_SECURITYERROR) {
+ GSM_Terminate_SMSD("ERROR: incorrect PIN", error, true, -1);
+ }
+ if (error != ERR_NONE) {
+ WriteSMSDLog("Error entering PIN (%i)", error);
+ return false;
+ }
+ break;
+ case SEC_SecurityCode:
+ case SEC_Pin2:
+ case SEC_Puk:
+ case SEC_Puk2:
+ GSM_Terminate_SMSD("ERROR: phone requires not supported code type", 0, true, -1);
+ case SEC_None:
+ break;
+ }
+ return true;
+}
+
+bool SMSD_ReadDeleteSMS(GSM_SMSDConfig *Config, GSM_SMSDService *Service)
+{
+ bool start,process;
+ GSM_MultiSMSMessage sms;
+ unsigned char buffer[100];
+ GSM_Error error=ERR_NONE;
+ INI_Entry *e;
+ int i;
+
+ start=true;
+ while (error == ERR_NONE && !gshutdown) {
+ sms.SMS[0].Folder=0x00;
+ error=Phone->GetNextSMS(&s, &sms, start);
+ switch (error) {
+ case ERR_EMPTY:
+ break;
+ case ERR_NONE:
+ /* Not Inbox SMS - exit */
+ if (!sms.SMS[0].InboxFolder) break;
+ process=true;
+ DecodeUnicode(sms.SMS[0].Number,buffer);
+ if (Config->IncludeNumbers != NULL) {
+ e=Config->IncludeNumbers;
+ process=false;
+ while (1) {
+ if (e == NULL) break;
+ if (strcmp(buffer,e->EntryValue)==0) {
+ process=true;
+ break;
+ }
+ e = e->Prev;
+ }
+ } else if (Config->ExcludeNumbers != NULL) {
+ e=Config->ExcludeNumbers;
+ process=true;
+ while (1) {
+ if (e == NULL) break;
+ if (strcmp(buffer,e->EntryValue)==0) {
+ process=false;
+ break;
+ }
+ e = e->Prev;
+ }
+ }
+ if (process) {
+ Service->SaveInboxSMS(sms, Config);
+ } else {
+ WriteSMSDLog("Excluded %s", buffer);
+ }
+ break;
+ default:
+ WriteSMSDLog("Error getting SMS (%i)", error);
+ return false;
+ }
+ if (error == ERR_NONE && sms.SMS[0].InboxFolder) {
+ for (i=0;i<sms.Number;i++) {
+ sms.SMS[i].Folder=0;
+ error=Phone->DeleteSMS(&s,&sms.SMS[i]);
+ switch (error) {
+ case ERR_NONE:
+ case ERR_EMPTY:
+ break;
+ default:
+ WriteSMSDLog("Error deleting SMS (%i)", error);
+ return false;
+ }
+ }
+ }
+ start=false;
+ }
+ return true;
+}
+
+bool SMSD_CheckSMSStatus(GSM_SMSDConfig *Config,GSM_SMSDService *Service)
+{
+ GSM_SMSMemoryStatus SMSStatus;
+ GSM_Error error;
+
+ /* Do we have any SMS in phone ? */
+ error=Phone->GetSMSStatus(&s,&SMSStatus);
+ if (error != ERR_NONE) {
+ WriteSMSDLog("Error getting SMS status (%i)", error);
+ return false;
+ }
+ /* Yes. We have SMS in phone */
+ if (SMSStatus.SIMUsed+SMSStatus.PhoneUsed != 0) {
+ return SMSD_ReadDeleteSMS(Config,Service);
+ }
+ return true;
+}
+
+bool SMSD_SendSMS(GSM_SMSDConfig *Config,GSM_SMSDService *Service)
+{
+ GSM_MultiSMSMessage sms;
+ GSM_DateTime Date;
+ GSM_Error error;
+ unsigned int i, j, z;
+
+ error = Service->FindOutboxSMS(&sms, Config, Config->SMSID);
+
+ if (error == ERR_EMPTY || error == ERR_NOTSUPPORTED) {
+ /* No outbox sms - wait few seconds and escape */
+ for (j=0;j<Config->commtimeout && !gshutdown;j++) {
+ GSM_GetCurrentDateTime (&Date);
+ i=Date.Second;
+ while (i==Date.Second && !gshutdown) {
+ my_sleep(10);
+ GSM_GetCurrentDateTime(&Date);
+ }
+ }
+ return true;
+ }
+ if (error != ERR_NONE) {
+ /* Unknown error - escape */
+ WriteSMSDLog("Error in outbox on %s", Config->SMSID);
+ for (i=0;i<sms.Number;i++) {
+ Service->AddSentSMSInfo(&sms, Config, Config->SMSID, i+1, false);
+ }
+ Service->MoveSMS(&sms,Config, Config->SMSID, true,false);
+ return false;
+ }
+ if (!gshutdown) {
+ if (strcmp(Config->prevSMSID, Config->SMSID) == 0) {
+ Config->retries++;
+ if (Config->retries > MAX_RETRIES) {
+ Config->retries = 0;
+ strcpy(Config->prevSMSID, "");
+ WriteSMSDLog("Moved to errorbox: %s", Config->SMSID);
+ for (i=0;i<sms.Number;i++) {
+ Service->AddSentSMSInfo(&sms, Config, Config->SMSID, i+1, false);
+ }
+ Service->MoveSMS(&sms,Config, Config->SMSID, true,false);
+ return false;
+ }
+ } else {
+ Config->retries = 0;
+ strcpy(Config->prevSMSID, Config->SMSID);
+ }
+ for (i=0;i<sms.Number;i++) {
+ if (strcmp(Config->deliveryreport, "no") != 0) sms.SMS[i].PDU = SMS_Status_Report;
+ error=Phone->SendSMS(&s, &sms.SMS[i]);
+ if (error!=ERR_NONE) {
+ WriteSMSDLog("Error sending SMS %s (%i): %s", Config->SMSID, error,print_error(error,s.di.df,s.msg));
+ return false;
+ }
+ j=0;
+ SendingSMSStatus = ERR_TIMEOUT;
+ while (!gshutdown) {
+ GSM_GetCurrentDateTime (&Date);
+ z=Date.Second;
+ while (z==Date.Second) {
+ my_sleep(10);
+ GSM_GetCurrentDateTime(&Date);
+ GSM_ReadDevice(&s,true);
+ if (SendingSMSStatus != ERR_TIMEOUT) break;
+ }
+ if (SendingSMSStatus != ERR_TIMEOUT) break;
+ j++;
+ if (j>Config->sendtimeout) break;
+ }
+ if (SendingSMSStatus != ERR_NONE) {
+ WriteSMSDLog("Error getting send status of %s (%i): %s", Config->SMSID, SendingSMSStatus,print_error(SendingSMSStatus,s.di.df,s.msg));
+ return false;
+ }
+ error = Service->AddSentSMSInfo(&sms, Config, Config->SMSID, i+1, true);
+ if (error!=ERR_NONE) {
+ return false;
+ }
+ }
+ while ((int)i<sms.Number-1) {
+ Service->AddSentSMSInfo(&sms, Config, Config->SMSID, i+1, false);
+ i++;
+ }
+ strcpy(Config->prevSMSID, "");
+ if (Service->MoveSMS(&sms,Config, Config->SMSID, false, true) != ERR_NONE) {
+ Service->MoveSMS(&sms,Config, Config->SMSID, true, false);
+ }
+ }
+ return true;
+}
+
+void SMSDaemon(int argc, char *argv[])
+{
+ int errors = 255, initerrors=0;
+ GSM_SMSDService *Service;
+ GSM_Error error;
+ time_t time1;
+ GSM_SMSDConfig Config;
+
+ if (!strcmp(argv[2],"FILES")) {
+ Service = &SMSDFiles;
+#ifdef HAVE_MYSQL_MYSQL_H
+ } else if (!strcmp(argv[2],"MYSQL")) {
+ Service = &SMSDMySQL;
+#endif
+ } else {
+ fprintf(stderr,"Unknown service type (\"%s\")\n",argv[2]);
+ exit(-1);
+ }
+
+ SMSD_ReadConfig(argv[3], &Config, true);
+
+ error = Service->Init(&Config);
+ if (error!=ERR_NONE) {
+ GSM_Terminate_SMSD("Stop GAMMU smsd (%i)", error, true, -1);
+ }
+
+ signal(SIGINT, interrupt);
+ signal(SIGTERM, interrupt);
+ fprintf(stderr,"Press Ctrl+C to stop the program ...\n");
+
+ time1 = time(NULL);
+ SendingSMSStatus = ERR_UNKNOWN;
+
+ while (!gshutdown) {
+ /* There were errors in communication - try to recover */
+ if (errors > 2) {
+ if (errors != 255) {
+ WriteSMSDLog("Terminating communication (%i,%i)", error, errors);
+ error=GSM_TerminateConnection(&s);
+ }
+ if (initerrors++ > 3) my_sleep(30000);
+ WriteSMSDLog("Starting communication");
+ error=GSM_InitConnection(&s,2);
+ switch (error) {
+ case ERR_NONE:
+ s.User.SendSMSStatus = SMSSendingSMSStatus;
+ Phone = s.Phone.Functions;
+ errors = 0;
+ /* Marcin Wiacek: FIXME. To check */
+// di = s.di;
+ break;
+ case ERR_DEVICEOPENERROR:
+ GSM_Terminate_SMSD("Can't open device (%i)", error, true, -1);
+ default:
+ WriteSMSDLog("Error at init connection (%i)", error);
+ errors = 250;
+ }
+ continue;
+ }
+ if ((difftime(time(NULL), time1) >= Config.receivefrequency) || (SendingSMSStatus != ERR_NONE)) {
+ time1 = time(NULL);
+
+ if (!SMSD_CheckSecurity(&Config)) {
+ errors++;
+ initerrors++;
+ continue;
+ } else errors=0;
+
+ initerrors = 0;
+
+ if (!SMSD_CheckSMSStatus(&Config,Service)) {
+ errors++;
+ continue;
+ } else errors=0;
+ }
+ if (!SMSD_SendSMS(&Config,Service)) continue;
+ }
+ GSM_Terminate_SMSD("Stop GAMMU smsd", 0, false, 0);
+}
+
+GSM_Error SMSDaemonSendSMS(char *service, char *filename, GSM_MultiSMSMessage *sms)
+{
+ GSM_SMSDService *Service;
+ GSM_SMSDConfig Config;
+
+ if (!strcmp(service,"FILES")) {
+ Service = &SMSDFiles;
+#ifdef HAVE_MYSQL_MYSQL_H
+ } else if (!strcmp(service,"MYSQL")) {
+ Service = &SMSDMySQL;
+#endif
+ } else {
+ fprintf(stderr,"Unknown service type (\"%s\")\n",service);
+ exit(-1);
+ }
+
+ SMSD_ReadConfig(filename, &Config, false);
+
+ error = Service->Init(&Config);
+ if (error!=ERR_NONE) return ERR_UNKNOWN;
+
+ return Service->CreateOutboxSMS(sms,&Config);
+}
+
+/* How should editor hadle tabs in this file? Add editor commands here.
+ * vim: noexpandtab sw=8 ts=8 sts=8:
+ */