Addressing some compilation warnings:
[qwerkisync] / EventParsers / VMGEntities / VBody.cpp
1 /*
2  * Copyright (C) 2011, Jamie Thompson
3  *
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.
8  *
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.
13  *
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/>.
17  */
18
19 #include "VBody.h"
20
21 #include "Attachment.h"
22 #include "Factory.h"
23 #include "EventTypes/SMS.h"
24
25 #include <QDateTime>
26 #include <QDir>
27 #include <QTextStream>
28
29 #include <QDebug>
30
31 using namespace EventParsers::VMGEntities;
32
33 VBody::VBody(const Settings &settings, const SMSEntity *parent) :
34         SMSEntity(settings, parent)
35 {
36 }
37
38 VBody::~VBody()
39 {
40 }
41
42 // Note: NametoNumberLookup is currently unused here.
43 void VBody::Write(QTextStream &stream, const EventTypes::SMS &event, const NumberToNameLookup &)
44 {
45         stream << "BEGIN:" << getTagName() << endl;
46
47         // First, the event's date field.
48         stream << "Date:" << event.Timestamp().toString("d.M.yyyy hh:mm:ss") << endl;
49
50         // ...next, the event's attachments
51         foreach(QSharedPointer<Attachment> attachment, event.Attachments())
52                 stream << attachment->Stream().readAll() << endl;
53
54         // ...and now the event's contents
55         stream << event.Contents() << endl;
56
57         stream << "END:" << getTagName() << endl;
58 }
59
60 bool VBody::Read(const QString &initialLine, QTextStream &stream, EventTypes::SMS &event)
61 {
62         bool hasEnded(false);
63         float version(0);
64         QString text;
65
66         // Stream may or may not have a 'BEGIN' present. Swallow it if it's ours.
67         uint linePos(stream.pos());
68         QString lineData(initialLine.length() > 0 ? initialLine : stream.readLine());
69         if(lineData.startsWith("BEGIN:"))
70         {
71                 if(lineData != QString("BEGIN:") + getTagName())
72                 {
73                         qDebug() << "Invalid stream";
74                         return false;
75                 }
76                 else
77                 {
78                         if(isAttachment())
79                         {
80                         }
81                         else
82                         {
83                                 // ...discard this line
84                                 lineData = stream.readLine();
85                         }
86                 }
87         }
88
89         do
90         {
91                 if(lineData.startsWith("Date:"))
92                 {
93                         version = lineData.mid(lineData.indexOf(":")+1).toFloat();
94                 }
95                 else if(lineData.startsWith("BEGIN:"))
96                 {
97                         iReader* reader = Factory::Instantiate(CurrentSettings(), lineData, this);
98                         bool valid(NULL != reader && reader->Read(lineData, stream, event));
99                         delete reader;
100
101                         // Quit processing if the nested content is not valid
102                         if(!valid)
103                                 return valid;
104                 }
105                 else if(lineData.startsWith("END:"))
106                 {
107                         if(lineData != QString("END:") + getTagName())
108                         {
109                                 qDebug() << getTagName() << " parser mismatch error: " << lineData;
110                                 return false;
111                         }
112                         else
113                         {
114                                 hasEnded = true;
115                                 break;
116                         }
117                 }
118                 else
119                 {
120                         if(text.isEmpty() && !lineData.isEmpty() && lineData.at(0) == 1)
121                         {
122                                 // It's a binary SMS. Oh joy.
123                                 if(lineData.count() >= 5)
124                                 {
125                                         int wspMIMETypeID = lineData.at(5).unicode() & 0x7F;
126                                         if(BinaryMIMETypes().contains(wspMIMETypeID))
127                                         {
128                                                 QString mimeType(BinaryMIMETypes().value(wspMIMETypeID));
129                                                 qDebug() << "Attachment is: " << mimeType;
130                                                 Attachment *binaryAttachment(new Attachment(
131                                                         (QDir::tempPath() + "/attachment-" + QString::number(event.Timestamp().toTime_t()) + "-" + QString::number(event.Attachments().count()) + ".bin").toUtf8(),
132                                                         mimeType));
133
134                                                 // Grab the content
135
136                                                 // Alias the stream's device so we can asily access it
137                                                 // directly in binary mode
138                                                 QIODevice &binfile(*stream.device());
139
140                                                 // Were going to ignore this data for the moment, but
141                                                 // get an approximation of the range in the file.
142                                                 int startPos(linePos);
143                                                 stream.readLine();
144                                                 int endPos(stream.pos());
145                                                 binfile.seek(startPos);
146
147                                                 qDebug() << "Binary offsets in file: " << startPos << ", " << endPos;
148
149                                                 // Prepare our pointers for storing the data
150                                                 int binDataLength((endPos - startPos) / sizeof(quint16));
151                                                 char binaryData[binDataLength];
152                                                 memset(&binaryData, 0, binDataLength);
153                                                 char *binaryDataByte(binaryData);
154
155                                                 // Grab the content from the file a byte at a time,
156                                                 // skipping over every alternate byte (VMGs are UTF16LE)
157                                                 // ...yes, even the binary data :(
158                                                 int curpos(startPos);
159                                                 while(binfile.pos() < endPos)
160                                                 {
161                                                         binfile.seek(curpos);
162                                                         binfile.read(binaryDataByte++, 1);
163
164                                                         // Look at the byte just stored. If it's an EOL,
165                                                         // we're done. Even binary data ends on a valid line.
166                                                         if(*(binaryDataByte - 1) == 0x0A)
167                                                         {
168                                                                 // Note where the data actually ended.
169                                                                 binDataLength = (binfile.pos() - startPos) / sizeof(quint16);
170                                                                 break;
171                                                         }
172
173                                                         qDebug() << hex << (int)binfile.pos() << "/" << hex << endPos << ": " << hex << (int)*(binaryDataByte - 1);
174
175                                                         // Advance, skipping over every other byte.
176                                                         curpos += sizeof(quint16);
177                                                 }
178                                                 // Move back a bit so the stream is ready to continue in
179                                                 // text mode once we're done with the attachment.
180                                                 stream.seek(endPos - 1);
181
182                                                 // Directly access the output device and dump the binary
183                                                 // data into it.
184                                                 // NOTE: This is why the QFile needs to be unbuffered
185                                                 binaryAttachment->Stream().device()->write(binaryData, binDataLength);
186
187                                                 // Save attachment
188                                                 event.Attachments().append(binaryAttachment);
189                                         }
190                                         else
191                                         {
192                                                 qDebug() << "Unrecognised binary mime type: " << hex << wspMIMETypeID;
193                                                 return false; // Not supported for now
194                                         }
195                                 }
196                                 else
197                                 {
198                                         qDebug() << "Binary attachment too short (" << lineData.count() << " bytes). Not supported.";
199                                         return false; // Not supported for now
200                                 }
201                         }
202                         else
203                         {
204                                 // If this isn't the first line, add a newline.
205                                 if(!text.isEmpty())
206                                         text.append(0x0A);
207                                 text.append(lineData);
208                         }
209                 }
210
211                 linePos = stream.pos();
212                 lineData = stream.readLine();
213         }while(!hasEnded && !stream.atEnd());
214
215         if(hasEnded)
216         {
217                 event.Contents(text);
218                 //event.fld_storage_time
219         }
220
221         return true;
222 }