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/>.
20 #include "CSVSymbianEventLogParser.h"
21 #include "EventTypes/PhoneCall.h"
30 #include <QStringList>
34 using namespace EventParsers;
35 using EventTypes::PhoneCall;
40 inline bool operator()(const QPair<QChar, uint> &a, const QPair<QChar, uint> &b) const
42 return b.second < a.second;
46 const QString ExtractString(const QString &originalString)
48 QRegExp content("^[\"\']?(.*)?[\"\']?$");
49 content.indexIn(originalString.trimmed());
50 return content.cap(1);
53 iEventParser *CSVSymbianEventLogParser::IsValid(const Settings ¤tSettings, QFile &eventFile)
55 qDebug() << "Checking if a CSV call log file...";
58 eventsReader.Open(eventFile);
60 // If we found all of the required headings, continue
61 if(eventsReader.HasRequiredHeadings(QStringList() << "EType" << "ETime"<< "Remote" << "Direction" << "Status" << "Duration" << "Number" << "Data").count() == 0)
62 return new EventParsers::CSVSymbianEventLogParser(currentSettings, eventFile.fileName()/*, delim, numColumnsPerRecord, headingPositions*/);
67 CSVSymbianEventLogParser::CSVSymbianEventLogParser(const Settings &settings, const QString &filename/*, const QChar delimiter, const int numColumnsPerRecord, const ColumnIndicesHash &headingIndices*/)
68 : m_Settings(settings)/*, m_Delimiter(delimiter), m_NumColumnsPerRecord(numColumnsPerRecord), m_HeadingIndices(headingIndices)*/
72 EventTypes::EventFromFileList CSVSymbianEventLogParser::ParseFile(QFile &eventFile, const QList<uint> &recordsToReturn)
74 EventTypes::EventFromFileList fileEvents;
76 // Parse secondary table for string values
79 QFileInfo eventFileInfo(eventFile);
80 QString filePath(eventFileInfo.absolutePath() + "/string.csv");
82 QFile stringsFile(filePath);
83 if(stringsFile.open(QFile::ReadOnly))
86 stringsReader.Open(stringsFile);
87 if(stringsReader.HasRequiredHeadings(QStringList() << "TEXT" << "Id").count() == 0)
89 while(!stringsReader.AtEnd())
91 QHash<QString, QString> values(stringsReader.ReadRecord());
92 Strings().insert(values.value("text").toLower(), values.value("id").toUInt());
97 throw std::runtime_error(QString("Unable to open: '%1'. The error was: %2").arg(filePath).arg(stringsFile.error()).toStdString());
100 QSet<uint> recordsToReturnSet(QSet<uint>::fromList(recordsToReturn));
103 eventsReader.Open(eventFile);
104 if(eventsReader.HasRequiredHeadings(QStringList() << "EType" << "ETime"
105 << "Remote" << "Direction" << "Status"
106 << "Duration" << "Number" << "Data").count() == 0)
108 while(!eventsReader.AtEnd())
110 QHash<QString, QString> recordValues(eventsReader.ReadRecord());
112 if(recordsToReturnSet.count() == 0 || recordsToReturnSet.contains(eventsReader.CurrentRecordNumber()))
115 int eType(recordValues.value("etype").toUInt(&bOK));
116 // We're only interested in phone calls
117 if(bOK && eType == 0)
119 qDebug() << "Parsing event from record #" << eventsReader.CurrentRecordNumber() << ". Values: " << recordValues;
121 QDateTime eTime(QDateTime::fromString(recordValues.value("etime"), "dd/MM/yyyy h:mm:ss ap"));
122 Settings::eDirection direction(ReadDirection(recordValues.value("direction").toUInt()));
124 // We only care about the requested directions...
125 if(CurrentSettings().ShouldProcess(direction, EventTypes::EVENT_TYPE_CALL))
127 int duration(recordValues.value("duration").toInt(&bOK));
130 qDebug() << QString("Unable to parse '%1' as a duration. Skipping record.")
131 .arg(recordValues.value("duration"));
135 QString number(ExtractString(recordValues.value("number")));
137 bool isMissedCall(ExtractString(recordValues.value("direction")).toUInt() == Strings().value("missed call"));
139 uint test = ExtractString(recordValues.value("direction")).toUInt();
140 if(test != Strings().value("incoming") && test != Strings().value("outgoing"))
141 qDebug() << eventFile.fileName() << ", line #" << eventsReader.CurrentRecordNumber() << "Direction? : " << test;
143 // TODO: Not currently used...but almost certainly contains SIP call data
144 QString data(ExtractString(recordValues.value("data")));
146 if(number.trimmed().length() == 0)
147 qDebug() << "Empty tel!";
149 QSharedPointer<EventTypes::iEvent> newEvent(new PhoneCall(
156 fileEvents.append(EventTypes::EventFromFile(newEvent, eventsReader.CurrentRecordNumber()));
163 qDebug() << QString("File pos: %1, bAvail: %2, canReadLine: %3").arg(eventFile.pos()).arg(eventFile.bytesAvailable()).arg(eventFile.canReadLine());
164 qDebug() << fileEvents.count() << " events loaded from file";
168 Settings::eDirection CSVSymbianEventLogParser::ReadDirection(const uint value)
171 if(value == Strings().value("incoming") || value == Strings().value("missed call"))
172 return Settings::INCOMING;
173 else if(value == Strings().value("outgoing"))
174 return Settings::OUTGOING;
177 // Determine which string this value corresponds to...
178 QString unexpectedString("");
179 foreach(QString string, Strings().keys())
180 if(Strings().value(string) == value)
181 unexpectedString = string;
183 throw std::runtime_error(
184 QString("Unexpected value found: \"%1\" (maps to \"%2\")")
186 .arg(unexpectedString != "" ? unexpectedString : "<no known string>")