1 /* (c) 2002-2004 by Joergen Thomsen */
15 #if defined HAVE_DIRENT_H && defined HAVE_SCANDIR && defined HAVE_ALPHASORT
16 #define HAVE_DIRBROWSING
22 #include "../../helper/string.h"
25 * Helper define to check error code from fwrite.
27 #define chk_fwrite(data, size, count, file) \
28 if (fwrite(data, size, count, file) != count) goto fail;
30 /* Save SMS from phone (called Inbox sms - it's in phone Inbox) somewhere */
31 static GSM_Error
SMSDFiles_SaveInboxSMS(GSM_MultiSMSMessage
* sms
, GSM_SMSDConfig
* Config
, char **Locations
)
33 GSM_Error error
= ERR_NONE
;
35 unsigned char FileName
[100], FullName
[400], ext
[4], buffer
[64], buffer2
[400];
38 size_t locations_size
= 0, locations_pos
= 0;
39 #ifdef GSM_ENABLE_BACKUP
40 GSM_SMS_Backup backup
;
46 for (i
= 0; i
< sms
->Number
&& !done
; i
++) {
48 if (sms
->SMS
[i
].Coding
== SMS_Coding_8bit
)
50 DecodeUnicode(sms
->SMS
[i
].Number
, buffer2
);
51 /* we loop on yy for the first SMS assuming that if xxxx_yy_00.ext is absent,
52 any xxxx_yy_01,02, must be garbage, that can be overwritten */
56 "IN%02d%02d%02d_%02d%02d%02d_%02i_%s_%02i.%s",
57 sms
->SMS
[i
].DateTime
.Year
, sms
->SMS
[i
].DateTime
.Month
, sms
->SMS
[i
].DateTime
.Day
,
58 sms
->SMS
[i
].DateTime
.Hour
, sms
->SMS
[i
].DateTime
.Minute
, sms
->SMS
[i
].DateTime
.Second
, j
, buffer2
, i
, ext
);
59 strcpy(FullName
, Config
->inboxpath
);
60 strcat(FullName
, FileName
);
63 file
= fopen(FullName
, "r");
64 } while ((i
== 0) && file
!= NULL
&& (++j
< 100));
69 SMSD_Log(DEBUG_ERROR
, Config
, "Cannot save %s. No available file names", FileName
);
70 return ERR_CANTOPENFILE
;
75 if ((sms
->SMS
[i
].PDU
== SMS_Status_Report
) && strcasecmp(Config
->deliveryreport
, "log") == 0) {
76 strcpy(buffer
, DecodeUnicodeString(sms
->SMS
[i
].Number
));
77 SMSD_Log(DEBUG_NOTICE
, Config
, "Delivery report: %s to %s, message reference 0x%02x",
78 DecodeUnicodeString(sms
->SMS
[i
].Text
), buffer
, sms
->SMS
[i
].MessageReference
);
80 if (locations_pos
+ strlen(FileName
) + 2 >= locations_size
) {
81 locations_size
+= strlen(FileName
) + 30;
82 *Locations
= (char *)realloc(*Locations
, locations_size
);
83 assert(*Locations
!= NULL
);
84 if (locations_pos
== 0) {
88 strcat(*Locations
, FileName
);
89 strcat(*Locations
, " ");
90 locations_pos
+= strlen(FileName
) + 1;
92 if (strcasecmp(Config
->inboxformat
, "detail") == 0) {
93 #ifndef GSM_ENABLE_BACKUP
94 SMSD_Log(DEBUG_ERROR
, Config
, "Saving in detail format not compiled in!");
97 for (j
= 0; j
< sms
->Number
; j
++) {
98 backup
.SMS
[j
] = &sms
->SMS
[j
];
100 backup
.SMS
[sms
->Number
] = NULL
;
101 error
= GSM_AddSMSBackupFile(FullName
, &backup
);
105 file
= fopen(FullName
, "wb");
107 SMSD_LogErrno(Config
, "Cannot save file!");
108 return ERR_CANTOPENFILE
;
111 switch (sms
->SMS
[i
].Coding
) {
112 case SMS_Coding_Unicode_No_Compression
:
113 case SMS_Coding_Default_No_Compression
:
114 DecodeUnicode(sms
->SMS
[i
].Text
, buffer2
);
115 if (strcasecmp(Config
->inboxformat
, "unicode") == 0) {
118 chk_fwrite(buffer
, 1, 2, file
);
119 chk_fwrite(sms
->SMS
[i
].Text
, 1, strlen(buffer2
) * 2, file
);
121 chk_fwrite(buffer2
, 1, strlen(buffer2
), file
);
124 case SMS_Coding_8bit
:
125 chk_fwrite(sms
->SMS
[i
].Text
, 1, (size_t) sms
->SMS
[i
].Length
, file
);
132 if (error
!= ERR_NONE
) {
136 SMSD_Log(DEBUG_INFO
, Config
, "%s %s", (sms
->SMS
[i
].PDU
== SMS_Status_Report
? "Delivery report" : "Received"), FileName
);
141 return ERR_WRITING_FILE
;
144 /* Find one multi SMS to sending and return it (or return ERR_EMPTY)
145 * There is also set ID for SMS
146 * File extension convention:
147 * OUTxxxxx.txt : normal text SMS
148 * Options appended to the extension applying to this SMS only:
149 * d: delivery report requested
151 * b: WAP bookmark as name,URL
152 * e.g. OUTG20040620_193810_123_+4512345678_xpq.txtdf
153 * is a flash text SMS requesting delivery reports
155 static GSM_Error
SMSDFiles_FindOutboxSMS(GSM_MultiSMSMessage
* sms
, GSM_SMSDConfig
* Config
, char *ID
)
157 GSM_MultiPartSMSInfo SMSInfo
;
158 GSM_WAPBookmark Bookmark
;
159 char FileName
[100], FullName
[400];
160 unsigned char Buffer
[(GSM_MAX_SMS_LENGTH
* GSM_MAX_MULTI_SMS
+ 1) * 2];
161 unsigned char Buffer2
[(GSM_MAX_SMS_LENGTH
* GSM_MAX_MULTI_SMS
+ 1) * 2];
164 char *pos1
, *pos2
, *options
= NULL
;
165 gboolean backup
= FALSE
;
166 #ifdef GSM_ENABLE_BACKUP
167 GSM_SMS_Backup smsbackup
;
171 struct _finddata_t c_file
;
174 strcpy(FullName
, Config
->outboxpath
);
175 strcat(FullName
, "OUT*.txt*");
176 hFile
= _findfirst(FullName
, &c_file
);
178 strcpy(FullName
, Config
->outboxpath
);
179 strcat(FullName
, "OUT*.smsbackup*");
180 hFile
= _findfirst(FullName
, &c_file
);
186 strcpy(FileName
, c_file
.name
);
189 #elif defined(HAVE_DIRBROWSING)
190 struct dirent
**namelist
= NULL
;
191 int cur_file
, num_files
;
194 strcpy(FullName
, Config
->outboxpath
);
196 FullName
[strlen(Config
->outboxpath
) - 1] = '\0';
198 num_files
= scandir(FullName
, &namelist
, 0, alphasort
);
200 for (cur_file
= 0; cur_file
< num_files
; cur_file
++) {
201 /* Hidden file or current/parent directory */
202 if (namelist
[cur_file
]->d_name
[0] == '.') {
205 /* We care only about files starting with out */
206 if (strncasecmp(namelist
[cur_file
]->d_name
, "out", 3) != 0) {
209 /* Check extension */
210 pos
= strrchr(namelist
[cur_file
]->d_name
, '.');
214 if (strncasecmp(pos
, ".txt", 4) == 0) {
215 /* We have found text file */
219 if (strncasecmp(pos
, ".smsbackup", 10) == 0) {
220 /* We have found a SMS backup file */
225 /* Remember file name */
226 if (cur_file
< num_files
) {
227 strcpy(FileName
, namelist
[cur_file
]->d_name
);
229 /* Free scandir result */
230 for (i
= 0; i
< num_files
; i
++) {
235 /* Did we actually find something? */
236 if (cur_file
>= num_files
) {
240 return ERR_NOTSUPPORTED
;
242 strcpy(FullName
, Config
->outboxpath
);
243 strcat(FullName
, FileName
);
246 #ifdef GSM_ENABLE_BACKUP
248 strcpy(ID
, FileName
);
250 GSM_ClearSMSBackup(&smsbackup
);
251 error
= GSM_ReadSMSBackupFile(FullName
, &smsbackup
);
252 if (error
!= ERR_NONE
) {
255 /* Copy it to our message */
257 for (i
= 0; smsbackup
.SMS
[i
] != NULL
; i
++) {
258 sms
->SMS
[sms
->Number
++] = *smsbackup
.SMS
[i
];
261 GSM_FreeSMSBackup(&smsbackup
);
263 /* Set delivery report flag */
264 if (sms
->SMS
[0].PDU
== SMS_Status_Report
) {
265 Config
->currdeliveryreport
= 1;
267 Config
->currdeliveryreport
= -1;
271 SMSD_Log(DEBUG_ERROR
, Config
, "SMS backup loading disabled at compile time!");
276 options
= strrchr(FileName
, '.') + 4;
278 File
= fopen(FullName
, "rb");
280 return ERR_CANTOPENFILE
;
282 len
= fread(Buffer
, 1, sizeof(Buffer
) - 2, File
);
285 if ((len
< 2) || (len
>= 2 && ((Buffer
[0] != 0xFF || Buffer
[1] != 0xFE) && (Buffer
[0] != 0xFE || Buffer
[1] != 0xFF)))) {
286 if (len
> GSM_MAX_SMS_LENGTH
* GSM_MAX_MULTI_SMS
)
287 len
= GSM_MAX_SMS_LENGTH
* GSM_MAX_MULTI_SMS
;
288 EncodeUnicode(Buffer2
, Buffer
, len
);
290 memmove(Buffer
, Buffer2
, len
);
296 /* Possibly convert byte order */
297 ReadUnicodeFile(Buffer2
, Buffer
);
300 GSM_ClearMultiPartSMSInfo(&SMSInfo
);
303 SMSInfo
.ReplaceMessage
= 0;
304 SMSInfo
.Entries
[0].Buffer
= Buffer2
;
306 SMSInfo
.EntriesNum
= 1;
307 Config
->currdeliveryreport
= -1;
308 if (strchr(options
, 'd'))
309 Config
->currdeliveryreport
= 1;
310 if (strchr(options
, 'f'))
311 SMSInfo
.Class
= 0; /* flash SMS */
313 if (strcasecmp(Config
->transmitformat
, "unicode") == 0) {
314 SMSInfo
.Entries
[0].ID
= SMS_ConcatenatedTextLong
;
315 SMSInfo
.UnicodeCoding
= TRUE
;
316 } else if (strcasecmp(Config
->transmitformat
, "7bit") == 0) {
317 SMSInfo
.Entries
[0].ID
= SMS_ConcatenatedTextLong
;
318 SMSInfo
.UnicodeCoding
= FALSE
;
321 SMSInfo
.Entries
[0].ID
= SMS_ConcatenatedAutoTextLong
;
324 if (strchr(options
, 'b')) { // WAP bookmark as title,URL
325 SMSInfo
.Entries
[0].Buffer
= NULL
;
326 SMSInfo
.Entries
[0].Bookmark
= &Bookmark
;
327 SMSInfo
.Entries
[0].ID
= SMS_NokiaWAPBookmarkLong
;
328 SMSInfo
.Entries
[0].Bookmark
->Location
= 0;
329 pos2
= mywstrstr(Buffer2
, "\0,");
336 pos2
++; // replace comma by zero
339 len
= UnicodeLength(Buffer2
);
343 memmove(&SMSInfo
.Entries
[0].Bookmark
->Title
, Buffer2
, len
* 2);
344 pos1
= &SMSInfo
.Entries
[0].Bookmark
->Title
[0] + len
* 2;
349 len
= UnicodeLength(pos2
);
353 memmove(&SMSInfo
.Entries
[0].Bookmark
->Address
, pos2
, len
* 2);
354 pos1
= &SMSInfo
.Entries
[0].Bookmark
->Address
[0] + len
* 2;
360 GSM_EncodeMultiPartSMS(GSM_GetDebug(Config
->gsm
), &SMSInfo
, sms
);
362 strcpy(ID
, FileName
);
364 for (i
= 1; i
<= 3 && pos1
!= NULL
; i
++) {
365 pos1
= strchr(++pos1
, '_');
368 /* OUT<priority><date>_<time>_<serialno>_<phone number>_<anything>.txt */
369 pos2
= strchr(++pos1
, '_');
371 phlen
= strlen(pos1
) - strlen(pos2
);
373 /* something wrong */
377 /* OUTxxxxxxx.txt or OUTxxxxxxx */
379 pos2
= strchr(pos1
, '.');
381 phlen
= strlen(pos1
);
383 phlen
= strlen(pos1
) - strlen(pos2
);
386 /* OUT<priority>_<phone number>_<serialno>.txt */
387 pos1
= strchr(FileName
, '_');
388 pos2
= strchr(++pos1
, '_');
389 phlen
= strlen(pos1
) - strlen(pos2
);
391 /* something wrong */
395 for (len
= 0; len
< sms
->Number
; len
++) {
396 EncodeUnicode(sms
->SMS
[len
].Number
, pos1
, phlen
);
400 if (sms
->Number
!= 0) {
401 DecodeUnicode(sms
->SMS
[0].Number
, Buffer
);
402 if (options
!= NULL
&& strchr(options
, 'b')) { // WAP bookmark as title,URL
403 SMSD_Log(DEBUG_NOTICE
, Config
, "Found %i sms to \"%s\" with bookmark \"%s\" cod %i lgt %i udh: t %i l %i dlr: %i fls: %i",
406 DecodeUnicodeString(SMSInfo
.Entries
[0].Bookmark
->Address
),
407 sms
->SMS
[0].Coding
, sms
->SMS
[0].Length
, sms
->SMS
[0].UDH
.Type
, sms
->SMS
[0].UDH
.Length
, Config
->currdeliveryreport
, SMSInfo
.Class
);
409 SMSD_Log(DEBUG_NOTICE
, Config
, "Found %i sms to \"%s\" with text \"%s\" cod %i lgt %i udh: t %i l %i dlr: %i fls: %i",
412 DecodeUnicodeString(sms
->SMS
[0].Text
),
413 sms
->SMS
[0].Coding
, sms
->SMS
[0].Length
, sms
->SMS
[0].UDH
.Type
, sms
->SMS
[0].UDH
.Length
, Config
->currdeliveryreport
, sms
->SMS
[0].Class
);
416 SMSD_Log(DEBUG_NOTICE
, Config
, "error: SMS-count = 0");
422 /* After sending SMS is moved to Sent Items or Error Items. */
423 static GSM_Error
SMSDFiles_MoveSMS(GSM_MultiSMSMessage
* sms UNUSED
, GSM_SMSDConfig
* Config
, char *ID
, gboolean alwaysDelete
, gboolean sent
)
426 size_t ilen
= 0, olen
= 0;
427 char Buffer
[(GSM_MAX_SMS_LENGTH
* GSM_MAX_MULTI_SMS
+ 1) * 2], ifilename
[400], ofilename
[400];
428 const char *sourcepath
, *destpath
;
430 sourcepath
= Config
->outboxpath
;
432 destpath
= Config
->sentsmspath
;
434 destpath
= Config
->errorsmspath
;
437 strcpy(ifilename
, sourcepath
);
438 strcat(ifilename
, ID
);
439 strcpy(ofilename
, destpath
);
440 strcat(ofilename
, ID
);
442 if (strcmp(ifilename
, ofilename
) != 0) {
443 iFile
= fopen(ifilename
, "r");
445 return ERR_CANTOPENFILE
;
447 ilen
= fread(Buffer
, 1, sizeof(Buffer
), iFile
);
449 oFile
= fopen(ofilename
, "w");
451 return ERR_CANTOPENFILE
;
453 olen
= fwrite(Buffer
, 1, ilen
, oFile
);
457 if ((strcmp(ifilename
, "/") == 0) || (remove(ifilename
) != 0)) {
458 SMSD_LogErrno(Config
, "Can not delete file");
459 SMSD_Log(DEBUG_INFO
, Config
, "Could not delete %s", ifilename
);
464 SMSD_Log(DEBUG_INFO
, Config
, "Error copying SMS %s -> %s", ifilename
, ofilename
);
466 if ((strcmp(ifilename
, "/") == 0) || (remove(ifilename
) != 0)) {
467 SMSD_LogErrno(Config
, "Can not delete file");
468 SMSD_Log(DEBUG_INFO
, Config
, "Could not delete %s", ifilename
);
475 /* Adds SMS to Outbox */
476 static GSM_Error
SMSDFiles_CreateOutboxSMS(GSM_MultiSMSMessage
* sms
, GSM_SMSDConfig
* Config
, char *NewID
)
479 unsigned char FileName
[100], FullName
[400], ext
[17], buffer
[64], buffer2
[400];
484 #ifdef GSM_ENABLE_BACKUP
486 GSM_SMS_Backup backup
;
491 timeinfo
= localtime(&rawtime
);
493 for (i
= 0; i
< sms
->Number
; i
++) {
494 if (strcasecmp(Config
->outboxformat
, "detail") == 0) {
495 strcpy(ext
, "smsbackup");
499 DecodeUnicode(sms
->SMS
[i
].Number
, buffer2
);
504 "OUTC%04d%02d%02d_%02d%02d%02d_00_%s_sms%d.%s",
505 1900 + timeinfo
->tm_year
, timeinfo
->tm_mon
, timeinfo
->tm_mday
, timeinfo
->tm_hour
, timeinfo
->tm_min
, timeinfo
->tm_sec
, buffer2
, j
, ext
);
506 strcpy(FullName
, Config
->outboxpath
);
507 strcat(FullName
, FileName
);
510 file
= fopen(FullName
, "r");
511 } while (file
!= NULL
&& (++j
< 100));
516 SMSD_Log(DEBUG_ERROR
, Config
, "Cannot save %s. No available file names", FileName
);
517 return ERR_CANTOPENFILE
;
521 if (strcasecmp(Config
->outboxformat
, "detail") == 0) {
522 #ifndef GSM_ENABLE_BACKUP
523 SMSD_Log(DEBUG_ERROR
, Config
, "Saving in detail format not compiled in!");
526 for (j
= 0; j
< sms
->Number
; j
++) {
527 backup
.SMS
[j
] = &sms
->SMS
[j
];
529 backup
.SMS
[sms
->Number
] = NULL
;
530 error
= GSM_AddSMSBackupFile(FullName
, &backup
);
532 if (error
!= ERR_NONE
) {
536 /* Force leaving the loop */
539 file
= fopen(FullName
, "wb");
541 SMSD_LogErrno(Config
, "Cannot save file!");
542 return ERR_CANTOPENFILE
;
544 switch (sms
->SMS
[i
].Coding
) {
545 case SMS_Coding_Unicode_No_Compression
:
546 case SMS_Coding_Default_No_Compression
:
547 if (strcasecmp(Config
->outboxformat
, "unicode") == 0) {
550 chk_fwrite(buffer
, 1, 2, file
);
551 chk_fwrite(sms
->SMS
[i
].Text
, 1, UnicodeLength(sms
->SMS
[i
].Text
) * 2, file
);
553 DecodeUnicode(sms
->SMS
[i
].Text
, buffer2
);
554 chk_fwrite(buffer2
, 1, strlen(buffer2
), file
);
557 case SMS_Coding_8bit
:
558 chk_fwrite(sms
->SMS
[i
].Text
, 1, (size_t) sms
->SMS
[i
].Length
, file
);
565 SMSD_Log(DEBUG_INFO
, Config
, "Created outbox message %s", FileName
);
569 strcpy(NewID
, FullName
);
574 return ERR_WRITING_FILE
;
577 static GSM_Error
SMSDFiles_AddSentSMSInfo(GSM_MultiSMSMessage
* sms UNUSED
, GSM_SMSDConfig
* Config
, char *ID UNUSED
, int Part
, GSM_SMSDSendingError err
, int TPMR
)
579 if (err
== SMSD_SEND_OK
) {
580 SMSD_Log(DEBUG_INFO
, Config
, "Transmitted %s (%s: %i) to %s, message reference 0x%02x",
581 Config
->SMSID
, (Part
== sms
->Number
? "total" : "part"), Part
, DecodeUnicodeString(sms
->SMS
[0].Number
), TPMR
);
587 GSM_Error
SMSDFiles_ReadConfiguration(GSM_SMSDConfig
*Config
)
589 static unsigned char emptyPath
[1] = "\0";
591 Config
->inboxpath
=INI_GetValue(Config
->smsdcfgfile
, "smsd", "inboxpath", FALSE
);
592 if (Config
->inboxpath
== NULL
) Config
->inboxpath
= emptyPath
;
594 Config
->inboxformat
=INI_GetValue(Config
->smsdcfgfile
, "smsd", "inboxformat", FALSE
);
595 if (Config
->inboxformat
== NULL
||
596 (strcasecmp(Config
->inboxformat
, "detail") != 0 &&
597 strcasecmp(Config
->inboxformat
, "standard") != 0 &&
598 strcasecmp(Config
->inboxformat
, "unicode") != 0)) {
599 Config
->inboxformat
= "standard";
601 SMSD_Log(DEBUG_NOTICE
, Config
, "Inbox is \"%s\" with format \"%s\"", Config
->inboxpath
, Config
->inboxformat
);
604 Config
->outboxpath
=INI_GetValue(Config
->smsdcfgfile
, "smsd", "outboxpath", FALSE
);
605 if (Config
->outboxpath
== NULL
) Config
->outboxpath
= emptyPath
;
607 Config
->transmitformat
=INI_GetValue(Config
->smsdcfgfile
, "smsd", "transmitformat", FALSE
);
608 if (Config
->transmitformat
== NULL
|| (strcasecmp(Config
->transmitformat
, "auto") != 0 && strcasecmp(Config
->transmitformat
, "unicode") != 0)) {
609 Config
->transmitformat
= "7bit";
611 Config
->outboxformat
=INI_GetValue(Config
->smsdcfgfile
, "smsd", "outboxformat", FALSE
);
612 if (Config
->outboxformat
== NULL
||
613 (strcasecmp(Config
->outboxformat
, "detail") != 0 &&
614 strcasecmp(Config
->outboxformat
, "standard") != 0 &&
615 strcasecmp(Config
->outboxformat
, "unicode") != 0)) {
616 #ifdef GSM_ENABLE_BACKUP
617 Config
->outboxformat
= "detail";
619 Config
->outboxformat
= "standard";
622 SMSD_Log(DEBUG_NOTICE
, Config
, "Outbox is \"%s\" with format \"%s\" and transmission format \"%s\"",
624 Config
->outboxformat
,
625 Config
->transmitformat
);
627 Config
->sentsmspath
=INI_GetValue(Config
->smsdcfgfile
, "smsd", "sentsmspath", FALSE
);
628 if (Config
->sentsmspath
== NULL
) Config
->sentsmspath
= Config
->outboxpath
;
629 SMSD_Log(DEBUG_NOTICE
, Config
, "Sent SMS moved to \"%s\"",Config
->sentsmspath
);
631 Config
->errorsmspath
=INI_GetValue(Config
->smsdcfgfile
, "smsd", "errorsmspath", FALSE
);
632 if (Config
->errorsmspath
== NULL
) Config
->errorsmspath
= Config
->sentsmspath
;
633 SMSD_Log(DEBUG_NOTICE
, Config
, "SMS with errors moved to \"%s\"",Config
->errorsmspath
);
638 GSM_SMSDService SMSDFiles
= {
639 NONEFUNCTION
, /* Init */
640 NONEFUNCTION
, /* Free */
641 NONEFUNCTION
, /* InitAfterConnect */
642 SMSDFiles_SaveInboxSMS
,
643 SMSDFiles_FindOutboxSMS
,
645 SMSDFiles_CreateOutboxSMS
,
646 SMSDFiles_AddSentSMSInfo
,
647 NOTIMPLEMENTED
, /* RefreshSendStatus */
648 NOTIMPLEMENTED
, /* RefreshPhoneStatus */
649 SMSDFiles_ReadConfiguration
652 /* How should editor handle tabs in this file? Add editor commands here.
653 * vim: noexpandtab sw=8 ts=8 sts=8: