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