siemens-sms-parser
Version:
Extract SMS messages from SMS.dat and .smo/.smi SMS Archive files on Siemens mobile phones.
76 lines (65 loc) • 2.61 kB
JavaScript
import {promises as fs} from 'node:fs';
import {join, resolve} from 'node:path';
import {formatTimestampToIsoWithOffset, SMSDatParser, SMSDecoder} from './sms-parser.js';
const args = process.argv.slice(2);
const debug = args.includes('--debug');
const target = args.find(a => !a.startsWith('-'));
if (!target) {
console.error('Usage: node cli.js <file|directory> [--debug]');
process.exit(1);
}
function formatOutput(decoded) {
let output = '';
if (decoded.errors.length > 0) output += `Errors:\n ${decoded.errors.join("\n ")}\n`;
output += `Format: ${decoded.format}\n`;
output += `Type: ${decoded.type}\n`;
output += `Segments: ${decoded.segmentsStored}/${decoded.segmentsTotal}\n`;
if (decoded.dateAndTimeZoneOffset !== undefined) output += `Date: ${formatTimestampToIsoWithOffset(decoded.dateAndTimeZoneOffset.date, decoded.dateAndTimeZoneOffset.timeZoneOffsetMinutes)}\n`;
output += `SMS Center: ${decoded.smsCenterNumber}\n`;
if (decoded.recipient !== undefined) output += `Recipient: ${decoded.recipient}\n`;
if (decoded.sender !== undefined) output += `Sender: ${decoded.sender}\n`;
output += `Encoding: ${decoded.encoding}\n`;
output += `Ref: ${decoded.messageRef}\n`;
output += `Length: ${decoded.length}\n`;
output += `Text: ${decoded.text}\n`;
if (debug) {
output += `HTML:\n`;
}
decoded.html.split('\n').forEach(line => output += ` ${line}\n`);
return output;
}
async function processFile(file) {
const raw = await fs.readFile(file);
try {
if (file.endsWith('.dat')) {
const messages = new SMSDatParser().decode(raw);
for (let i=0;i<messages.length;i++) {
console.log("*Message #" + (i+1) + "*");
console.log(formatOutput(messages[i]));
}
} else {
const decoded = new SMSDecoder().decode(raw);
console.log(formatOutput(decoded));
}
} catch (e) {
console.error(`ERROR: ${e.message}${debug ? `\n${e.stack}` : ''}`);
}
}
async function walk(p) {
const stat = await fs.stat(p);
if (stat.isDirectory()) {
for (const f of await fs.readdir(p)) await walk(join(p, f));
} else if (stat.isFile()) {
console.log(`--- ${p} ---`);
if (stat.size > 128 * 1024) {
console.error(`ERROR: File too large: ${p}`);
return;
}
await processFile(p);
}
}
walk(resolve(target)).catch(err => {
console.error(debug ? err : `ERROR: ${err.message}`);
process.exit(1);
});