// CalendarTimezone.cpp - CalendarTimezone class functions
//
// (c) 2016-2017 Xestia Software Development.
//
// This file is part of Xestia Calendar.
//
// Xestia Calendar is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by the
// Free Software Foundation, version 3 of the license.
//
// Xestia Calendar is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with Xestia Calendar. If not, see
#include "CalendarTimezone.h"
using namespace std;
CalendarObjectValidResult CalendarTimezoneObject::ValidObject(){
bool ValidBegin = false;
bool ValidEnd = false;
bool ValidTimeZoneID = false;
int SeekCount = 0;
string PropertyName;
// Look for BEGIN:VEVENT.
for (vector::iterator iter = ObjectName.begin();
iter != ObjectName.end(); iter++){
if (ObjectName[SeekCount] == "BEGIN" &&
ObjectData[SeekCount] == "VTIMEZONE"){
if (ValidBegin == false){
ValidBegin = true;
} else {
return CALENDAROBJECTVALID_INVALIDFORMAT;
}
}
if (ObjectName[SeekCount] == "END" &&
ObjectData[SeekCount] == "VTIMEZONE" &&
ValidBegin == false){
return CALENDAROBJECTVALID_INVALIDFORMAT;
}
SeekCount++;
}
SeekCount = 0;
// Look for TZID.
for (vector::iterator iter = ObjectName.begin();
iter != ObjectName.end(); iter++){
try{
PropertyName = ObjectName[SeekCount].substr(0,4);
}
catch(const out_of_range& oor){
continue;
}
if (PropertyName == "TZID"){
if (ValidTimeZoneID == false){
ValidTimeZoneID = true;
} else {
return CALENDAROBJECTVALID_INVALIDFORMAT;
}
}
SeekCount++;
}
SeekCount = 0;
// Look for END:VEVENT.
for (vector::iterator iter = ObjectName.begin();
iter != ObjectName.end(); iter++){
if (ObjectName[SeekCount] == "END" &&
ObjectData[SeekCount] == "VTIMEZONE"){
if (ValidEnd == false){
ValidEnd = true;
} else {
return CALENDAROBJECTVALID_INVALIDFORMAT;
}
}
SeekCount++;
}
// Check if the VEVENT is valid.
if (ValidBegin == true &&
ValidEnd == true &&
ValidTimeZoneID == true){
return CALENDAROBJECTVALID_OK;
} else {
return CALENDAROBJECTVALID_INVALIDFORMAT;
}
}
void CalendarTimezoneObject::ProcessData(){
// Process the data.
multimap DataReceived;
map PropertyData;
string *PropertyNameData = nullptr;
int ObjectSeekCount = 0;
// Process the data from TZID.
DataReceived = ProcessTextVectors(&ObjectName, &ObjectData, false, "TZID");
if (DataReceived.begin() != DataReceived.end()){
try {
TimeZoneDataTokens = DataReceived.begin()->first.substr(5);
}
catch(const out_of_range &oor){
// Do nothing as there is no data.
}
TimeZoneData = DataReceived.begin()->second;
}
// Process the data from LAST-MODIFIED.
DataReceived = ProcessTextVectors(&ObjectName, &ObjectData, false, "LAST-MODIFIED");
if (DataReceived.begin() != DataReceived.end()){
try {
LastModifiedTokens = DataReceived.begin()->first.substr(14);
}
catch(const out_of_range &oor){
// Do nothing as there is no data.
}
LastModifiedData = DataReceived.begin()->second;
}
// Process the data from TZURL.
DataReceived = ProcessTextVectors(&ObjectName, &ObjectData, false, "TZURL");
if (DataReceived.begin() != DataReceived.end()){
try {
TimeZoneURLTokens = DataReceived.begin()->first.substr(6);
}
catch(const out_of_range &oor){
// Do nothing as there is no data.
}
TimeZoneURLData = DataReceived.begin()->second;
}
// Process data from each STANDARD and DAYLIGHT.
ProcessStandardDaylight();
int TZSeekCount = 0;
int SeekCount = 0;
for (vector>::iterator tzsiter = TimezoneStandardName.begin();
tzsiter != TimezoneStandardName.end(); tzsiter++){
bool DateTimeStartFound = false;
bool TimeZoneOffsetToFound = false;
bool TimeZoneOffsetFromFound = false;
TimezoneDataStruct NewTZData;
// Process the data from DTSTART.
DataReceived = ProcessTextVectors(&TimezoneStandardName[SeekCount],
&TimezoneStandardData[SeekCount], false, "DTSTART");
if (DataReceived.begin() != DataReceived.end()){
try {
NewTZData.DateTimeStartTokens = DataReceived.begin()->first.substr(8);
}
catch(const out_of_range &oor){
// Do nothing as there is no data.
}
NewTZData.DateTimeStartData = DataReceived.begin()->second;
DateTimeStartFound = true;
}
// Process the data from TZOFFSETFROM.
DataReceived = ProcessTextVectors(&TimezoneStandardName[SeekCount],
&TimezoneStandardData[SeekCount], false, "TZOFFSETFROM");
if (DataReceived.begin() != DataReceived.end()){
try {
NewTZData.TimeZoneOffsetFromTokens = DataReceived.begin()->first.substr(13);
}
catch(const out_of_range &oor){
// Do nothing as there is no data.
}
NewTZData.TimeZoneOffsetFromData = DataReceived.begin()->second;
TimeZoneOffsetFromFound = true;
}
// Process the data from TZOFFSETTO.
DataReceived = ProcessTextVectors(&TimezoneStandardName[SeekCount],
&TimezoneStandardData[SeekCount], false, "TZOFFSETTO");
if (DataReceived.begin() != DataReceived.end()){
try {
NewTZData.TimeZoneOffsetToTokens = DataReceived.begin()->first.substr(11);
}
catch(const out_of_range &oor){
// Do nothing as there is no data.
}
NewTZData.TimeZoneOffsetToData = DataReceived.begin()->second;
TimeZoneOffsetToFound = true;
}
// Process the data from RRULE.
DataReceived = ProcessTextVectors(&TimezoneStandardName[SeekCount],
&TimezoneStandardData[SeekCount], false, "RRULE");
if (DataReceived.begin() != DataReceived.end()){
try {
NewTZData.RecurranceRuleDataTokens = DataReceived.begin()->first.substr(6);
}
catch(const out_of_range &oor){
// Do nothing as there is no data.
}
NewTZData.RecurranceRuleData = DataReceived.begin()->second;
}
// Process the data from COMMENT.
DataReceived = ProcessTextVectors(&TimezoneStandardName[SeekCount],
&TimezoneStandardData[SeekCount], true, "COMMENT");
ObjectSeekCount = 0;
for(multimap::iterator propiter = DataReceived.begin();
propiter != DataReceived.end();
++propiter){
NewTZData.CommentListTokens.push_back("");
NewTZData.CommentListAltRep.push_back("");
NewTZData.CommentListLanguage.push_back("");
NewTZData.CommentList.push_back("");
bool TokenData = false;
string PropertyTokens;
PropertyNameData = (string*)&propiter->first;
PropertyData = SplitValues(*PropertyNameData);
for(map::iterator propdataiter = PropertyData.begin();
propdataiter != PropertyData.end(); propdataiter++){
if (propdataiter->first == "ALTREP"){
NewTZData.CommentListAltRep[ObjectSeekCount] = propdataiter->second;
} else if (propdataiter->first == "LANGUAGE"){
NewTZData.CommentListLanguage[ObjectSeekCount] = propdataiter->second;
} else {
if (TokenData == false){
TokenData = true;
} else {
PropertyTokens += ";";
}
PropertyTokens += propdataiter->first;
PropertyTokens += "=";
PropertyTokens += propdataiter->second;
}
}
if (PropertyTokens.size() > 0){
NewTZData.CommentListTokens[ObjectSeekCount] = PropertyTokens;
}
NewTZData.CommentList[ObjectSeekCount] = propiter->second;
ObjectSeekCount++;
}
// Process the data from RDATE.
DataReceived = ProcessTextVectors(&TimezoneStandardName[SeekCount],
&TimezoneStandardData[SeekCount], true, "RDATE");
ObjectSeekCount = 0;
for(multimap::iterator propiter = DataReceived.begin();
propiter != DataReceived.end();
++propiter){
NewTZData.RecurranceDateDataTokens.push_back("");
NewTZData.RecurranceDateDataValue.push_back("");
NewTZData.RecurranceDateDataTimeZoneParam.push_back("");
NewTZData.RecurranceDateData.push_back("");
bool TokenData = false;
string PropertyTokens;
PropertyNameData = (string*)&propiter->first;
PropertyData = SplitValues(*PropertyNameData);
for(map::iterator dataiter = PropertyData.begin();
dataiter != PropertyData.end(); dataiter++){
if (dataiter->first == "VALUE"){
NewTZData.RecurranceDateDataValue[ObjectSeekCount] = dataiter->second;
} else if (dataiter->first == "TZID"){
NewTZData.RecurranceDateDataTimeZoneParam[ObjectSeekCount] = dataiter->second;
} else {
if (TokenData == false){
TokenData = true;
} else {
PropertyTokens += ";";
}
PropertyTokens += dataiter->first;
PropertyTokens += "=";
PropertyTokens += dataiter->second;
}
}
if (PropertyTokens.size() > 0){
NewTZData.RecurranceDateDataTokens[ObjectSeekCount] = PropertyTokens;
}
NewTZData.RecurranceDateData[ObjectSeekCount] = propiter->second;
ObjectSeekCount++;
}
// Process the data from TZNAME.
DataReceived = ProcessTextVectors(&TimezoneStandardName[SeekCount],
&TimezoneStandardData[SeekCount], true, "TZNAME");
ObjectSeekCount = 0;
for(multimap::iterator propiter = DataReceived.begin();
propiter != DataReceived.end();
++propiter){
NewTZData.TimeZoneNameTokens.push_back("");
NewTZData.TimeZoneNameLanguage.push_back("");
NewTZData.TimeZoneNameData.push_back("");
bool TokenData = false;
string PropertyTokens;
PropertyNameData = (string*)&propiter->first;
PropertyData = SplitValues(*PropertyNameData);
for(map::iterator dataiter = PropertyData.begin();
dataiter != PropertyData.end(); dataiter++){
if (dataiter->first == "LANGUAGE"){
NewTZData.TimeZoneNameLanguage[ObjectSeekCount] = dataiter->second;
} else {
if (TokenData == false){
TokenData = true;
} else {
PropertyTokens += ";";
}
PropertyTokens += dataiter->first;
PropertyTokens += "=";
PropertyTokens += dataiter->second;
}
}
if (PropertyTokens.size() > 0){
NewTZData.TimeZoneNameTokens[ObjectSeekCount] = PropertyTokens;
}
NewTZData.TimeZoneNameData[ObjectSeekCount] = propiter->second;
ObjectSeekCount++;
}
ObjectSeekCount = 0;
// Process data from X-*
for(vector::iterator propiter = TimezoneStandardName[SeekCount].begin();
propiter != TimezoneStandardName[SeekCount].end(); ++propiter){
if (propiter->substr(0,2) == "X-" &&
propiter->size() > 2){
NewTZData.XTokensData.push_back(TimezoneStandardData[SeekCount][ObjectSeekCount]);
NewTZData.XTokensDataTokens.push_back(TimezoneStandardName[SeekCount][ObjectSeekCount]);
}
ObjectSeekCount++;
}
// Check if the required values were given and
// insert NewTZData into the vector list of
// standard timezones.
if (DateTimeStartFound == true &&
TimeZoneOffsetToFound == true &&
TimeZoneOffsetFromFound == true){
TimezoneStandardCollection.push_back(NewTZData);
}
SeekCount++;
}
TZSeekCount = 0;
SeekCount = 0;
for (vector>::iterator tzsiter = TimezoneDaylightName.begin();
tzsiter != TimezoneDaylightName.end(); tzsiter++){
bool DateTimeStartFound = false;
bool TimeZoneOffsetToFound = false;
bool TimeZoneOffsetFromFound = false;
TimezoneDataStruct NewTZData;
// Process the data from DTSTART.
DataReceived = ProcessTextVectors(&TimezoneDaylightName[SeekCount],
&TimezoneDaylightData[SeekCount], false, "DTSTART");
if (DataReceived.begin() != DataReceived.end()){
try {
NewTZData.DateTimeStartTokens = DataReceived.begin()->first.substr(8);
}
catch(const out_of_range &oor){
// Do nothing as there is no data.
}
NewTZData.DateTimeStartData = DataReceived.begin()->second;
DateTimeStartFound = true;
}
// Process the data from TZOFFSETFROM.
DataReceived = ProcessTextVectors(&TimezoneDaylightName[SeekCount],
&TimezoneDaylightData[SeekCount], false, "TZOFFSETFROM");
if (DataReceived.begin() != DataReceived.end()){
try {
NewTZData.TimeZoneOffsetFromTokens = DataReceived.begin()->first.substr(13);
}
catch(const out_of_range &oor){
// Do nothing as there is no data.
}
NewTZData.TimeZoneOffsetFromData = DataReceived.begin()->second;
TimeZoneOffsetFromFound = true;
}
// Process the data from TZOFFSETTO.
DataReceived = ProcessTextVectors(&TimezoneDaylightName[SeekCount],
&TimezoneDaylightData[SeekCount], false, "TZOFFSETTO");
if (DataReceived.begin() != DataReceived.end()){
try {
NewTZData.TimeZoneOffsetToTokens = DataReceived.begin()->first.substr(11);
}
catch(const out_of_range &oor){
// Do nothing as there is no data.
}
NewTZData.TimeZoneOffsetToData = DataReceived.begin()->second;
TimeZoneOffsetToFound = true;
}
// Process the data from RRULE.
DataReceived = ProcessTextVectors(&TimezoneDaylightName[SeekCount],
&TimezoneDaylightData[SeekCount], false, "RRULE");
if (DataReceived.begin() != DataReceived.end()){
try {
NewTZData.RecurranceRuleDataTokens = DataReceived.begin()->first.substr(6);
}
catch(const out_of_range &oor){
// Do nothing as there is no data.
}
NewTZData.RecurranceRuleData = DataReceived.begin()->second;
}
// Process the data from COMMENT.
DataReceived = ProcessTextVectors(&TimezoneDaylightName[SeekCount],
&TimezoneDaylightData[SeekCount], true, "COMMENT");
ObjectSeekCount = 0;
for(multimap::iterator propiter = DataReceived.begin();
propiter != DataReceived.end();
++propiter){
NewTZData.CommentListTokens.push_back("");
NewTZData.CommentListAltRep.push_back("");
NewTZData.CommentListLanguage.push_back("");
NewTZData.CommentList.push_back("");
bool TokenData = false;
string PropertyTokens;
PropertyNameData = (string*)&propiter->first;
PropertyData = SplitValues(*PropertyNameData);
for(map::iterator propdataiter = PropertyData.begin();
propdataiter != PropertyData.end(); propdataiter++){
if (propdataiter->first == "ALTREP"){
NewTZData.CommentListAltRep[ObjectSeekCount] = propdataiter->second;
} else if (propdataiter->first == "LANGUAGE"){
NewTZData.CommentListLanguage[ObjectSeekCount] = propdataiter->second;
} else {
if (TokenData == false){
TokenData = true;
} else {
PropertyTokens += ";";
}
PropertyTokens += propdataiter->first;
PropertyTokens += "=";
PropertyTokens += propdataiter->second;
}
}
if (PropertyTokens.size() > 0){
NewTZData.CommentListTokens[ObjectSeekCount] = PropertyTokens;
}
NewTZData.CommentList[ObjectSeekCount] = propiter->second;
ObjectSeekCount++;
}
// Process the data from RDATE.
DataReceived = ProcessTextVectors(&TimezoneDaylightName[SeekCount],
&TimezoneDaylightData[SeekCount], true, "RDATE");
ObjectSeekCount = 0;
for(multimap::iterator propiter = DataReceived.begin();
propiter != DataReceived.end();
++propiter){
NewTZData.RecurranceDateDataTokens.push_back("");
NewTZData.RecurranceDateDataValue.push_back("");
NewTZData.RecurranceDateDataTimeZoneParam.push_back("");
NewTZData.RecurranceDateData.push_back("");
bool TokenData = false;
string PropertyTokens;
PropertyNameData = (string*)&propiter->first;
PropertyData = SplitValues(*PropertyNameData);
for(map::iterator dataiter = PropertyData.begin();
dataiter != PropertyData.end(); dataiter++){
if (dataiter->first == "VALUE"){
NewTZData.RecurranceDateDataValue[ObjectSeekCount] = dataiter->second;
} else if (dataiter->first == "TZID"){
NewTZData.RecurranceDateDataTimeZoneParam[ObjectSeekCount] = dataiter->second;
} else {
if (TokenData == false){
TokenData = true;
} else {
PropertyTokens += ";";
}
PropertyTokens += dataiter->first;
PropertyTokens += "=";
PropertyTokens += dataiter->second;
}
}
if (PropertyTokens.size() > 0){
NewTZData.RecurranceDateDataTokens[ObjectSeekCount] = PropertyTokens;
}
NewTZData.RecurranceDateData[ObjectSeekCount] = propiter->second;
ObjectSeekCount++;
}
// Process the data from TZNAME.
DataReceived = ProcessTextVectors(&TimezoneDaylightName[SeekCount],
&TimezoneDaylightData[SeekCount], true, "TZNAME");
ObjectSeekCount = 0;
for(multimap::iterator propiter = DataReceived.begin();
propiter != DataReceived.end();
++propiter){
NewTZData.TimeZoneNameTokens.push_back("");
NewTZData.TimeZoneNameLanguage.push_back("");
NewTZData.TimeZoneNameData.push_back("");
bool TokenData = false;
string PropertyTokens;
PropertyNameData = (string*)&propiter->first;
PropertyData = SplitValues(*PropertyNameData);
for(map::iterator dataiter = PropertyData.begin();
dataiter != PropertyData.end(); dataiter++){
if (dataiter->first == "LANGUAGE"){
NewTZData.TimeZoneNameLanguage[ObjectSeekCount] = dataiter->second;
} else {
if (TokenData == false){
TokenData = true;
} else {
PropertyTokens += ";";
}
PropertyTokens += dataiter->first;
PropertyTokens += "=";
PropertyTokens += dataiter->second;
}
}
if (PropertyTokens.size() > 0){
NewTZData.TimeZoneNameTokens[ObjectSeekCount] = PropertyTokens;
}
NewTZData.TimeZoneNameData[ObjectSeekCount] = propiter->second;
ObjectSeekCount++;
}
ObjectSeekCount = 0;
// Process data from X-*
for(vector::iterator propiter = TimezoneDaylightName[SeekCount].begin();
propiter != TimezoneDaylightName[SeekCount].end(); ++propiter){
if (propiter->substr(0,2) == "X-" &&
propiter->size() > 2){
NewTZData.XTokensData.push_back(TimezoneDaylightData[SeekCount][ObjectSeekCount]);
NewTZData.XTokensDataTokens.push_back(TimezoneDaylightName[SeekCount][ObjectSeekCount]);
}
ObjectSeekCount++;
}
// Check if the required values were given and
// insert NewTZData into the vector list of
// daylight timezones.
if (DateTimeStartFound == true &&
TimeZoneOffsetToFound == true &&
TimeZoneOffsetFromFound == true){
TimezoneDaylightCollection.push_back(NewTZData);
}
SeekCount++;
}
}
void CalendarTimezoneObject::ProcessStandardDaylight(){
int SeekCount = 0;
bool TZMode = false; // False = STANDARD, True = DAYLIGHT.
bool ValidBegin = false;
vector TimezoneObjectName;
vector TimezoneObjectData;
for (vector::iterator iter = ObjectName.begin();
iter != ObjectName.end(); iter++){
// Check if the current name is BEGIN and
// data is either STANDARD or DAYLIGHT.
if (ObjectName[SeekCount] == "BEGIN" &&
(ObjectData[SeekCount] == "STANDARD" ||
ObjectData[SeekCount] == "DAYLIGHT")){
if (ValidBegin == false){
ValidBegin = true;
} else {
}
if (ObjectData[SeekCount] == "STANDARD"){
TZMode = false;
} else if (ObjectData[SeekCount] == "DAYLIGHT") {
TZMode = true;
}
SeekCount++;
continue;
}
// Check if current name is END and
// data is either STANDARD or DAYLIGHT.
if (ObjectName[SeekCount] == "END" &&
(ObjectData[SeekCount] == "STANDARD" ||
ObjectData[SeekCount] == "DAYLIGHT") &&
ValidBegin == true){
if (TZMode == false && TimezoneObjectName.size() > 0){
TimezoneStandardName.push_back(TimezoneObjectName);
TimezoneStandardData.push_back(TimezoneObjectData);
} else {
TimezoneDaylightName.push_back(TimezoneObjectName);
TimezoneDaylightData.push_back(TimezoneObjectData);
}
TimezoneObjectName.clear();
TimezoneObjectData.clear();
ValidBegin = false;
}
if (ValidBegin == true){
TimezoneObjectName.push_back(ObjectName[SeekCount]);
TimezoneObjectData.push_back(ObjectData[SeekCount]);
}
SeekCount++;
}
}