2 * Copyright (C) 2011, Jamie Thompson
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public
6 * License as published by the Free Software Foundation; either
7 * version 3 of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public
15 * License along with this program; If not, see
16 * <http://www.gnu.org/licenses/>.
21 #include "Attachment.h"
23 #include "EventTypes/SMS.h"
27 #include <QTextStream>
31 using namespace EventParsers::VMGEntities;
33 VBody::VBody(const Settings &settings, const SMSEntity *parent) :
34 SMSEntity(settings, parent)
38 //VBody::VBody(QTextStream& stream)
46 void VBody::Write(QTextStream &stream, const EventTypes::SMS &event, const NumberToNameLookup &numberToNameLookup)
48 stream << "BEGIN:" << getTagName() << endl;
50 // First, the event's date field.
51 stream << "Date:" << event.Timestamp().toString("d.M.yyyy hh:mm:ss") << endl;
53 // ...next, the event's attachments
54 foreach(QSharedPointer<Attachment> attachment, event.Attachments())
55 stream << attachment->Stream().readAll() << endl;
57 // ...and now the event's contents
58 stream << event.Contents() << endl;
60 stream << "END:" << getTagName() << endl;
63 bool VBody::Read(const QString &initialLine, QTextStream &stream, EventTypes::SMS &event)
69 // Stream may or may not have a 'BEGIN' present. Swallow it if it's ours.
70 uint linePos(stream.pos());
71 QString lineData(initialLine.length() > 0 ? initialLine : stream.readLine());
72 if(lineData.startsWith("BEGIN:"))
74 if(lineData != QString("BEGIN:") + getTagName())
76 qDebug() << "Invalid stream";
86 // ...discard this line
87 lineData = stream.readLine();
94 if(lineData.startsWith("Date:"))
96 version = lineData.mid(lineData.indexOf(":")+1).toFloat();
98 else if(lineData.startsWith("BEGIN:"))
100 iReader* reader = Factory::Instantiate(CurrentSettings(), lineData, this);
101 bool valid(NULL != reader && reader->Read(lineData, stream, event));
104 // Quit processing if the nested content is not valid
108 else if(lineData.startsWith("END:"))
110 if(lineData != QString("END:") + getTagName())
112 qDebug() << getTagName() << " parser mismatch error: " << lineData;
123 if(text.isEmpty() && !lineData.isEmpty() && lineData.at(0) == 1)
125 // It's a binary SMS. Oh joy.
126 if(lineData.count() >= 5)
128 int wspMIMETypeID = lineData.at(5).unicode() & 0x7F;
129 if(BinaryMIMETypes().contains(wspMIMETypeID))
131 QString mimeType(BinaryMIMETypes().value(wspMIMETypeID));
132 qDebug() << "Attachment is: " << mimeType;
133 Attachment *binaryAttachment(new Attachment(
134 (QDir::tempPath() + "/attachment-" + QString::number(event.Timestamp().toTime_t()) + "-" + QString::number(event.Attachments().count()) + ".bin").toUtf8(),
139 // Alias the stream's device so we can asily access it
140 // directly in binary mode
141 QIODevice &binfile(*stream.device());
143 // Were going to ignore this data for the moment, but
144 // get an approximation of the range in the file.
145 int startPos(linePos);
147 int endPos(stream.pos());
148 binfile.seek(startPos);
150 qDebug() << "Binary offsets in file: " << startPos << ", " << endPos;
152 // Prepare our pointers for storing the data
153 int binDataLength((endPos - startPos) / sizeof(quint16));
154 char binaryData[binDataLength];
155 memset(&binaryData, 0, binDataLength);
156 char *binaryDataByte(binaryData);
158 // Grab the content from the file a byte at a time,
159 // skipping over every alternate byte (VMGs are UTF16LE)
160 // ...yes, even the binary data :(
161 int curpos(startPos);
162 while(binfile.pos() < endPos)
164 binfile.seek(curpos);
165 binfile.read(binaryDataByte++, 1);
167 // Look at the byte just stored. If it's an EOL,
168 // we're done. Even binary data ends on a valid line.
169 if(*(binaryDataByte - 1) == 0x0A)
171 // Note where the data actually ended.
172 binDataLength = (binfile.pos() - startPos) / sizeof(quint16);
176 qDebug() << hex << (int)binfile.pos() << "/" << hex << endPos << ": " << hex << (int)*(binaryDataByte - 1);
178 // Advance, skipping over every other byte.
179 curpos += sizeof(quint16);
181 // Move back a bit so the stream is ready to continue in
182 // text mode once we're done with the attachment.
183 stream.seek(endPos - 1);
185 // Directly access the output device and dump the binary
187 // NOTE: This is why the QFile needs to be unbuffered
188 binaryAttachment->Stream().device()->write(binaryData, binDataLength);
191 event.Attachments().append(binaryAttachment);
195 qDebug() << "Unrecognised binary mime type: " << hex << wspMIMETypeID;
196 return false; // Not supported for now
201 qDebug() << "Binary attachment too short (" << lineData.count() << " bytes). Not supported.";
202 return false; // Not supported for now
207 // If this isn't the first line, add a newline.
210 text.append(lineData);
214 linePos = stream.pos();
215 lineData = stream.readLine();
216 }while(!hasEnded && !stream.atEnd());
220 event.Contents(text);
221 //event.fld_storage_time