10 #include "../../common/misc/coding/coding.h"
12 FILE *smsd_log_file
= NULL
;
13 static GSM_Error SendingSMSStatus
;
15 static void SMSSendingSMSStatus (char *Device
, int status
)
17 dbgprintf("Incoming SMS device: \"%s\" status=%d\n",Device
, status
);
19 SendingSMSStatus
= GE_NONE
;
21 SendingSMSStatus
= GE_UNKNOWN
;
25 void GSM_Terminate_SMSD(char *msg
, int error
, bool exitprogram
, int rc
)
30 WriteSMSDLog("Terminating communication");
31 ret
=GSM_TerminateConnection(&s
);
33 printf("%s\n",print_error(error
,s
.di
.df
,s
.msg
));
34 if (s
.opened
) GSM_TerminateConnection(&s
);
38 WriteSMSDLog(msg
, error
, print_error(error
,s
.di
.df
,s
.msg
));
39 fprintf(stderr
, msg
, error
, print_error(error
,s
.di
.df
,s
.msg
));
40 fprintf(stderr
, "\n");
43 if (smsd_log_file
!=NULL
) fclose(smsd_log_file
);
48 void WriteSMSDLog(unsigned char *format
, ...)
50 GSM_DateTime date_time
;
55 if (smsd_log_file
!= NULL
) {
56 va_start(argp
, format
);
57 result
= vsprintf(Buffer
,GetMsg(s
.msg
,format
),argp
);
60 GSM_GetCurrentDateTime(&date_time
);
62 fprintf(smsd_log_file
,"%s %4d/%02d/%02d %02d:%02d:%02d : %s\n",
63 DayOfWeek(date_time
.Year
, date_time
.Month
, date_time
.Day
),
64 date_time
.Year
, date_time
.Month
, date_time
.Day
,
65 date_time
.Hour
, date_time
.Minute
, date_time
.Second
,Buffer
);
66 fflush(smsd_log_file
);
70 void SMSD_ReadConfig(int argc
, char *argv
[], GSM_SMSDConfig
*Config
)
72 INI_Section
*smsdcfgfile
= NULL
;
75 static unsigned char emptyPath
[1] = "\0";
77 smsdcfgfile
=INI_ReadFile(argv
[3], false);
78 if (smsdcfgfile
==NULL
) {
79 fprintf(stderr
,"Can't find file \"%s\"\n",argv
[3]);
83 Config
->logfilename
=INI_GetValue(smsdcfgfile
, "smsd", "logfile", false);
84 if (Config
->logfilename
!= NULL
) {
85 smsd_log_file
=fopen(Config
->logfilename
,"ab");
86 if (smsd_log_file
== NULL
) {
87 fprintf(stderr
,"Can't open file \"%s\"\n",Config
->logfilename
);
90 fprintf(stderr
,"Log filename is \"%s\"\n",Config
->logfilename
);
92 WriteSMSDLog("Start GAMMU smsd");
94 /* Include Numbers used, because we don't want create new variable */
95 Config
->IncludeNumbers
=INI_FindLastSectionEntry(smsdcfgfile
, "gammu", false);
96 if (Config
->IncludeNumbers
) {
97 GSM_ReadConfig(smsdcfgfile
, &smsdcfg
, 0);
98 memcpy(&s
.Config
,&smsdcfg
,sizeof(GSM_Config
));
101 Config
->PINCode
=INI_GetValue(smsdcfgfile
, "smsd", "PIN", false);
102 if (Config
->PINCode
== NULL
) {
103 WriteSMSDLog("No PIN code in %s file",argv
[3]);
104 fprintf(stderr
,"No PIN code in %s file\n",argv
[3]);
107 WriteSMSDLog("PIN code is \"%s\"",Config
->PINCode
);
109 str
= INI_GetValue(smsdcfgfile
, "smsd", "commtimeout", false);
110 if (str
) Config
->commtimeout
=atoi(str
); else Config
->commtimeout
= 1;
111 str
= INI_GetValue(smsdcfgfile
, "smsd", "sendtimeout", false);
112 if (str
) Config
->sendtimeout
=atoi(str
); else Config
->sendtimeout
= 10;
113 str
= INI_GetValue(smsdcfgfile
, "smsd", "receivefrequency", false);
114 if (str
) Config
->receivefrequency
=atoi(str
); else Config
->receivefrequency
= 0;
115 WriteSMSDLog("commtimeout=%i, sendtimeout=%i, receivefrequency=%i", Config
->commtimeout
, Config
->sendtimeout
, Config
->receivefrequency
);
117 Config
->deliveryreport
= INI_GetValue(smsdcfgfile
, "smsd", "deliveryreport", false);
118 if (Config
->deliveryreport
== NULL
|| (!mystrncasecmp(Config
->deliveryreport
, "log", 3) && !mystrncasecmp(Config
->deliveryreport
, "sms", 3))) {
119 Config
->deliveryreport
= "no";
121 WriteSMSDLog("deliveryreport = %s", Config
->deliveryreport
);
123 Config
->inboxpath
=INI_GetValue(smsdcfgfile
, "smsd", "inboxpath", false);
124 if (Config
->inboxpath
== NULL
) Config
->inboxpath
= emptyPath
;
126 Config
->inboxformat
=INI_GetValue(smsdcfgfile
, "smsd", "inboxformat", false);
127 if (Config
->inboxformat
== NULL
|| (!mystrncasecmp(Config
->inboxformat
, "detail", 6) && !mystrncasecmp(Config
->inboxformat
, "unicode", 7))) {
128 Config
->inboxformat
= "standard";
130 WriteSMSDLog("Inbox is \"%s\" with format \"%s\"", Config
->inboxpath
, Config
->inboxformat
);
132 Config
->outboxpath
=INI_GetValue(smsdcfgfile
, "smsd", "outboxpath", false);
133 if (Config
->outboxpath
== NULL
) Config
->outboxpath
= emptyPath
;
135 Config
->transmitformat
=INI_GetValue(smsdcfgfile
, "smsd", "transmitformat", false);
136 if (Config
->transmitformat
== NULL
|| (!mystrncasecmp(Config
->transmitformat
, "auto", 4) && !mystrncasecmp(Config
->transmitformat
, "unicode", 7))) {
137 Config
->transmitformat
= "7bit";
139 WriteSMSDLog("Outbox is \"%s\" with transmission format \"%s\"", Config
->outboxpath
, Config
->transmitformat
);
141 Config
->sentsmspath
=INI_GetValue(smsdcfgfile
, "smsd", "sentsmspath", false);
142 if (Config
->sentsmspath
== NULL
) Config
->sentsmspath
= Config
->outboxpath
;
143 WriteSMSDLog("Sent SMS moved to \"%s\"",Config
->sentsmspath
);
145 Config
->errorsmspath
=INI_GetValue(smsdcfgfile
, "smsd", "errorsmspath", false);
146 if (Config
->errorsmspath
== NULL
) Config
->errorsmspath
= Config
->sentsmspath
;
147 WriteSMSDLog("SMS with errors moved to \"%s\"",Config
->errorsmspath
);
149 Config
->IncludeNumbers
=INI_FindLastSectionEntry(smsdcfgfile
, "include_numbers", false);
150 Config
->ExcludeNumbers
=INI_FindLastSectionEntry(smsdcfgfile
, "exclude_numbers", false);
151 if (Config
->IncludeNumbers
!= NULL
) {
152 WriteSMSDLog("Include numbers available");
154 if (Config
->ExcludeNumbers
!= NULL
) {
155 if (Config
->IncludeNumbers
== NULL
) {
156 WriteSMSDLog("Exclude numbers available");
158 WriteSMSDLog("Exclude numbers available, but IGNORED");
163 Config
->prevSMSID
[0] = 0;
166 bool SMSD_CheckSecurity(GSM_SMSDConfig
*Config
)
168 GSM_SecurityCode SecurityCode
;
172 error
=Phone
->GetSecurityStatus(&s
,&SecurityCode
.Type
);
174 if (error
!= GE_NOTSUPPORTED
&& error
!= GE_NONE
) {
175 WriteSMSDLog("Error getting security status (%i)", error
);
178 /* No supported - do not check more */
179 if (error
== GE_NOTSUPPORTED
) return true;
180 /* If PIN, try to enter */
181 switch (SecurityCode
.Type
) {
183 WriteSMSDLog("Trying to enter PIN");
184 strcpy(SecurityCode
.Code
,Config
->PINCode
);
185 error
=Phone
->EnterSecurityCode(&s
,SecurityCode
);
186 if (error
== GE_SECURITYERROR
) {
187 GSM_Terminate_SMSD("ERROR: incorrect PIN", error
, true, -1);
189 if (error
!= GE_NONE
) {
190 WriteSMSDLog("Error entering PIN (%i)", error
);
194 case GSCT_SecurityCode
:
198 GSM_Terminate_SMSD("ERROR: phone requires not supported code type", 0, true, -1);
205 bool SMSD_ReadDeleteSMS(GSM_SMSDConfig
*Config
, GSM_SMSDService
*Service
)
208 GSM_MultiSMSMessage sms
;
209 unsigned char buffer
[100];
210 GSM_Error error
=GE_NONE
;
215 while (error
== GE_NONE
&& !bshutdown
) {
216 sms
.SMS
[0].Folder
=0x00;
217 error
=Phone
->GetNextSMS(&s
, &sms
, start
);
222 /* Not Inbox SMS - exit */
223 if (!sms
.SMS
[0].InboxFolder
) break;
225 DecodeUnicode(sms
.SMS
[0].Number
,buffer
);
226 if (Config
->IncludeNumbers
!= NULL
) {
227 e
=Config
->IncludeNumbers
;
230 if (e
== NULL
) break;
231 if (strcmp(buffer
,e
->EntryValue
)==0) {
237 } else if (Config
->ExcludeNumbers
!= NULL
) {
238 e
=Config
->ExcludeNumbers
;
241 if (e
== NULL
) break;
242 if (strcmp(buffer
,e
->EntryValue
)==0) {
250 Service
->SaveInboxSMS(sms
, Config
);
252 WriteSMSDLog("Excluded %s", buffer
);
256 WriteSMSDLog("Error getting SMS (%i)", error
);
259 if (error
== GE_NONE
&& sms
.SMS
[0].InboxFolder
) {
260 for (i
=0;i
<sms
.Number
;i
++) {
262 error
=Phone
->DeleteSMS(&s
,&sms
.SMS
[i
]);
268 WriteSMSDLog("Error deleting SMS (%i)", error
);
278 bool SMSD_CheckSMSStatus(GSM_SMSDConfig
*Config
,GSM_SMSDService
*Service
)
280 GSM_SMSMemoryStatus SMSStatus
;
283 /* Do we have any SMS in phone ? */
284 error
=Phone
->GetSMSStatus(&s
,&SMSStatus
);
285 if (error
!= GE_NONE
) {
286 WriteSMSDLog("Error getting SMS status (%i)", error
);
289 /* Yes. We have SMS in phone */
290 if (SMSStatus
.SIMUsed
+SMSStatus
.PhoneUsed
!= 0) {
291 return SMSD_ReadDeleteSMS(Config
,Service
);
296 bool SMSD_SendSMS(GSM_SMSDConfig
*Config
,GSM_SMSDService
*Service
)
298 GSM_MultiSMSMessage sms
;
301 unsigned int i
, j
, z
;
303 error
= Service
->FindOutboxSMS(&sms
, Config
, Config
->SMSID
);
305 if (error
== GE_EMPTY
) {
306 /* No outbox sms - wait few seconds and escape */
307 for (j
=0;j
<Config
->commtimeout
&& !bshutdown
;j
++) {
308 GSM_GetCurrentDateTime (&Date
);
310 while (i
==Date
.Second
&& !bshutdown
) {
312 GSM_GetCurrentDateTime(&Date
);
317 if (error
!= GE_NONE
) {
318 /* Unknown error - escape */
319 WriteSMSDLog("Error in outbox on %s", Config
->SMSID
);
320 Service
->MoveSMS(Config
->outboxpath
, Config
->errorsmspath
, Config
->SMSID
, true);
324 if (strcmp(Config
->prevSMSID
, Config
->SMSID
) == 0) {
326 if (Config
->retries
> MAX_RETRIES
) {
328 strcpy(Config
->prevSMSID
, "");
329 WriteSMSDLog("Moved to errorbox: %s", Config
->SMSID
);
330 Service
->MoveSMS(Config
->outboxpath
, Config
->errorsmspath
, Config
->SMSID
, true);
335 strcpy(Config
->prevSMSID
, Config
->SMSID
);
337 for (i
=0;i
<sms
.Number
;i
++) {
338 if (strcmp(Config
->deliveryreport
, "no") != 0) sms
.SMS
[i
].PDU
= SMS_Status_Report
;
339 error
=Phone
->SendSMS(&s
, &sms
.SMS
[i
]);
340 if (error
!=GE_NONE
) {
341 WriteSMSDLog("Error sending SMS %s (%i): %s", Config
->SMSID
, error
,print_error(error
,s
.di
.df
,s
.msg
));
345 SendingSMSStatus
= GE_TIMEOUT
;
347 GSM_GetCurrentDateTime (&Date
);
349 while (z
==Date
.Second
) {
351 GSM_GetCurrentDateTime(&Date
);
352 GSM_ReadDevice(&s
,true);
353 if (SendingSMSStatus
!= GE_TIMEOUT
) break;
355 if (SendingSMSStatus
!= GE_TIMEOUT
) break;
357 if (j
>Config
->sendtimeout
) break;
359 if (SendingSMSStatus
!= GE_NONE
) {
360 WriteSMSDLog("Error getting send status of %s (%i): %s", Config
->SMSID
, SendingSMSStatus
,print_error(SendingSMSStatus
,s
.di
.df
,s
.msg
));
363 WriteSMSDLog("Transmitted %s (%s: %i) to %s", Config
->SMSID
, (i
+1 == sms
.Number
?"total":"part"),i
+1,DecodeUnicodeString(sms
.SMS
[0].Number
));
365 strcpy(Config
->prevSMSID
, "");
366 if (Service
->MoveSMS(Config
->outboxpath
, Config
->sentsmspath
, Config
->SMSID
, false) != GE_NONE
)
367 Service
->MoveSMS(Config
->outboxpath
, Config
->errorsmspath
, Config
->SMSID
, true);
372 void SMSDaemon(int argc
, char *argv
[])
374 int errors
= 255, initerrors
=0;
375 GSM_SMSDService
*Service
;
378 GSM_SMSDConfig Config
;
380 if (!strcmp(argv
[2],"FILES")) {
381 Service
= &SMSDFiles
;
383 fprintf(stderr
,"Unknown service type (\"%s\")\n",argv
[2]);
387 SMSD_ReadConfig(argc
, argv
, &Config
);
389 error
= Service
->Init();
390 if (error
!=GE_NONE
) {
391 GSM_Terminate_SMSD("Stop GAMMU smsd (%i)", error
, true, -1);
394 /* We do not want to monitor serial line forever -
395 * press Ctrl+C to stop the monitoring mode.
397 signal(SIGINT
, interrupted
);
398 signal(SIGTERM
, interrupted
);
399 fprintf(stderr
,"Press Ctrl+C to stop the program ...\n");
402 SendingSMSStatus
= GE_UNKNOWN
;
404 /* Loop here indefinitely -
405 * allows you to see messages from GSM code in
406 * response to unknown messages etc.
407 * The loops ends after pressing the Ctrl+C.
410 /* There were errors in communication - try to recover */
413 WriteSMSDLog("Terminating communication (%i,%i)", error
, errors
);
414 error
=GSM_TerminateConnection(&s
);
416 if (initerrors
++ > 3) my_sleep(30000);
417 WriteSMSDLog("Starting communication");
418 error
=GSM_InitConnection(&s
,2);
421 s
.User
.SendSMSStatus
= SMSSendingSMSStatus
;
422 Phone
= s
.Phone
.Functions
;
424 /* Marcin Wiacek: FIXME. To check */
427 case GE_DEVICEOPENERROR
:
428 GSM_Terminate_SMSD("Can't open device (%i)", error
, true, -1);
430 WriteSMSDLog("Error at init connection (%i)", error
);
435 if ((difftime(time(NULL
), time1
) >= Config
.receivefrequency
) || (SendingSMSStatus
!= GE_NONE
)) {
438 if (!SMSD_CheckSecurity(&Config
))
447 if (!SMSD_CheckSMSStatus(&Config
,Service
))
453 if (!SMSD_SendSMS(&Config
,Service
)) continue;
455 GSM_Terminate_SMSD("Stop GAMMU smsd", 0, false, 0);
458 /* How should editor hadle tabs in this file? Add editor commands here.
459 * vim: noexpandtab sw=8 ts=8 sts=8: