/* (c) 2002-2004 by Joergen Thomsen */ /* Copyright (c) 2009 - 2015 Michal Cihar */ #include #include #include #include #include #include #include #include #include #include #ifdef WIN32 #include #endif #if defined HAVE_DIRENT_H && defined HAVE_SCANDIR && defined HAVE_ALPHASORT #define HAVE_DIRBROWSING #include #endif #include "../core.h" #include "../../helper/string.h" #ifndef PATH_MAX #ifdef MAX_PATH #define PATH_MAX (MAX_PATH) #else #define PATH_MAX (4069) #endif #endif /** * Helper define to check error code from fwrite. */ #define chk_fwrite(data, size, count, file) \ if (fwrite(data, size, count, file) != count) goto fail; /* Save SMS from phone (called Inbox sms - it's in phone Inbox) somewhere */ static GSM_Error SMSDFiles_SaveInboxSMS(GSM_MultiSMSMessage * sms, GSM_SMSDConfig * Config, char **Locations) { GSM_Error error = ERR_NONE; int i, j; unsigned char FileName[100], FullName[PATH_MAX], ext[4], buffer[64], buffer2[400]; gboolean done; FILE *file; size_t locations_size = 0, locations_pos = 0; #ifdef GSM_ENABLE_BACKUP GSM_SMS_Backup *backup; #endif *Locations = NULL; j = 0; done = FALSE; for (i = 0; i < sms->Number && !done; i++) { strcpy(ext, "txt"); if (sms->SMS[i].Coding == SMS_Coding_8bit) strcpy(ext, "bin"); DecodeUnicode(sms->SMS[i].Number, buffer2); /* we loop on yy for the first SMS assuming that if xxxx_yy_00.ext is absent, any xxxx_yy_01,02, must be garbage, that can be overwritten */ file = NULL; do { sprintf(FileName, "IN%02d%02d%02d_%02d%02d%02d_%02i_%s_%02i.%s", sms->SMS[i].DateTime.Year, sms->SMS[i].DateTime.Month, sms->SMS[i].DateTime.Day, sms->SMS[i].DateTime.Hour, sms->SMS[i].DateTime.Minute, sms->SMS[i].DateTime.Second, j, buffer2, i, ext); strcpy(FullName, Config->inboxpath); strcat(FullName, FileName); if (file) { fclose(file); } file = fopen(FullName, "r"); } while ((i == 0) && file != NULL && (++j < 100)); if (file) { fclose(file); file = NULL; if (i == 0) { SMSD_Log(DEBUG_ERROR, Config, "Cannot save %s. No available file names", FileName); return ERR_CANTOPENFILE; } } errno = 0; if ((sms->SMS[i].PDU == SMS_Status_Report) && strcasecmp(Config->deliveryreport, "log") == 0) { strcpy(buffer, DecodeUnicodeString(sms->SMS[i].Number)); SMSD_Log(DEBUG_NOTICE, Config, "Delivery report: %s to %s, message reference 0x%02x", DecodeUnicodeString(sms->SMS[i].Text), buffer, sms->SMS[i].MessageReference); } else { if (locations_pos + strlen(FileName) + 2 >= locations_size) { locations_size += strlen(FileName) + 30; *Locations = (char *)realloc(*Locations, locations_size); assert(*Locations != NULL); if (locations_pos == 0) { *Locations[0] = 0; } } strcat(*Locations, FileName); strcat(*Locations, " "); locations_pos += strlen(FileName) + 1; if (strcasecmp(Config->inboxformat, "detail") == 0) { #ifndef GSM_ENABLE_BACKUP SMSD_Log(DEBUG_ERROR, Config, "Saving in detail format not compiled in!"); #else backup = malloc(sizeof(GSM_SMS_Backup)); if (backup == NULL) { return ERR_MOREMEMORY; } for (j = 0; j < sms->Number; j++) { backup->SMS[j] = &sms->SMS[j]; } backup->SMS[sms->Number] = NULL; error = GSM_AddSMSBackupFile(FullName, backup); done = TRUE; free(backup); #endif } else { file = fopen(FullName, "wb"); if (file == NULL) { SMSD_LogErrno(Config, "Cannot save file!"); return ERR_CANTOPENFILE; } switch (sms->SMS[i].Coding) { case SMS_Coding_Unicode_No_Compression: case SMS_Coding_Default_No_Compression: DecodeUnicode(sms->SMS[i].Text, buffer2); if (strcasecmp(Config->inboxformat, "unicode") == 0) { buffer[0] = 0xFE; buffer[1] = 0xFF; chk_fwrite(buffer, 1, 2, file); chk_fwrite(sms->SMS[i].Text, 1, strlen(buffer2) * 2, file); } else { chk_fwrite(buffer2, 1, strlen(buffer2), file); } break; case SMS_Coding_8bit: chk_fwrite(sms->SMS[i].Text, 1, (size_t) sms->SMS[i].Length, file); default: break; } fclose(file); file = NULL; } if (error != ERR_NONE) { return error; } SMSD_Log(DEBUG_INFO, Config, "%s %s", (sms->SMS[i].PDU == SMS_Status_Report ? "Delivery report" : "Received"), FileName); } } return ERR_NONE; fail: if (file) { fclose(file); } return ERR_WRITING_FILE; } /* Find one multi SMS to sending and return it (or return ERR_EMPTY) * There is also set ID for SMS * File extension convention: * OUTxxxxx.txt : normal text SMS * Options appended to the extension applying to this SMS only: * d: delivery report requested * f: flash SMS * b: WAP bookmark as name,URL * e.g. OUTG20040620_193810_123_+4512345678_xpq.txtdf * is a flash text SMS requesting delivery reports */ static GSM_Error SMSDFiles_FindOutboxSMS(GSM_MultiSMSMessage * sms, GSM_SMSDConfig * Config, char *ID) { GSM_MultiPartSMSInfo SMSInfo; GSM_WAPBookmark Bookmark; char FileName[100], FullName[PATH_MAX]; unsigned char Buffer[(GSM_MAX_SMS_LENGTH * GSM_MAX_MULTI_SMS + 1) * 2]; unsigned char Buffer2[(GSM_MAX_SMS_LENGTH * GSM_MAX_MULTI_SMS + 1) * 2]; FILE *File; int i; size_t len, phlen; char *pos1, *pos2, *options = NULL; gboolean backup = FALSE; #ifdef GSM_ENABLE_BACKUP GSM_SMS_Backup *smsbackup; GSM_Error error; #endif #ifdef WIN32 struct _finddata_t c_file; intptr_t hFile; strcpy(FullName, Config->outboxpath); strcat(FullName, "OUT*.txt*"); hFile = _findfirst(FullName, &c_file); if (hFile == -1) { strcpy(FullName, Config->outboxpath); strcat(FullName, "OUT*.smsbackup*"); hFile = _findfirst(FullName, &c_file); backup = TRUE; } if (hFile == -1) { return ERR_EMPTY; } else { strcpy(FileName, c_file.name); } _findclose(hFile); #elif defined(HAVE_DIRBROWSING) struct dirent **namelist = NULL; int cur_file, num_files; char *pos; strcpy(FullName, Config->outboxpath); FullName[strlen(Config->outboxpath) - 1] = '\0'; num_files = scandir(FullName, &namelist, 0, alphasort); for (cur_file = 0; cur_file < num_files; cur_file++) { /* Hidden file or current/parent directory */ if (namelist[cur_file]->d_name[0] == '.') { continue; } /* We care only about files starting with out */ if (strncasecmp(namelist[cur_file]->d_name, "out", 3) != 0) { continue; } /* Check extension */ pos = strrchr(namelist[cur_file]->d_name, '.'); if (pos == NULL) { continue; } if (strncasecmp(pos, ".txt", 4) == 0) { /* We have found text file */ backup = FALSE; break; } if (strncasecmp(pos, ".smsbackup", 10) == 0) { /* We have found a SMS backup file */ backup = TRUE; break; } } /* Remember file name */ if (cur_file < num_files) { strcpy(FileName, namelist[cur_file]->d_name); } /* Free scandir result */ for (i = 0; i < num_files; i++) { free(namelist[i]); } free(namelist); namelist = NULL; /* Did we actually find something? */ if (cur_file >= num_files) { return ERR_EMPTY; } #else return ERR_NOTSUPPORTED; #endif strcpy(FullName, Config->outboxpath); strcat(FullName, FileName); if (backup) { #ifdef GSM_ENABLE_BACKUP smsbackup = malloc(sizeof(GSM_SMS_Backup)); if (smsbackup == NULL) { return ERR_MOREMEMORY; } /* Remember ID */ strcpy(ID, FileName); /* Load backup */ GSM_ClearSMSBackup(smsbackup); error = GSM_ReadSMSBackupFile(FullName, smsbackup); if (error != ERR_NONE) { free(smsbackup); return error; } /* Copy it to our message */ sms->Number = 0; for (i = 0; smsbackup->SMS[i] != NULL; i++) { sms->SMS[sms->Number++] = *(smsbackup->SMS[i]); } /* Free memory */ GSM_FreeSMSBackup(smsbackup); free(smsbackup); /* Set delivery report flag */ if (sms->SMS[0].PDU == SMS_Status_Report) { Config->currdeliveryreport = 1; } else { Config->currdeliveryreport = -1; } #else SMSD_Log(DEBUG_ERROR, Config, "SMS backup loading disabled at compile time!"); return ERR_DISABLED; #endif } else { options = strrchr(FileName, '.') + 4; File = fopen(FullName, "rb"); if (File == NULL) { return ERR_CANTOPENFILE; } len = fread(Buffer, 1, sizeof(Buffer) - 2, File); fclose(File); if ((len < 2) || (len >= 2 && ((Buffer[0] != 0xFF || Buffer[1] != 0xFE) && (Buffer[0] != 0xFE || Buffer[1] != 0xFF)))) { if (len > GSM_MAX_SMS_LENGTH * GSM_MAX_MULTI_SMS) len = GSM_MAX_SMS_LENGTH * GSM_MAX_MULTI_SMS; EncodeUnicode(Buffer2, Buffer, len); len = len * 2; memmove(Buffer, Buffer2, len); Buffer[len] = 0; Buffer[len + 1] = 0; } else { Buffer[len] = 0; Buffer[len + 1] = 0; /* Possibly convert byte order */ ReadUnicodeFile(Buffer2, Buffer); } GSM_ClearMultiPartSMSInfo(&SMSInfo); sms->Number = 0; SMSInfo.ReplaceMessage = 0; SMSInfo.Entries[0].Buffer = Buffer2; SMSInfo.Class = -1; SMSInfo.EntriesNum = 1; Config->currdeliveryreport = -1; if (strchr(options, 'd')) Config->currdeliveryreport = 1; if (strchr(options, 'f')) SMSInfo.Class = 0; /* flash SMS */ if (strcasecmp(Config->transmitformat, "unicode") == 0) { SMSInfo.Entries[0].ID = SMS_ConcatenatedTextLong; SMSInfo.UnicodeCoding = TRUE; } else if (strcasecmp(Config->transmitformat, "7bit") == 0) { SMSInfo.Entries[0].ID = SMS_ConcatenatedTextLong; SMSInfo.UnicodeCoding = FALSE; } else { /* auto */ SMSInfo.Entries[0].ID = SMS_ConcatenatedAutoTextLong; } if (strchr(options, 'b')) { // WAP bookmark as title,URL SMSInfo.Entries[0].Buffer = NULL; SMSInfo.Entries[0].Bookmark = &Bookmark; SMSInfo.Entries[0].ID = SMS_NokiaWAPBookmarkLong; SMSInfo.Entries[0].Bookmark->Location = 0; pos2 = mywstrstr(Buffer2, "\0,"); if (pos2 == NULL) { pos2 = Buffer2; } else { *pos2 = '\0'; pos2++; *pos2 = '\0'; pos2++; // replace comma by zero } len = UnicodeLength(Buffer2); if (len > 50) { len = 50; } memmove(&SMSInfo.Entries[0].Bookmark->Title, Buffer2, len * 2); pos1 = &SMSInfo.Entries[0].Bookmark->Title[0] + len * 2; *pos1 = '\0'; pos1++; *pos1 = '\0'; len = UnicodeLength(pos2); if (len > 255) { len = 255; } memmove(&SMSInfo.Entries[0].Bookmark->Address, pos2, len * 2); pos1 = &SMSInfo.Entries[0].Bookmark->Address[0] + len * 2; *pos1 = '\0'; pos1++; *pos1 = '\0'; } GSM_EncodeMultiPartSMS(GSM_GetDebug(Config->gsm), &SMSInfo, sms); strcpy(ID, FileName); pos1 = FileName; for (i = 1; i <= 3 && pos1 != NULL; i++) { pos1 = strchr(++pos1, '_'); } if (pos1 != NULL) { /* OUT_