// 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++; } }