diff --git a/.idea/calendarimporter.iml b/.idea/calendarimporter.iml new file mode 100644 index 0000000..c956989 --- /dev/null +++ b/.idea/calendarimporter.iml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..e7bedf3 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..d821048 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..34195db --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/php.xml b/.idea/php.xml new file mode 100644 index 0000000..07f31c0 --- /dev/null +++ b/.idea/php.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/scopes/scope_settings.xml b/.idea/scopes/scope_settings.xml new file mode 100644 index 0000000..922003b --- /dev/null +++ b/.idea/scopes/scope_settings.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml new file mode 100644 index 0000000..6488bc3 --- /dev/null +++ b/.idea/workspace.xml @@ -0,0 +1,677 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + DEFINITION_ORDER + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + project + + + true + + + + DIRECTORY + + false + + + + + + + + + 1477949602474 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..fd5d35c --- /dev/null +++ b/Makefile @@ -0,0 +1,2 @@ +default: + ant deploy; cp -r /home/osboxes/Documents/kopano-webapp-3.2.0.285/deploy/plugins/calendarimporter /usr/share/kopano-webapp/plugins/ diff --git a/backend/functions.php b/backend/functions.php index f6a9625..b4df684 100644 --- a/backend/functions.php +++ b/backend/functions.php @@ -3,7 +3,7 @@ * functions.php, zarafa calender to ics im/exporter backend * * Author: Christoph Haas - * Copyright (C) 2012-2014 Christoph Haas + * Copyright (C) 2012-2016 Christoph Haas * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public diff --git a/backend/sync.php b/backend/sync.php index 647429b..90e2322 100644 --- a/backend/sync.php +++ b/backend/sync.php @@ -4,7 +4,7 @@ * sync.php, zarafa calender to ics im/exporter backend * * Author: Christoph Haas - * Copyright (C) 2012-2014 Christoph Haas + * Copyright (C) 2012-2016 Christoph Haas * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -129,7 +129,7 @@ foreach($userList as $userName => $userData) { if($icsData != NULL) { file_put_contents($tmpFilename, $icsData); echo "Got valid data for " . $syncItem["icsurl"] . " stored in " . $tmpFilename . "\n"; - $result = upload_ics_to_caldav($tmpFilename, $CALDAVURL, $userName, $syncItem["calendar"], $ADMINUSERNAME, $ADMINPASSWORD); + $result = upload_ics_to_caldav($tmpFilename, $CALDAVURL, $userName, $syncItem["calendarname"], $ADMINUSERNAME, $ADMINPASSWORD); if(intval($result) == 200) { echo "Import completed: $result\n"; $result = update_last_sync_date($userStore, $syncItemName); diff --git a/build.xml b/build.xml index 47601f7..dba3f1c 100644 --- a/build.xml +++ b/build.xml @@ -1,18 +1,15 @@ - - - - - - - + + + + + - @@ -21,30 +18,8 @@ - - - - - - - - - - - - - - - - - - - - - - @@ -54,8 +29,7 @@ - - + @@ -68,16 +42,6 @@ - - - - - - - - - - @@ -89,27 +53,11 @@ - - - - - - - - - - - - - - - - - + @@ -118,8 +66,8 @@ - - + + @@ -163,16 +111,7 @@ var npgettext = function(msgctxt, msgid, msgid_plural, count) {}; var pgettext = function(msgctxt, msgid) {}; - - + @@ -180,105 +119,82 @@ - + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - Processing manifest.xml - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + - + + - - - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/changelog.txt b/changelog.txt index 3854a97..1e2a725 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,10 @@ +calendarimporter 2.2.0: + - support for Kopano Webapp 3.1.1 + - Code rework + - Calendar export improved + - Calendar import improved + - GUI improvements + calendarimporter 2.1.0: - ics sync is now implemented diff --git a/config.php b/config.php index 34bd778..a1b8f1b 100644 --- a/config.php +++ b/config.php @@ -1,15 +1,13 @@ diff --git a/java/Main.java b/java/Main.java deleted file mode 100644 index ba2c238..0000000 --- a/java/Main.java +++ /dev/null @@ -1,87 +0,0 @@ -/** - * A small tool to create our timezone mappings list =) - */ -import java.util.TimeZone; - -public class Main { - static String map[] = new String[51]; // one field = 30 minutes step - - private static void initMap() { - map[0] = "Pacific/Midway"; - map[1] = ""; - map[2] = "Pacific/Fakaofo"; - map[3] = "Pacific/Marquesas"; - map[4] = "America/Anchorage"; - map[5] = ""; - map[6] = "America/Dawson"; - map[7] = ""; - map[8] = "America/Dawson_Creek"; - map[9] = ""; - map[10] = "America/Chicago"; - map[11] = "America/Caracas"; - map[12] = "America/Detroit"; - map[13] = "America/Caracas"; - map[14] = "America/Santiago"; - map[15] = "America/St_Johns"; - map[16] = "America/Sao_Paulo"; - map[17] = ""; - map[18] = "America/Noronha"; - map[19] = ""; - map[20] = "Atlantic/Cape_Verde"; - map[21] = ""; - map[22] = "Africa/Abidjan"; - map[23] = ""; - map[24] = "Europe/Vienna"; - map[25] = ""; - map[26] = "Asia/Jerusalem"; - map[27] = ""; - map[28] = "Africa/Addis_Ababa"; - map[29] = "Asia/Tehran"; - map[30] = "Asia/Dubai"; - map[31] = "Asia/Kabul"; - map[32] = "Antarctica/Mawson"; - map[33] = "Asia/Colombo"; - map[34] = "Antarctica/Vostok"; - map[35] = "Asia/Rangoon"; - map[36] = "Antarctica/Davis"; - map[37] = ""; - map[38] = "Antarctica/Casey"; - map[39] = ""; - map[40] = "Asia/Dili"; - map[41] = "Australia/Darwin"; - map[42] = "Australia/Currie"; - map[43] = "Australia/Lord_Howe"; - map[44] = "Antarctica/Macquarie"; - map[45] = "Pacific/Norfolk"; - map[46] = "Antarctica/McMurdo"; - map[47] = ""; - map[48] = "Pacific/Enderbury"; - map[49] = ""; - map[50] = "Pacific/Kiritimati"; - } - - /** - * @param args - */ - public static void main(String[] args) { - initMap(); - - int i = 0; - for(int time = -660; time < 900; time += 30) { - - int hours = time / 60; - int minutes = Math.abs(time) % 60; - - String[] avaiId = TimeZone.getAvailableIDs(time*60*1000); - - if(avaiId.length > 0) { - System.out.printf("\t\t/*%+d:%02d*/\n", hours, minutes); - for (String string : avaiId) { - System.out.println("\t\t'" + string + "' : '" + map[i] + "',"); - } - } - - i++; - } - } -} diff --git a/js/ABOUT.js b/js/ABOUT.js index 3ee5b09..984c28b 100644 --- a/js/ABOUT.js +++ b/js/ABOUT.js @@ -2,7 +2,7 @@ * ABOUT.js zarafa calender to ics im/exporter * * Author: Christoph Haas - * Copyright (C) 2012-2013 Christoph Haas + * Copyright (C) 2012-2016 Christoph Haas * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -29,7 +29,7 @@ Ext.namespace('Zarafa.plugins.calendarimporter'); * The copyright string holding the copyright notice for the Zarafa calendarimporter Plugin. */ Zarafa.plugins.calendarimporter.ABOUT = "" - + "

Copyright (C) 2012-2013 Christoph Haas <christoph.h@sprinternet.at>

" + + "

Copyright (C) 2012-2016 Christoph Haas <christoph.h@sprinternet.at>

" + "

This program is free software; you can redistribute it and/or " + "modify it under the terms of the GNU Lesser General Public " diff --git a/js/data/Actions.js b/js/data/Actions.js new file mode 100644 index 0000000..68d6e5a --- /dev/null +++ b/js/data/Actions.js @@ -0,0 +1,178 @@ +/** + * Actions.js zarafa calender to ics im/exporter + * + * Author: Christoph Haas + * Copyright (C) 2012-2016 Christoph Haas + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/** + * ResponseHandler + * + * This class handles all responses from the php backend + */ +Ext.namespace('Zarafa.plugins.calendarimporter.data'); + +/** + * @class Zarafa.plugins.calendarimporter.data.Actions + * Common actions which can be used within {@link Ext.Button buttons} + * or other {@link Ext.Component components} with action handlers. + * @singleton + */ +Zarafa.plugins.calendarimporter.data.Actions = { + /** + * Callback for the export request. + * @param {Object} response + */ + downloadICS: function (response) { + if (response.status == false) { + Zarafa.common.dialogs.MessageBox.show({ + title : dgettext('plugin_files', 'Warning'), + msg : dgettext('plugin_files', response.message), + icon : Zarafa.common.dialogs.MessageBox.WARNING, + buttons: Zarafa.common.dialogs.MessageBox.OK + }); + } else { + var downloadFrame = Ext.getBody().createChild({ + tag: 'iframe', + cls: 'x-hidden' + }); + + var url = document.URL; + var link = url.substring(0, url.lastIndexOf('/') + 1); + + link += "index.php?sessionid=" + container.getUser().getSessionId() + "&load=custom&name=download_ics"; + link = Ext.urlAppend(link, "token=" + encodeURIComponent(response.download_token)); + link = Ext.urlAppend(link, "filename=" + encodeURIComponent(response.filename)); + + downloadFrame.dom.contentWindow.location = link; + } + }, + + /** + * Get all calendar folders. + * @param {boolean} asDropdownStore If true, a simple array store will be returned. + * @returns {*} + */ + getAllCalendarFolders: function (asDropdownStore) { + asDropdownStore = Ext.isEmpty(asDropdownStore) ? false : asDropdownStore; + + var allFolders = []; + + var inbox = container.getHierarchyStore().getDefaultStore(); + var pub = container.getHierarchyStore().getPublicStore(); + + if (!Ext.isEmpty(inbox.subStores) && inbox.subStores.folders.totalLength > 0) { + for (var i = 0; i < inbox.subStores.folders.totalLength; i++) { + var folder = inbox.subStores.folders.getAt(i); + if (folder.get("container_class") == "IPF.Appointment") { + if (asDropdownStore) { + allFolders.push([ + folder.get("entryid"), + folder.get("display_name") + ]); + } else { + allFolders.push({ + display_name : folder.get("display_name"), + entryid : folder.get("entryid"), + store_entryid: folder.get("store_entryid"), + is_public : false + }); + } + } + } + } + + if (!Ext.isEmpty(pub.subStores) && pub.subStores.folders.totalLength > 0) { + for (var j = 0; j < pub.subStores.folders.totalLength; j++) { + var folder = pub.subStores.folders.getAt(j); + if (folder.get("container_class") == "IPF.Appointment") { + if (asDropdownStore) { + allFolders.push([ + folder.get("entryid"), + folder.get("display_name") + " (Public)" + ]); + } else { + allFolders.push({ + display_name : folder.get("display_name"), + entryid : folder.get("entryid"), + store_entryid: folder.get("store_entryid"), + is_public : true + }); + } + } + } + } + + if (asDropdownStore) { + return allFolders.sort(Zarafa.plugins.calendarimporter.data.Actions.dynamicSort(1)); + } else { + return allFolders; + } + }, + + /** + * Return a calendar folder element by name. + * @param {string} name + * @returns {*} + */ + getCalendarFolderByName: function (name) { + var folders = Zarafa.plugins.calendarimporter.data.Actions.getAllCalendarFolders(false); + + for (var i = 0; i < folders.length; i++) { + if (folders[i].display_name == name) { + return folders[i]; + } + } + + return container.getHierarchyStore().getDefaultFolder('calendar'); + }, + + /** + * Return a calendar folder element by entryid. + * @param {string} entryid + * @returns {*} + */ + getCalendarFolderByEntryid: function (entryid) { + var folders = Zarafa.plugins.calendarimporter.data.Actions.getAllCalendarFolders(false); + + for (var i = 0; i < folders.length; i++) { + if (folders[i].entryid == entryid) { + return folders[i]; + } + } + + return container.getHierarchyStore().getDefaultFolder('calendar'); + }, + + /** + * Dynamic sort function, sorts by property name. + * @param {string|int} property + * @returns {Function} + */ + dynamicSort: function (property) { + var sortOrder = 1; + if (property[0] === "-") { + sortOrder = -1; + property = property.substr(1); + } + return function (a, b) { + var result = (a[property].toLowerCase() < b[property].toLowerCase()) ? -1 : (a[property].toLowerCase() > b[property].toLowerCase()) ? 1 : 0; + return result * sortOrder; + } + } +}; \ No newline at end of file diff --git a/js/data/ResponseHandler.js b/js/data/ResponseHandler.js index a155466..0a2b823 100644 --- a/js/data/ResponseHandler.js +++ b/js/data/ResponseHandler.js @@ -2,7 +2,7 @@ * ResponseHandler.js zarafa calender to ics im/exporter * * Author: Christoph Haas - * Copyright (C) 2012-2013 Christoph Haas + * Copyright (C) 2012-2016 Christoph Haas * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ - + /** * ResponseHandler * @@ -38,46 +38,46 @@ Zarafa.plugins.calendarimporter.data.ResponseHandler = Ext.extend(Zarafa.core.da * @cfg {Function} successCallback The function which * will be called after success request. */ - successCallback : null, - + successCallback: null, + /** * Call the successCallback callback function. * @param {Object} response Object contained the response data. */ - doExport : function(response) { + doExport: function (response) { this.successCallback(response); }, - + /** * Call the successCallback callback function. * @param {Object} response Object contained the response data. */ - doList : function(response) { + doLoad: function (response) { this.successCallback(response); }, - + /** * Call the successCallback callback function. * @param {Object} response Object contained the response data. */ - doImport : function(response) { + doImport: function (response) { this.successCallback(response); }, - + /** * Call the successCallback callback function. * @param {Object} response Object contained the response data. */ - doAttachmentpath : function(response) { + doImportattachment: function (response) { this.successCallback(response); }, - + /** * In case exception happened on server, server will return * exception response with the code of exception. * @param {Object} response Object contained the response data. */ - doError: function(response) { + doError: function (response) { alert("error response code: " + response.error.info.code); } }); diff --git a/js/data/timezones.js b/js/data/timezones.js index 9fb34c7..3e36004 100644 --- a/js/data/timezones.js +++ b/js/data/timezones.js @@ -2,7 +2,7 @@ * timezones.js zarafa calender to ics im/exporter * * Author: Christoph Haas - * Copyright (C) 2012-2013 Christoph Haas + * Copyright (C) 2012-2016 Christoph Haas * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -24,742 +24,742 @@ * Timezone class * * This class can handle all our timezone operations and conversions. - */ -Ext.namespace("Zarafa.plugins.calendarimporter.data"); + */ +Ext.namespace("Zarafa.plugins.calendarimporter.data"); Zarafa.plugins.calendarimporter.data.Timezones = Ext.extend(Object, { - store : [ - ['Pacific/Midway','(UTC -11:00) Midway, Niue, Pago Pago', -660], - ['Pacific/Fakaofo','(UTC -10:00) Adak, Fakaofo, Honolulu, Johnston, Rarotonga, Tahiti', -600], - ['Pacific/Marquesas','(UTC -09:30) Marquesas', -570], - ['America/Anchorage','(UTC -09:00) Gambier, Anchorage, Juneau, Nome, Sitka, Yakutat', -540], - ['America/Dawson','(UTC -08:00) Dawson, Los Angeles, Tijuana, Vancouver, Whitehorse, Santa Isabel, Metlakatla, Pitcairn', -480], - ['America/Dawson_Creek','(UTC -07:00) Dawson Creek, Hermosillo, Phoenix, Chihuahua, Mazatlan, Boise, Cambridge Bay, Denver, Edmonton, Inuvik, Ojinaga, Shiprock, Yellowknife', -420], - ['America/Chicago','(UTC -06:00) Beulah, Center, Chicago, Knox, Matamoros, Menominee, New Salem, Rainy River, Rankin Inlet, Resolute, Tell City, Winnipeg', -360], - ['America/Belize','(UTC -06:00) Belize, Costa Rica, El Salvador, Galapagos, Guatemala, Managua, Regina, Swift Current, Tegucigalpa', -360], - ['Pacific/Easter','(UTC -06:00) Easter', -360], - ['America/Bahia_Banderas','(UTC -06:00) Bahia Banderas, Cancun, Merida, Mexico City, Monterrey', -360], - ['America/Detroit','(UTC -05:00) Detroit, Grand Turk, Indianapolis, Iqaluit, Louisville, Marengo, Monticello, Montreal, Nassau, New York, Nipigon, Pangnirtung, Petersburg, Thunder Bay, Toronto, Vevay, Vincennes, Winamac', -300], - ['America/Atikokan','(UTC -05:00) Atikokan, Bogota, Cayman, Guayaquil, Jamaica, Lima, Panama, Port-au-Prince', -300], - ['America/Havana','(UTC -05:00) Havana', -300], - ['America/Caracas','(UTC -04:30) Caracas', -270], - ['America/Glace_Bay','(UTC -04:00) Bermuda, Glace Bay, Goose Bay, Halifax, Moncton, Thule', -240], - ['Atlantic/Stanley','(UTC -04:00) Stanley', -240], - ['America/Santiago','(UTC -04:00) Palmer, Santiago', -240], - ['America/Anguilla','(UTC -04:00) Anguilla, Antigua, Aruba, Barbados, Blanc-Sablon, Boa Vista, Curacao, Dominica, Eirunepe, Grenada, Guadeloupe, Guyana, Kralendijk, La Paz, Lower Princes, Manaus, Marigot, Martinique, Montserrat, Port of Spain, Porto Velho, Puerto Rico, Rio Branco, Santo Domingo, St Barthelemy, St Kitts, St Lucia, St Thomas, St Vincent, Tortola', -240], - ['America/Campo_Grande','(UTC -04:00) Campo Grande, Cuiaba', -240], - ['America/Asuncion','(UTC -04:00) Asuncion', -240], - ['America/St_Johns','(UTC -03:30) St Johns', -210], - ['America/Sao_Paulo','(UTC -03:00) Sao Paulo', -180], - ['America/Araguaina','(UTC -03:00) Araguaina, Bahia, Belem, Buenos Aires, Catamarca, Cayenne, Cordoba, Fortaleza, Jujuy, La Rioja, Maceio, Mendoza, Paramaribo, Recife, Rio Gallegos, Rothera, Salta, San Juan, Santarem, Tucuman, Ushuaia', -180], - ['America/Montevideo','(UTC -03:00) Montevideo', -180], - ['America/Godthab','(UTC -03:00) Godthab', -180], - ['America/Argentina/San_Luis','(UTC -03:00) San Luis', -180], - ['America/Miquelon','(UTC -03:00) Miquelon', -180], - ['America/Noronha','(UTC -02:00) Noronha, South Georgia', -120], - ['Atlantic/Cape_Verde','(UTC -01:00) Cape Verde', -60], - ['America/Scoresbysund','(UTC -01:00) Azores, Scoresbysund', -60], - ['Atlantic/Canary','(UTC) Canary, Dublin, Faroe, Guernsey, Isle of Man, Jersey, Lisbon, London, Madeira', 0], - ['Africa/Abidjan','(UTC) Abidjan, Accra, Bamako, Banjul, Bissau, Casablanca, Conakry, Dakar, Danmarkshavn, El Aaiun, Freetown, Lome, Monrovia, Nouakchott, Ouagadougou, Reykjavik, Sao Tome, St Helena', 0], - ['Africa/Algiers','(UTC +01:00) Algiers, Bangui, Brazzaville, Douala, Kinshasa, Lagos, Libreville, Luanda, Malabo, Ndjamena, Niamey, Porto-Novo, Tunis', 60], - ['Europe/Vienna','(UTC +01:00) Amsterdam, Andorra, Belgrade, Berlin, Bratislava, Brussels, Budapest, Ceuta, Copenhagen, Gibraltar, Ljubljana, Longyearbyen, Luxembourg, Madrid, Malta, Monaco, Oslo, Paris, Podgorica, Prague, Rome, San Marino, Sarajevo, Skopje, Stockholm, Tirane, Vaduz, Vatican, Vienna, Warsaw, Zagreb, Zurich', 60], - ['Africa/Windhoek','(UTC +01:00) Windhoek', 60], - ['Asia/Damascus','(UTC +02:00) Damascus', 120], - ['Asia/Beirut','(UTC +02:00) Beirut', 120], - ['Asia/Jerusalem','(UTC +02:00) Jerusalem', 120], - ['Asia/Nicosia','(UTC +02:00) Athens, Bucharest, Chisinau, Helsinki, Istanbul, Mariehamn, Nicosia, Riga, Sofia, Tallinn, Vilnius', 120], - ['Africa/Blantyre','(UTC +02:00) Blantyre, Bujumbura, Cairo, Gaborone, Gaza, Harare, Hebron, Johannesburg, Kigali, Lubumbashi, Lusaka, Maputo, Maseru, Mbabane, Tripoli', 120], - ['Asia/Amman','(UTC +02:00) Amman', 120], - ['Africa/Addis_Ababa','(UTC +03:00) Addis Ababa, Aden, Antananarivo, Asmara, Baghdad, Bahrain, Comoro, Dar es Salaam, Djibouti, Juba, Kaliningrad, Kampala, Khartoum, Kiev, Kuwait, Mayotte, Minsk, Mogadishu, Nairobi, Qatar, Riyadh, Simferopol, Syowa, Uzhgorod, Zaporozhye', 180], - ['Asia/Tehran','(UTC +03:30) Tehran', 210], - ['Asia/Yerevan','(UTC +04:00) Yerevan', 240], - ['Asia/Dubai','(UTC +04:00) Dubai, Mahe, Mauritius, Moscow, Muscat, Reunion, Samara, Tbilisi, Volgograd', 240], - ['Asia/Baku','(UTC +04:00) Baku', 240], - ['Asia/Kabul','(UTC +04:30) Kabul', 270], - ['Antarctica/Mawson','(UTC +05:00) Aqtau, Aqtobe, Ashgabat, Dushanbe, Karachi, Kerguelen, Maldives, Mawson, Oral, Samarkand, Tashkent', 300], - ['Asia/Colombo','(UTC +05:30) Colombo, Kolkata', 330], - ['Asia/Kathmandu','(UTC +05:45) Kathmandu', 345], - ['Antarctica/Vostok','(UTC +06:00) Almaty, Bishkek, Chagos, Dhaka, Qyzylorda, Thimphu, Vostok, Yekaterinburg', 360], - ['Asia/Rangoon','(UTC +06:30) Cocos, Rangoon', 390], - ['Antarctica/Davis','(UTC +07:00) Bangkok, Christmas, Davis, Ho Chi Minh, Hovd, Jakarta, Novokuznetsk, Novosibirsk, Omsk, Phnom Penh, Pontianak, Vientiane', 420], - ['Antarctica/Casey','(UTC +08:00) Brunei, Casey, Choibalsan, Chongqing, Harbin, Hong Kong, Kashgar, Krasnoyarsk, Kuala Lumpur, Kuching, Macau, Makassar, Manila, Perth, Shanghai, Singapore, Taipei, Ulaanbaatar, Urumqi', 480], - ['Australia/Eucla','(UTC +08:45) Eucla', 525], - ['Asia/Dili','(UTC +09:00) Dili, Irkutsk, Jayapura, Palau, Pyongyang, Seoul, Tokyo', 540], - ['Australia/Adelaide','(UTC +09:30) Adelaide, Broken Hill', 570], - ['Australia/Darwin','(UTC +09:30) Darwin', 570], - ['Antarctica/DumontDUrville','(UTC +10:00) Brisbane, Chuuk, DumontDUrville, Guam, Lindeman, Port Moresby, Saipan, Yakutsk', 600], - ['Australia/Currie','(UTC +10:00) Currie, Hobart, Melbourne, Sydney', 600], - ['Australia/Lord_Howe','(UTC +10:30) Lord Howe', 630], - ['Antarctica/Macquarie','(UTC +11:00) Efate, Guadalcanal, Kosrae, Macquarie, Noumea, Pohnpei, Sakhalin, Vladivostok', 660], - ['Pacific/Norfolk','(UTC +11:30) Norfolk', 690], - ['Antarctica/McMurdo','(UTC +12:00) Auckland, McMurdo, South Pole', 720], - ['Asia/Anadyr','(UTC +12:00) Anadyr, Fiji, Funafuti, Kamchatka, Kwajalein, Magadan, Majuro, Nauru, Tarawa, Wake, Wallis', 720], - ['Pacific/Chatham','(UTC +12:45) Chatham', 765], - ['Pacific/Enderbury','(UTC +13:00) Enderbury, Tongatapu', 780], - ['Pacific/Apia','(UTC +13:00) Apia', 780], - ['Pacific/Kiritimati','(UTC +14:00) Kiritimati', 840] + store: [ + ['Pacific/Midway', '(UTC -11:00) Midway, Niue, Pago Pago', -660], + ['Pacific/Fakaofo', '(UTC -10:00) Adak, Fakaofo, Honolulu, Johnston, Rarotonga, Tahiti', -600], + ['Pacific/Marquesas', '(UTC -09:30) Marquesas', -570], + ['America/Anchorage', '(UTC -09:00) Gambier, Anchorage, Juneau, Nome, Sitka, Yakutat', -540], + ['America/Dawson', '(UTC -08:00) Dawson, Los Angeles, Tijuana, Vancouver, Whitehorse, Santa Isabel, Metlakatla, Pitcairn', -480], + ['America/Dawson_Creek', '(UTC -07:00) Dawson Creek, Hermosillo, Phoenix, Chihuahua, Mazatlan, Boise, Cambridge Bay, Denver, Edmonton, Inuvik, Ojinaga, Shiprock, Yellowknife', -420], + ['America/Chicago', '(UTC -06:00) Beulah, Center, Chicago, Knox, Matamoros, Menominee, New Salem, Rainy River, Rankin Inlet, Resolute, Tell City, Winnipeg', -360], + ['America/Belize', '(UTC -06:00) Belize, Costa Rica, El Salvador, Galapagos, Guatemala, Managua, Regina, Swift Current, Tegucigalpa', -360], + ['Pacific/Easter', '(UTC -06:00) Easter', -360], + ['America/Bahia_Banderas', '(UTC -06:00) Bahia Banderas, Cancun, Merida, Mexico City, Monterrey', -360], + ['America/Detroit', '(UTC -05:00) Detroit, Grand Turk, Indianapolis, Iqaluit, Louisville, Marengo, Monticello, Montreal, Nassau, New York, Nipigon, Pangnirtung, Petersburg, Thunder Bay, Toronto, Vevay, Vincennes, Winamac', -300], + ['America/Atikokan', '(UTC -05:00) Atikokan, Bogota, Cayman, Guayaquil, Jamaica, Lima, Panama, Port-au-Prince', -300], + ['America/Havana', '(UTC -05:00) Havana', -300], + ['America/Caracas', '(UTC -04:30) Caracas', -270], + ['America/Glace_Bay', '(UTC -04:00) Bermuda, Glace Bay, Goose Bay, Halifax, Moncton, Thule', -240], + ['Atlantic/Stanley', '(UTC -04:00) Stanley', -240], + ['America/Santiago', '(UTC -04:00) Palmer, Santiago', -240], + ['America/Anguilla', '(UTC -04:00) Anguilla, Antigua, Aruba, Barbados, Blanc-Sablon, Boa Vista, Curacao, Dominica, Eirunepe, Grenada, Guadeloupe, Guyana, Kralendijk, La Paz, Lower Princes, Manaus, Marigot, Martinique, Montserrat, Port of Spain, Porto Velho, Puerto Rico, Rio Branco, Santo Domingo, St Barthelemy, St Kitts, St Lucia, St Thomas, St Vincent, Tortola', -240], + ['America/Campo_Grande', '(UTC -04:00) Campo Grande, Cuiaba', -240], + ['America/Asuncion', '(UTC -04:00) Asuncion', -240], + ['America/St_Johns', '(UTC -03:30) St Johns', -210], + ['America/Sao_Paulo', '(UTC -03:00) Sao Paulo', -180], + ['America/Araguaina', '(UTC -03:00) Araguaina, Bahia, Belem, Buenos Aires, Catamarca, Cayenne, Cordoba, Fortaleza, Jujuy, La Rioja, Maceio, Mendoza, Paramaribo, Recife, Rio Gallegos, Rothera, Salta, San Juan, Santarem, Tucuman, Ushuaia', -180], + ['America/Montevideo', '(UTC -03:00) Montevideo', -180], + ['America/Godthab', '(UTC -03:00) Godthab', -180], + ['America/Argentina/San_Luis', '(UTC -03:00) San Luis', -180], + ['America/Miquelon', '(UTC -03:00) Miquelon', -180], + ['America/Noronha', '(UTC -02:00) Noronha, South Georgia', -120], + ['Atlantic/Cape_Verde', '(UTC -01:00) Cape Verde', -60], + ['America/Scoresbysund', '(UTC -01:00) Azores, Scoresbysund', -60], + ['Atlantic/Canary', '(UTC) Canary, Dublin, Faroe, Guernsey, Isle of Man, Jersey, Lisbon, London, Madeira', 0], + ['Africa/Abidjan', '(UTC) Abidjan, Accra, Bamako, Banjul, Bissau, Casablanca, Conakry, Dakar, Danmarkshavn, El Aaiun, Freetown, Lome, Monrovia, Nouakchott, Ouagadougou, Reykjavik, Sao Tome, St Helena', 0], + ['Africa/Algiers', '(UTC +01:00) Algiers, Bangui, Brazzaville, Douala, Kinshasa, Lagos, Libreville, Luanda, Malabo, Ndjamena, Niamey, Porto-Novo, Tunis', 60], + ['Europe/Vienna', '(UTC +01:00) Amsterdam, Andorra, Belgrade, Berlin, Bratislava, Brussels, Budapest, Ceuta, Copenhagen, Gibraltar, Ljubljana, Longyearbyen, Luxembourg, Madrid, Malta, Monaco, Oslo, Paris, Podgorica, Prague, Rome, San Marino, Sarajevo, Skopje, Stockholm, Tirane, Vaduz, Vatican, Vienna, Warsaw, Zagreb, Zurich', 60], + ['Africa/Windhoek', '(UTC +01:00) Windhoek', 60], + ['Asia/Damascus', '(UTC +02:00) Damascus', 120], + ['Asia/Beirut', '(UTC +02:00) Beirut', 120], + ['Asia/Jerusalem', '(UTC +02:00) Jerusalem', 120], + ['Asia/Nicosia', '(UTC +02:00) Athens, Bucharest, Chisinau, Helsinki, Istanbul, Mariehamn, Nicosia, Riga, Sofia, Tallinn, Vilnius', 120], + ['Africa/Blantyre', '(UTC +02:00) Blantyre, Bujumbura, Cairo, Gaborone, Gaza, Harare, Hebron, Johannesburg, Kigali, Lubumbashi, Lusaka, Maputo, Maseru, Mbabane, Tripoli', 120], + ['Asia/Amman', '(UTC +02:00) Amman', 120], + ['Africa/Addis_Ababa', '(UTC +03:00) Addis Ababa, Aden, Antananarivo, Asmara, Baghdad, Bahrain, Comoro, Dar es Salaam, Djibouti, Juba, Kaliningrad, Kampala, Khartoum, Kiev, Kuwait, Mayotte, Minsk, Mogadishu, Nairobi, Qatar, Riyadh, Simferopol, Syowa, Uzhgorod, Zaporozhye', 180], + ['Asia/Tehran', '(UTC +03:30) Tehran', 210], + ['Asia/Yerevan', '(UTC +04:00) Yerevan', 240], + ['Asia/Dubai', '(UTC +04:00) Dubai, Mahe, Mauritius, Moscow, Muscat, Reunion, Samara, Tbilisi, Volgograd', 240], + ['Asia/Baku', '(UTC +04:00) Baku', 240], + ['Asia/Kabul', '(UTC +04:30) Kabul', 270], + ['Antarctica/Mawson', '(UTC +05:00) Aqtau, Aqtobe, Ashgabat, Dushanbe, Karachi, Kerguelen, Maldives, Mawson, Oral, Samarkand, Tashkent', 300], + ['Asia/Colombo', '(UTC +05:30) Colombo, Kolkata', 330], + ['Asia/Kathmandu', '(UTC +05:45) Kathmandu', 345], + ['Antarctica/Vostok', '(UTC +06:00) Almaty, Bishkek, Chagos, Dhaka, Qyzylorda, Thimphu, Vostok, Yekaterinburg', 360], + ['Asia/Rangoon', '(UTC +06:30) Cocos, Rangoon', 390], + ['Antarctica/Davis', '(UTC +07:00) Bangkok, Christmas, Davis, Ho Chi Minh, Hovd, Jakarta, Novokuznetsk, Novosibirsk, Omsk, Phnom Penh, Pontianak, Vientiane', 420], + ['Antarctica/Casey', '(UTC +08:00) Brunei, Casey, Choibalsan, Chongqing, Harbin, Hong Kong, Kashgar, Krasnoyarsk, Kuala Lumpur, Kuching, Macau, Makassar, Manila, Perth, Shanghai, Singapore, Taipei, Ulaanbaatar, Urumqi', 480], + ['Australia/Eucla', '(UTC +08:45) Eucla', 525], + ['Asia/Dili', '(UTC +09:00) Dili, Irkutsk, Jayapura, Palau, Pyongyang, Seoul, Tokyo', 540], + ['Australia/Adelaide', '(UTC +09:30) Adelaide, Broken Hill', 570], + ['Australia/Darwin', '(UTC +09:30) Darwin', 570], + ['Antarctica/DumontDUrville', '(UTC +10:00) Brisbane, Chuuk, DumontDUrville, Guam, Lindeman, Port Moresby, Saipan, Yakutsk', 600], + ['Australia/Currie', '(UTC +10:00) Currie, Hobart, Melbourne, Sydney', 600], + ['Australia/Lord_Howe', '(UTC +10:30) Lord Howe', 630], + ['Antarctica/Macquarie', '(UTC +11:00) Efate, Guadalcanal, Kosrae, Macquarie, Noumea, Pohnpei, Sakhalin, Vladivostok', 660], + ['Pacific/Norfolk', '(UTC +11:30) Norfolk', 690], + ['Antarctica/McMurdo', '(UTC +12:00) Auckland, McMurdo, South Pole', 720], + ['Asia/Anadyr', '(UTC +12:00) Anadyr, Fiji, Funafuti, Kamchatka, Kwajalein, Magadan, Majuro, Nauru, Tarawa, Wake, Wallis', 720], + ['Pacific/Chatham', '(UTC +12:45) Chatham', 765], + ['Pacific/Enderbury', '(UTC +13:00) Enderbury, Tongatapu', 780], + ['Pacific/Apia', '(UTC +13:00) Apia', 780], + ['Pacific/Kiritimati', '(UTC +14:00) Kiritimati', 840] ], - + /* map all citys to the above timezones */ - map : { + map : { /*-11:00*/ - 'Etc/GMT+11' : 'Pacific/Midway', - 'Pacific/Midway' : 'Pacific/Midway', - 'Pacific/Niue' : 'Pacific/Midway', - 'Pacific/Pago_Pago' : 'Pacific/Midway', - 'Pacific/Samoa' : 'Pacific/Midway', - 'US/Samoa' : 'Pacific/Midway', + 'Etc/GMT+11' : 'Pacific/Midway', + 'Pacific/Midway' : 'Pacific/Midway', + 'Pacific/Niue' : 'Pacific/Midway', + 'Pacific/Pago_Pago' : 'Pacific/Midway', + 'Pacific/Samoa' : 'Pacific/Midway', + 'US/Samoa' : 'Pacific/Midway', /*-10:00*/ - 'America/Adak' : 'Pacific/Fakaofo', - 'America/Atka' : 'Pacific/Fakaofo', - 'Etc/GMT+10' : 'Pacific/Fakaofo', - 'HST' : 'Pacific/Fakaofo', - 'Pacific/Honolulu' : 'Pacific/Fakaofo', - 'Pacific/Johnston' : 'Pacific/Fakaofo', - 'Pacific/Rarotonga' : 'Pacific/Fakaofo', - 'Pacific/Tahiti' : 'Pacific/Fakaofo', - 'SystemV/HST10' : 'Pacific/Fakaofo', - 'US/Aleutian' : 'Pacific/Fakaofo', - 'US/Hawaii' : 'Pacific/Fakaofo', + 'America/Adak' : 'Pacific/Fakaofo', + 'America/Atka' : 'Pacific/Fakaofo', + 'Etc/GMT+10' : 'Pacific/Fakaofo', + 'HST' : 'Pacific/Fakaofo', + 'Pacific/Honolulu' : 'Pacific/Fakaofo', + 'Pacific/Johnston' : 'Pacific/Fakaofo', + 'Pacific/Rarotonga' : 'Pacific/Fakaofo', + 'Pacific/Tahiti' : 'Pacific/Fakaofo', + 'SystemV/HST10' : 'Pacific/Fakaofo', + 'US/Aleutian' : 'Pacific/Fakaofo', + 'US/Hawaii' : 'Pacific/Fakaofo', /*-9:30*/ - 'Pacific/Marquesas' : 'Pacific/Marquesas', + 'Pacific/Marquesas' : 'Pacific/Marquesas', /*-9:00*/ - 'AST' : 'America/Anchorage', - 'America/Anchorage' : 'America/Anchorage', - 'America/Juneau' : 'America/Anchorage', - 'America/Nome' : 'America/Anchorage', - 'America/Sitka' : 'America/Anchorage', - 'America/Yakutat' : 'America/Anchorage', - 'Etc/GMT+9' : 'America/Anchorage', - 'Pacific/Gambier' : 'America/Anchorage', - 'SystemV/YST9' : 'America/Anchorage', - 'SystemV/YST9YDT' : 'America/Anchorage', - 'US/Alaska' : 'America/Anchorage', + 'AST' : 'America/Anchorage', + 'America/Anchorage' : 'America/Anchorage', + 'America/Juneau' : 'America/Anchorage', + 'America/Nome' : 'America/Anchorage', + 'America/Sitka' : 'America/Anchorage', + 'America/Yakutat' : 'America/Anchorage', + 'Etc/GMT+9' : 'America/Anchorage', + 'Pacific/Gambier' : 'America/Anchorage', + 'SystemV/YST9' : 'America/Anchorage', + 'SystemV/YST9YDT' : 'America/Anchorage', + 'US/Alaska' : 'America/Anchorage', /*-8:00*/ - 'America/Dawson' : 'America/Dawson', - 'America/Ensenada' : 'America/Dawson', - 'America/Los_Angeles' : 'America/Dawson', - 'America/Metlakatla' : 'America/Dawson', - 'America/Santa_Isabel' : 'America/Dawson', - 'America/Tijuana' : 'America/Dawson', - 'America/Vancouver' : 'America/Dawson', - 'America/Whitehorse' : 'America/Dawson', - 'Canada/Pacific' : 'America/Dawson', - 'Canada/Yukon' : 'America/Dawson', - 'Etc/GMT+8' : 'America/Dawson', - 'Mexico/BajaNorte' : 'America/Dawson', - 'PST' : 'America/Dawson', - 'PST8PDT' : 'America/Dawson', - 'Pacific/Pitcairn' : 'America/Dawson', - 'SystemV/PST8' : 'America/Dawson', - 'SystemV/PST8PDT' : 'America/Dawson', - 'US/Pacific' : 'America/Dawson', - 'US/Pacific-New' : 'America/Dawson', + 'America/Dawson' : 'America/Dawson', + 'America/Ensenada' : 'America/Dawson', + 'America/Los_Angeles' : 'America/Dawson', + 'America/Metlakatla' : 'America/Dawson', + 'America/Santa_Isabel' : 'America/Dawson', + 'America/Tijuana' : 'America/Dawson', + 'America/Vancouver' : 'America/Dawson', + 'America/Whitehorse' : 'America/Dawson', + 'Canada/Pacific' : 'America/Dawson', + 'Canada/Yukon' : 'America/Dawson', + 'Etc/GMT+8' : 'America/Dawson', + 'Mexico/BajaNorte' : 'America/Dawson', + 'PST' : 'America/Dawson', + 'PST8PDT' : 'America/Dawson', + 'Pacific/Pitcairn' : 'America/Dawson', + 'SystemV/PST8' : 'America/Dawson', + 'SystemV/PST8PDT' : 'America/Dawson', + 'US/Pacific' : 'America/Dawson', + 'US/Pacific-New' : 'America/Dawson', /*-7:00*/ - 'America/Boise' : 'America/Dawson_Creek', - 'America/Cambridge_Bay' : 'America/Dawson_Creek', - 'America/Chihuahua' : 'America/Dawson_Creek', - 'America/Creston' : 'America/Dawson_Creek', - 'America/Dawson_Creek' : 'America/Dawson_Creek', - 'America/Denver' : 'America/Dawson_Creek', - 'America/Edmonton' : 'America/Dawson_Creek', - 'America/Hermosillo' : 'America/Dawson_Creek', - 'America/Inuvik' : 'America/Dawson_Creek', - 'America/Mazatlan' : 'America/Dawson_Creek', - 'America/Ojinaga' : 'America/Dawson_Creek', - 'America/Phoenix' : 'America/Dawson_Creek', - 'America/Shiprock' : 'America/Dawson_Creek', - 'America/Yellowknife' : 'America/Dawson_Creek', - 'Canada/Mountain' : 'America/Dawson_Creek', - 'Etc/GMT+7' : 'America/Dawson_Creek', - 'MST' : 'America/Dawson_Creek', - 'MST7MDT' : 'America/Dawson_Creek', - 'Mexico/BajaSur' : 'America/Dawson_Creek', - 'Navajo' : 'America/Dawson_Creek', - 'PNT' : 'America/Dawson_Creek', - 'SystemV/MST7' : 'America/Dawson_Creek', - 'SystemV/MST7MDT' : 'America/Dawson_Creek', - 'US/Arizona' : 'America/Dawson_Creek', - 'US/Mountain' : 'America/Dawson_Creek', + 'America/Boise' : 'America/Dawson_Creek', + 'America/Cambridge_Bay' : 'America/Dawson_Creek', + 'America/Chihuahua' : 'America/Dawson_Creek', + 'America/Creston' : 'America/Dawson_Creek', + 'America/Dawson_Creek' : 'America/Dawson_Creek', + 'America/Denver' : 'America/Dawson_Creek', + 'America/Edmonton' : 'America/Dawson_Creek', + 'America/Hermosillo' : 'America/Dawson_Creek', + 'America/Inuvik' : 'America/Dawson_Creek', + 'America/Mazatlan' : 'America/Dawson_Creek', + 'America/Ojinaga' : 'America/Dawson_Creek', + 'America/Phoenix' : 'America/Dawson_Creek', + 'America/Shiprock' : 'America/Dawson_Creek', + 'America/Yellowknife' : 'America/Dawson_Creek', + 'Canada/Mountain' : 'America/Dawson_Creek', + 'Etc/GMT+7' : 'America/Dawson_Creek', + 'MST' : 'America/Dawson_Creek', + 'MST7MDT' : 'America/Dawson_Creek', + 'Mexico/BajaSur' : 'America/Dawson_Creek', + 'Navajo' : 'America/Dawson_Creek', + 'PNT' : 'America/Dawson_Creek', + 'SystemV/MST7' : 'America/Dawson_Creek', + 'SystemV/MST7MDT' : 'America/Dawson_Creek', + 'US/Arizona' : 'America/Dawson_Creek', + 'US/Mountain' : 'America/Dawson_Creek', /*-6:00*/ - 'America/Bahia_Banderas' : 'America/Chicago', - 'America/Belize' : 'America/Chicago', - 'America/Cancun' : 'America/Chicago', - 'America/Chicago' : 'America/Chicago', - 'America/Costa_Rica' : 'America/Chicago', - 'America/El_Salvador' : 'America/Chicago', - 'America/Guatemala' : 'America/Chicago', - 'America/Indiana/Knox' : 'America/Chicago', - 'America/Indiana/Tell_City' : 'America/Chicago', - 'America/Knox_IN' : 'America/Chicago', - 'America/Managua' : 'America/Chicago', - 'America/Matamoros' : 'America/Chicago', - 'America/Menominee' : 'America/Chicago', - 'America/Merida' : 'America/Chicago', - 'America/Mexico_City' : 'America/Chicago', - 'America/Monterrey' : 'America/Chicago', - 'America/North_Dakota/Beulah' : 'America/Chicago', - 'America/North_Dakota/Center' : 'America/Chicago', - 'America/North_Dakota/New_Salem' : 'America/Chicago', - 'America/Rainy_River' : 'America/Chicago', - 'America/Rankin_Inlet' : 'America/Chicago', - 'America/Regina' : 'America/Chicago', - 'America/Resolute' : 'America/Chicago', - 'America/Swift_Current' : 'America/Chicago', - 'America/Tegucigalpa' : 'America/Chicago', - 'America/Winnipeg' : 'America/Chicago', - 'CST' : 'America/Chicago', - 'CST6CDT' : 'America/Chicago', - 'Canada/Central' : 'America/Chicago', - 'Canada/East-Saskatchewan' : 'America/Chicago', - 'Canada/Saskatchewan' : 'America/Chicago', - 'Chile/EasterIsland' : 'America/Chicago', - 'Etc/GMT+6' : 'America/Chicago', - 'Mexico/General' : 'America/Chicago', - 'Pacific/Easter' : 'America/Chicago', - 'Pacific/Galapagos' : 'America/Chicago', - 'SystemV/CST6' : 'America/Chicago', - 'SystemV/CST6CDT' : 'America/Chicago', - 'US/Central' : 'America/Chicago', - 'US/Indiana-Starke' : 'America/Chicago', + 'America/Bahia_Banderas' : 'America/Chicago', + 'America/Belize' : 'America/Chicago', + 'America/Cancun' : 'America/Chicago', + 'America/Chicago' : 'America/Chicago', + 'America/Costa_Rica' : 'America/Chicago', + 'America/El_Salvador' : 'America/Chicago', + 'America/Guatemala' : 'America/Chicago', + 'America/Indiana/Knox' : 'America/Chicago', + 'America/Indiana/Tell_City' : 'America/Chicago', + 'America/Knox_IN' : 'America/Chicago', + 'America/Managua' : 'America/Chicago', + 'America/Matamoros' : 'America/Chicago', + 'America/Menominee' : 'America/Chicago', + 'America/Merida' : 'America/Chicago', + 'America/Mexico_City' : 'America/Chicago', + 'America/Monterrey' : 'America/Chicago', + 'America/North_Dakota/Beulah' : 'America/Chicago', + 'America/North_Dakota/Center' : 'America/Chicago', + 'America/North_Dakota/New_Salem' : 'America/Chicago', + 'America/Rainy_River' : 'America/Chicago', + 'America/Rankin_Inlet' : 'America/Chicago', + 'America/Regina' : 'America/Chicago', + 'America/Resolute' : 'America/Chicago', + 'America/Swift_Current' : 'America/Chicago', + 'America/Tegucigalpa' : 'America/Chicago', + 'America/Winnipeg' : 'America/Chicago', + 'CST' : 'America/Chicago', + 'CST6CDT' : 'America/Chicago', + 'Canada/Central' : 'America/Chicago', + 'Canada/East-Saskatchewan' : 'America/Chicago', + 'Canada/Saskatchewan' : 'America/Chicago', + 'Chile/EasterIsland' : 'America/Chicago', + 'Etc/GMT+6' : 'America/Chicago', + 'Mexico/General' : 'America/Chicago', + 'Pacific/Easter' : 'America/Chicago', + 'Pacific/Galapagos' : 'America/Chicago', + 'SystemV/CST6' : 'America/Chicago', + 'SystemV/CST6CDT' : 'America/Chicago', + 'US/Central' : 'America/Chicago', + 'US/Indiana-Starke' : 'America/Chicago', /*-5:00*/ - 'America/Atikokan' : 'America/Detroit', - 'America/Bogota' : 'America/Detroit', - 'America/Cayman' : 'America/Detroit', - 'America/Coral_Harbour' : 'America/Detroit', - 'America/Detroit' : 'America/Detroit', - 'America/Fort_Wayne' : 'America/Detroit', - 'America/Grand_Turk' : 'America/Detroit', - 'America/Guayaquil' : 'America/Detroit', - 'America/Havana' : 'America/Detroit', - 'America/Indiana/Indianapolis' : 'America/Detroit', - 'America/Indiana/Marengo' : 'America/Detroit', - 'America/Indiana/Petersburg' : 'America/Detroit', - 'America/Indiana/Vevay' : 'America/Detroit', - 'America/Indiana/Vincennes' : 'America/Detroit', - 'America/Indiana/Winamac' : 'America/Detroit', - 'America/Indianapolis' : 'America/Detroit', - 'America/Iqaluit' : 'America/Detroit', - 'America/Jamaica' : 'America/Detroit', - 'America/Kentucky/Louisville' : 'America/Detroit', - 'America/Kentucky/Monticello' : 'America/Detroit', - 'America/Lima' : 'America/Detroit', - 'America/Louisville' : 'America/Detroit', - 'America/Montreal' : 'America/Detroit', - 'America/Nassau' : 'America/Detroit', - 'America/New_York' : 'America/Detroit', - 'America/Nipigon' : 'America/Detroit', - 'America/Panama' : 'America/Detroit', - 'America/Pangnirtung' : 'America/Detroit', - 'America/Port-au-Prince' : 'America/Detroit', - 'America/Thunder_Bay' : 'America/Detroit', - 'America/Toronto' : 'America/Detroit', - 'Canada/Eastern' : 'America/Detroit', - 'Cuba' : 'America/Detroit', - 'EST' : 'America/Detroit', - 'EST5EDT' : 'America/Detroit', - 'Etc/GMT+5' : 'America/Detroit', - 'IET' : 'America/Detroit', - 'Jamaica' : 'America/Detroit', - 'SystemV/EST5' : 'America/Detroit', - 'SystemV/EST5EDT' : 'America/Detroit', - 'US/East-Indiana' : 'America/Detroit', - 'US/Eastern' : 'America/Detroit', - 'US/Michigan' : 'America/Detroit', + 'America/Atikokan' : 'America/Detroit', + 'America/Bogota' : 'America/Detroit', + 'America/Cayman' : 'America/Detroit', + 'America/Coral_Harbour' : 'America/Detroit', + 'America/Detroit' : 'America/Detroit', + 'America/Fort_Wayne' : 'America/Detroit', + 'America/Grand_Turk' : 'America/Detroit', + 'America/Guayaquil' : 'America/Detroit', + 'America/Havana' : 'America/Detroit', + 'America/Indiana/Indianapolis' : 'America/Detroit', + 'America/Indiana/Marengo' : 'America/Detroit', + 'America/Indiana/Petersburg' : 'America/Detroit', + 'America/Indiana/Vevay' : 'America/Detroit', + 'America/Indiana/Vincennes' : 'America/Detroit', + 'America/Indiana/Winamac' : 'America/Detroit', + 'America/Indianapolis' : 'America/Detroit', + 'America/Iqaluit' : 'America/Detroit', + 'America/Jamaica' : 'America/Detroit', + 'America/Kentucky/Louisville' : 'America/Detroit', + 'America/Kentucky/Monticello' : 'America/Detroit', + 'America/Lima' : 'America/Detroit', + 'America/Louisville' : 'America/Detroit', + 'America/Montreal' : 'America/Detroit', + 'America/Nassau' : 'America/Detroit', + 'America/New_York' : 'America/Detroit', + 'America/Nipigon' : 'America/Detroit', + 'America/Panama' : 'America/Detroit', + 'America/Pangnirtung' : 'America/Detroit', + 'America/Port-au-Prince' : 'America/Detroit', + 'America/Thunder_Bay' : 'America/Detroit', + 'America/Toronto' : 'America/Detroit', + 'Canada/Eastern' : 'America/Detroit', + 'Cuba' : 'America/Detroit', + 'EST' : 'America/Detroit', + 'EST5EDT' : 'America/Detroit', + 'Etc/GMT+5' : 'America/Detroit', + 'IET' : 'America/Detroit', + 'Jamaica' : 'America/Detroit', + 'SystemV/EST5' : 'America/Detroit', + 'SystemV/EST5EDT' : 'America/Detroit', + 'US/East-Indiana' : 'America/Detroit', + 'US/Eastern' : 'America/Detroit', + 'US/Michigan' : 'America/Detroit', /*-4:30*/ - 'America/Caracas' : 'America/Caracas', + 'America/Caracas' : 'America/Caracas', /*-4:00*/ - 'America/Anguilla' : 'America/Santiago', - 'America/Antigua' : 'America/Santiago', - 'America/Argentina/San_Luis' : 'America/Santiago', - 'America/Aruba' : 'America/Santiago', - 'America/Asuncion' : 'America/Santiago', - 'America/Barbados' : 'America/Santiago', - 'America/Blanc-Sablon' : 'America/Santiago', - 'America/Boa_Vista' : 'America/Santiago', - 'America/Campo_Grande' : 'America/Santiago', - 'America/Cuiaba' : 'America/Santiago', - 'America/Curacao' : 'America/Santiago', - 'America/Dominica' : 'America/Santiago', - 'America/Eirunepe' : 'America/Santiago', - 'America/Glace_Bay' : 'America/Santiago', - 'America/Goose_Bay' : 'America/Santiago', - 'America/Grenada' : 'America/Santiago', - 'America/Guadeloupe' : 'America/Santiago', - 'America/Guyana' : 'America/Santiago', - 'America/Halifax' : 'America/Santiago', - 'America/Kralendijk' : 'America/Santiago', - 'America/La_Paz' : 'America/Santiago', - 'America/Lower_Princes' : 'America/Santiago', - 'America/Manaus' : 'America/Santiago', - 'America/Marigot' : 'America/Santiago', - 'America/Martinique' : 'America/Santiago', - 'America/Moncton' : 'America/Santiago', - 'America/Montserrat' : 'America/Santiago', - 'America/Port_of_Spain' : 'America/Santiago', - 'America/Porto_Acre' : 'America/Santiago', - 'America/Porto_Velho' : 'America/Santiago', - 'America/Puerto_Rico' : 'America/Santiago', - 'America/Rio_Branco' : 'America/Santiago', - 'America/Santiago' : 'America/Santiago', - 'America/Santo_Domingo' : 'America/Santiago', - 'America/St_Barthelemy' : 'America/Santiago', - 'America/St_Kitts' : 'America/Santiago', - 'America/St_Lucia' : 'America/Santiago', - 'America/St_Thomas' : 'America/Santiago', - 'America/St_Vincent' : 'America/Santiago', - 'America/Thule' : 'America/Santiago', - 'America/Tortola' : 'America/Santiago', - 'America/Virgin' : 'America/Santiago', - 'Antarctica/Palmer' : 'America/Santiago', - 'Atlantic/Bermuda' : 'America/Santiago', - 'Brazil/Acre' : 'America/Santiago', - 'Brazil/West' : 'America/Santiago', - 'Canada/Atlantic' : 'America/Santiago', - 'Chile/Continental' : 'America/Santiago', - 'Etc/GMT+4' : 'America/Santiago', - 'PRT' : 'America/Santiago', - 'SystemV/AST4' : 'America/Santiago', - 'SystemV/AST4ADT' : 'America/Santiago', + 'America/Anguilla' : 'America/Santiago', + 'America/Antigua' : 'America/Santiago', + 'America/Argentina/San_Luis' : 'America/Santiago', + 'America/Aruba' : 'America/Santiago', + 'America/Asuncion' : 'America/Santiago', + 'America/Barbados' : 'America/Santiago', + 'America/Blanc-Sablon' : 'America/Santiago', + 'America/Boa_Vista' : 'America/Santiago', + 'America/Campo_Grande' : 'America/Santiago', + 'America/Cuiaba' : 'America/Santiago', + 'America/Curacao' : 'America/Santiago', + 'America/Dominica' : 'America/Santiago', + 'America/Eirunepe' : 'America/Santiago', + 'America/Glace_Bay' : 'America/Santiago', + 'America/Goose_Bay' : 'America/Santiago', + 'America/Grenada' : 'America/Santiago', + 'America/Guadeloupe' : 'America/Santiago', + 'America/Guyana' : 'America/Santiago', + 'America/Halifax' : 'America/Santiago', + 'America/Kralendijk' : 'America/Santiago', + 'America/La_Paz' : 'America/Santiago', + 'America/Lower_Princes' : 'America/Santiago', + 'America/Manaus' : 'America/Santiago', + 'America/Marigot' : 'America/Santiago', + 'America/Martinique' : 'America/Santiago', + 'America/Moncton' : 'America/Santiago', + 'America/Montserrat' : 'America/Santiago', + 'America/Port_of_Spain' : 'America/Santiago', + 'America/Porto_Acre' : 'America/Santiago', + 'America/Porto_Velho' : 'America/Santiago', + 'America/Puerto_Rico' : 'America/Santiago', + 'America/Rio_Branco' : 'America/Santiago', + 'America/Santiago' : 'America/Santiago', + 'America/Santo_Domingo' : 'America/Santiago', + 'America/St_Barthelemy' : 'America/Santiago', + 'America/St_Kitts' : 'America/Santiago', + 'America/St_Lucia' : 'America/Santiago', + 'America/St_Thomas' : 'America/Santiago', + 'America/St_Vincent' : 'America/Santiago', + 'America/Thule' : 'America/Santiago', + 'America/Tortola' : 'America/Santiago', + 'America/Virgin' : 'America/Santiago', + 'Antarctica/Palmer' : 'America/Santiago', + 'Atlantic/Bermuda' : 'America/Santiago', + 'Brazil/Acre' : 'America/Santiago', + 'Brazil/West' : 'America/Santiago', + 'Canada/Atlantic' : 'America/Santiago', + 'Chile/Continental' : 'America/Santiago', + 'Etc/GMT+4' : 'America/Santiago', + 'PRT' : 'America/Santiago', + 'SystemV/AST4' : 'America/Santiago', + 'SystemV/AST4ADT' : 'America/Santiago', /*-3:30*/ - 'America/St_Johns' : 'America/St_Johns', - 'CNT' : '', - 'Canada/Newfoundland' : '', + 'America/St_Johns' : 'America/St_Johns', + 'CNT' : '', + 'Canada/Newfoundland' : '', /*-3:00*/ - 'AGT' : 'America/Sao_Paulo', - 'America/Araguaina' : 'America/Sao_Paulo', - 'America/Argentina/Buenos_Aires' : 'America/Sao_Paulo', - 'America/Argentina/Catamarca' : 'America/Sao_Paulo', - 'America/Argentina/ComodRivadavia' : 'America/Sao_Paulo', - 'America/Argentina/Cordoba' : 'America/Sao_Paulo', - 'America/Argentina/Jujuy' : 'America/Sao_Paulo', - 'America/Argentina/La_Rioja' : 'America/Sao_Paulo', - 'America/Argentina/Mendoza' : 'America/Sao_Paulo', - 'America/Argentina/Rio_Gallegos' : 'America/Sao_Paulo', - 'America/Argentina/Salta' : 'America/Sao_Paulo', - 'America/Argentina/San_Juan' : 'America/Sao_Paulo', - 'America/Argentina/Tucuman' : 'America/Sao_Paulo', - 'America/Argentina/Ushuaia' : 'America/Sao_Paulo', - 'America/Bahia' : 'America/Sao_Paulo', - 'America/Belem' : 'America/Sao_Paulo', - 'America/Buenos_Aires' : 'America/Sao_Paulo', - 'America/Catamarca' : 'America/Sao_Paulo', - 'America/Cayenne' : 'America/Sao_Paulo', - 'America/Cordoba' : 'America/Sao_Paulo', - 'America/Fortaleza' : 'America/Sao_Paulo', - 'America/Godthab' : 'America/Sao_Paulo', - 'America/Jujuy' : 'America/Sao_Paulo', - 'America/Maceio' : 'America/Sao_Paulo', - 'America/Mendoza' : 'America/Sao_Paulo', - 'America/Miquelon' : 'America/Sao_Paulo', - 'America/Montevideo' : 'America/Sao_Paulo', - 'America/Paramaribo' : 'America/Sao_Paulo', - 'America/Recife' : 'America/Sao_Paulo', - 'America/Rosario' : 'America/Sao_Paulo', - 'America/Santarem' : 'America/Sao_Paulo', - 'America/Sao_Paulo' : 'America/Sao_Paulo', - 'Antarctica/Rothera' : 'America/Sao_Paulo', - 'Atlantic/Stanley' : 'America/Sao_Paulo', - 'BET' : 'America/Sao_Paulo', - 'Brazil/East' : 'America/Sao_Paulo', - 'Etc/GMT+3' : 'America/Sao_Paulo', + 'AGT' : 'America/Sao_Paulo', + 'America/Araguaina' : 'America/Sao_Paulo', + 'America/Argentina/Buenos_Aires' : 'America/Sao_Paulo', + 'America/Argentina/Catamarca' : 'America/Sao_Paulo', + 'America/Argentina/ComodRivadavia': 'America/Sao_Paulo', + 'America/Argentina/Cordoba' : 'America/Sao_Paulo', + 'America/Argentina/Jujuy' : 'America/Sao_Paulo', + 'America/Argentina/La_Rioja' : 'America/Sao_Paulo', + 'America/Argentina/Mendoza' : 'America/Sao_Paulo', + 'America/Argentina/Rio_Gallegos' : 'America/Sao_Paulo', + 'America/Argentina/Salta' : 'America/Sao_Paulo', + 'America/Argentina/San_Juan' : 'America/Sao_Paulo', + 'America/Argentina/Tucuman' : 'America/Sao_Paulo', + 'America/Argentina/Ushuaia' : 'America/Sao_Paulo', + 'America/Bahia' : 'America/Sao_Paulo', + 'America/Belem' : 'America/Sao_Paulo', + 'America/Buenos_Aires' : 'America/Sao_Paulo', + 'America/Catamarca' : 'America/Sao_Paulo', + 'America/Cayenne' : 'America/Sao_Paulo', + 'America/Cordoba' : 'America/Sao_Paulo', + 'America/Fortaleza' : 'America/Sao_Paulo', + 'America/Godthab' : 'America/Sao_Paulo', + 'America/Jujuy' : 'America/Sao_Paulo', + 'America/Maceio' : 'America/Sao_Paulo', + 'America/Mendoza' : 'America/Sao_Paulo', + 'America/Miquelon' : 'America/Sao_Paulo', + 'America/Montevideo' : 'America/Sao_Paulo', + 'America/Paramaribo' : 'America/Sao_Paulo', + 'America/Recife' : 'America/Sao_Paulo', + 'America/Rosario' : 'America/Sao_Paulo', + 'America/Santarem' : 'America/Sao_Paulo', + 'America/Sao_Paulo' : 'America/Sao_Paulo', + 'Antarctica/Rothera' : 'America/Sao_Paulo', + 'Atlantic/Stanley' : 'America/Sao_Paulo', + 'BET' : 'America/Sao_Paulo', + 'Brazil/East' : 'America/Sao_Paulo', + 'Etc/GMT+3' : 'America/Sao_Paulo', /*-2:00*/ - 'America/Noronha' : 'America/Noronha', - 'Atlantic/South_Georgia' : 'America/Noronha', - 'Brazil/DeNoronha' : 'America/Noronha', - 'Etc/GMT+2' : 'America/Noronha', + 'America/Noronha' : 'America/Noronha', + 'Atlantic/South_Georgia' : 'America/Noronha', + 'Brazil/DeNoronha' : 'America/Noronha', + 'Etc/GMT+2' : 'America/Noronha', /*-1:00*/ - 'America/Scoresbysund' : 'Atlantic/Cape_Verde', - 'Atlantic/Azores' : 'Atlantic/Cape_Verde', - 'Atlantic/Cape_Verde' : 'Atlantic/Cape_Verde', - 'Etc/GMT+1' : 'Atlantic/Cape_Verde', + 'America/Scoresbysund' : 'Atlantic/Cape_Verde', + 'Atlantic/Azores' : 'Atlantic/Cape_Verde', + 'Atlantic/Cape_Verde' : 'Atlantic/Cape_Verde', + 'Etc/GMT+1' : 'Atlantic/Cape_Verde', /*+0:00*/ - 'Africa/Abidjan' : 'Africa/Abidjan', - 'Africa/Accra' : 'Africa/Abidjan', - 'Africa/Bamako' : 'Africa/Abidjan', - 'Africa/Banjul' : 'Africa/Abidjan', - 'Africa/Bissau' : 'Africa/Abidjan', - 'Africa/Casablanca' : 'Africa/Abidjan', - 'Africa/Conakry' : 'Africa/Abidjan', - 'Africa/Dakar' : 'Africa/Abidjan', - 'Africa/El_Aaiun' : 'Africa/Abidjan', - 'Africa/Freetown' : 'Africa/Abidjan', - 'Africa/Lome' : 'Africa/Abidjan', - 'Africa/Monrovia' : 'Africa/Abidjan', - 'Africa/Nouakchott' : 'Africa/Abidjan', - 'Africa/Ouagadougou' : 'Africa/Abidjan', - 'Africa/Sao_Tome' : 'Africa/Abidjan', - 'Africa/Timbuktu' : 'Africa/Abidjan', - 'America/Danmarkshavn' : 'Africa/Abidjan', - 'Atlantic/Canary' : 'Africa/Abidjan', - 'Atlantic/Faeroe' : 'Africa/Abidjan', - 'Atlantic/Faroe' : 'Africa/Abidjan', - 'Atlantic/Madeira' : 'Africa/Abidjan', - 'Atlantic/Reykjavik' : 'Africa/Abidjan', - 'Atlantic/St_Helena' : 'Africa/Abidjan', - 'Eire' : 'Africa/Abidjan', - 'Etc/GMT' : 'Africa/Abidjan', - 'Etc/GMT+0' : 'Africa/Abidjan', - 'Etc/GMT-0' : 'Africa/Abidjan', - 'Etc/GMT0' : 'Africa/Abidjan', - 'Etc/Greenwich' : 'Africa/Abidjan', - 'Etc/UCT' : 'Africa/Abidjan', - 'Etc/UTC' : 'Africa/Abidjan', - 'Etc/Universal' : 'Africa/Abidjan', - 'Etc/Zulu' : 'Africa/Abidjan', - 'Europe/Belfast' : 'Africa/Abidjan', - 'Europe/Dublin' : 'Africa/Abidjan', - 'Europe/Guernsey' : 'Africa/Abidjan', - 'Europe/Isle_of_Man' : 'Africa/Abidjan', - 'Europe/Jersey' : 'Africa/Abidjan', - 'Europe/Lisbon' : 'Africa/Abidjan', - 'Europe/London' : 'Africa/Abidjan', - 'GB' : 'Africa/Abidjan', - 'GB-Eire' : 'Africa/Abidjan', - 'GMT' : 'Africa/Abidjan', - 'GMT0' : 'Africa/Abidjan', - 'Greenwich' : 'Africa/Abidjan', - 'Iceland' : 'Africa/Abidjan', - 'Portugal' : 'Africa/Abidjan', - 'UCT' : 'Africa/Abidjan', - 'UTC' : 'Africa/Abidjan', - 'Universal' : 'Africa/Abidjan', - 'WET' : 'Africa/Abidjan', - 'Zulu' : 'Africa/Abidjan', + 'Africa/Abidjan' : 'Africa/Abidjan', + 'Africa/Accra' : 'Africa/Abidjan', + 'Africa/Bamako' : 'Africa/Abidjan', + 'Africa/Banjul' : 'Africa/Abidjan', + 'Africa/Bissau' : 'Africa/Abidjan', + 'Africa/Casablanca' : 'Africa/Abidjan', + 'Africa/Conakry' : 'Africa/Abidjan', + 'Africa/Dakar' : 'Africa/Abidjan', + 'Africa/El_Aaiun' : 'Africa/Abidjan', + 'Africa/Freetown' : 'Africa/Abidjan', + 'Africa/Lome' : 'Africa/Abidjan', + 'Africa/Monrovia' : 'Africa/Abidjan', + 'Africa/Nouakchott' : 'Africa/Abidjan', + 'Africa/Ouagadougou' : 'Africa/Abidjan', + 'Africa/Sao_Tome' : 'Africa/Abidjan', + 'Africa/Timbuktu' : 'Africa/Abidjan', + 'America/Danmarkshavn' : 'Africa/Abidjan', + 'Atlantic/Canary' : 'Africa/Abidjan', + 'Atlantic/Faeroe' : 'Africa/Abidjan', + 'Atlantic/Faroe' : 'Africa/Abidjan', + 'Atlantic/Madeira' : 'Africa/Abidjan', + 'Atlantic/Reykjavik' : 'Africa/Abidjan', + 'Atlantic/St_Helena' : 'Africa/Abidjan', + 'Eire' : 'Africa/Abidjan', + 'Etc/GMT' : 'Africa/Abidjan', + 'Etc/GMT+0' : 'Africa/Abidjan', + 'Etc/GMT-0' : 'Africa/Abidjan', + 'Etc/GMT0' : 'Africa/Abidjan', + 'Etc/Greenwich' : 'Africa/Abidjan', + 'Etc/UCT' : 'Africa/Abidjan', + 'Etc/UTC' : 'Africa/Abidjan', + 'Etc/Universal' : 'Africa/Abidjan', + 'Etc/Zulu' : 'Africa/Abidjan', + 'Europe/Belfast' : 'Africa/Abidjan', + 'Europe/Dublin' : 'Africa/Abidjan', + 'Europe/Guernsey' : 'Africa/Abidjan', + 'Europe/Isle_of_Man' : 'Africa/Abidjan', + 'Europe/Jersey' : 'Africa/Abidjan', + 'Europe/Lisbon' : 'Africa/Abidjan', + 'Europe/London' : 'Africa/Abidjan', + 'GB' : 'Africa/Abidjan', + 'GB-Eire' : 'Africa/Abidjan', + 'GMT' : 'Africa/Abidjan', + 'GMT0' : 'Africa/Abidjan', + 'Greenwich' : 'Africa/Abidjan', + 'Iceland' : 'Africa/Abidjan', + 'Portugal' : 'Africa/Abidjan', + 'UCT' : 'Africa/Abidjan', + 'UTC' : 'Africa/Abidjan', + 'Universal' : 'Africa/Abidjan', + 'WET' : 'Africa/Abidjan', + 'Zulu' : 'Africa/Abidjan', /*+1:00*/ - 'Africa/Algiers' : 'Europe/Vienna', - 'Africa/Bangui' : 'Europe/Vienna', - 'Africa/Brazzaville' : 'Europe/Vienna', - 'Africa/Ceuta' : 'Europe/Vienna', - 'Africa/Douala' : 'Europe/Vienna', - 'Africa/Kinshasa' : 'Europe/Vienna', - 'Africa/Lagos' : 'Europe/Vienna', - 'Africa/Libreville' : 'Europe/Vienna', - 'Africa/Luanda' : 'Europe/Vienna', - 'Africa/Malabo' : 'Europe/Vienna', - 'Africa/Ndjamena' : 'Europe/Vienna', - 'Africa/Niamey' : 'Europe/Vienna', - 'Africa/Porto-Novo' : 'Europe/Vienna', - 'Africa/Tunis' : 'Europe/Vienna', - 'Africa/Windhoek' : 'Europe/Vienna', - 'Arctic/Longyearbyen' : 'Europe/Vienna', - 'Atlantic/Jan_Mayen' : 'Europe/Vienna', - 'CET' : 'Europe/Vienna', - 'ECT' : 'Europe/Vienna', - 'Etc/GMT-1' : 'Europe/Vienna', - 'Europe/Amsterdam' : 'Europe/Vienna', - 'Europe/Andorra' : 'Europe/Vienna', - 'Europe/Belgrade' : 'Europe/Vienna', - 'Europe/Berlin' : 'Europe/Vienna', - 'Europe/Bratislava' : 'Europe/Vienna', - 'Europe/Brussels' : 'Europe/Vienna', - 'Europe/Budapest' : 'Europe/Vienna', - 'Europe/Copenhagen' : 'Europe/Vienna', - 'Europe/Gibraltar' : 'Europe/Vienna', - 'Europe/Ljubljana' : 'Europe/Vienna', - 'Europe/Luxembourg' : 'Europe/Vienna', - 'Europe/Madrid' : 'Europe/Vienna', - 'Europe/Malta' : 'Europe/Vienna', - 'Europe/Monaco' : 'Europe/Vienna', - 'Europe/Oslo' : 'Europe/Vienna', - 'Europe/Paris' : 'Europe/Vienna', - 'Europe/Podgorica' : 'Europe/Vienna', - 'Europe/Prague' : 'Europe/Vienna', - 'Europe/Rome' : 'Europe/Vienna', - 'Europe/San_Marino' : 'Europe/Vienna', - 'Europe/Sarajevo' : 'Europe/Vienna', - 'Europe/Skopje' : 'Europe/Vienna', - 'Europe/Stockholm' : 'Europe/Vienna', - 'Europe/Tirane' : 'Europe/Vienna', - 'Europe/Vaduz' : 'Europe/Vienna', - 'Europe/Vatican' : 'Europe/Vienna', - 'Europe/Vienna' : 'Europe/Vienna', - 'Europe/Warsaw' : 'Europe/Vienna', - 'Europe/Zagreb' : 'Europe/Vienna', - 'Europe/Zurich' : 'Europe/Vienna', - 'MET' : 'Europe/Vienna', - 'Poland' : 'Europe/Vienna', + 'Africa/Algiers' : 'Europe/Vienna', + 'Africa/Bangui' : 'Europe/Vienna', + 'Africa/Brazzaville' : 'Europe/Vienna', + 'Africa/Ceuta' : 'Europe/Vienna', + 'Africa/Douala' : 'Europe/Vienna', + 'Africa/Kinshasa' : 'Europe/Vienna', + 'Africa/Lagos' : 'Europe/Vienna', + 'Africa/Libreville' : 'Europe/Vienna', + 'Africa/Luanda' : 'Europe/Vienna', + 'Africa/Malabo' : 'Europe/Vienna', + 'Africa/Ndjamena' : 'Europe/Vienna', + 'Africa/Niamey' : 'Europe/Vienna', + 'Africa/Porto-Novo' : 'Europe/Vienna', + 'Africa/Tunis' : 'Europe/Vienna', + 'Africa/Windhoek' : 'Europe/Vienna', + 'Arctic/Longyearbyen' : 'Europe/Vienna', + 'Atlantic/Jan_Mayen' : 'Europe/Vienna', + 'CET' : 'Europe/Vienna', + 'ECT' : 'Europe/Vienna', + 'Etc/GMT-1' : 'Europe/Vienna', + 'Europe/Amsterdam' : 'Europe/Vienna', + 'Europe/Andorra' : 'Europe/Vienna', + 'Europe/Belgrade' : 'Europe/Vienna', + 'Europe/Berlin' : 'Europe/Vienna', + 'Europe/Bratislava' : 'Europe/Vienna', + 'Europe/Brussels' : 'Europe/Vienna', + 'Europe/Budapest' : 'Europe/Vienna', + 'Europe/Copenhagen' : 'Europe/Vienna', + 'Europe/Gibraltar' : 'Europe/Vienna', + 'Europe/Ljubljana' : 'Europe/Vienna', + 'Europe/Luxembourg' : 'Europe/Vienna', + 'Europe/Madrid' : 'Europe/Vienna', + 'Europe/Malta' : 'Europe/Vienna', + 'Europe/Monaco' : 'Europe/Vienna', + 'Europe/Oslo' : 'Europe/Vienna', + 'Europe/Paris' : 'Europe/Vienna', + 'Europe/Podgorica' : 'Europe/Vienna', + 'Europe/Prague' : 'Europe/Vienna', + 'Europe/Rome' : 'Europe/Vienna', + 'Europe/San_Marino' : 'Europe/Vienna', + 'Europe/Sarajevo' : 'Europe/Vienna', + 'Europe/Skopje' : 'Europe/Vienna', + 'Europe/Stockholm' : 'Europe/Vienna', + 'Europe/Tirane' : 'Europe/Vienna', + 'Europe/Vaduz' : 'Europe/Vienna', + 'Europe/Vatican' : 'Europe/Vienna', + 'Europe/Vienna' : 'Europe/Vienna', + 'Europe/Warsaw' : 'Europe/Vienna', + 'Europe/Zagreb' : 'Europe/Vienna', + 'Europe/Zurich' : 'Europe/Vienna', + 'MET' : 'Europe/Vienna', + 'Poland' : 'Europe/Vienna', /*+2:00*/ - 'ART' : 'Asia/Jerusalem', - 'Africa/Blantyre' : 'Asia/Jerusalem', - 'Africa/Bujumbura' : 'Asia/Jerusalem', - 'Africa/Cairo' : 'Asia/Jerusalem', - 'Africa/Gaborone' : 'Asia/Jerusalem', - 'Africa/Harare' : 'Asia/Jerusalem', - 'Africa/Johannesburg' : 'Asia/Jerusalem', - 'Africa/Kigali' : 'Asia/Jerusalem', - 'Africa/Lubumbashi' : 'Asia/Jerusalem', - 'Africa/Lusaka' : 'Asia/Jerusalem', - 'Africa/Maputo' : 'Asia/Jerusalem', - 'Africa/Maseru' : 'Asia/Jerusalem', - 'Africa/Mbabane' : 'Asia/Jerusalem', - 'Africa/Tripoli' : 'Asia/Jerusalem', - 'Asia/Amman' : 'Asia/Jerusalem', - 'Asia/Beirut' : 'Asia/Jerusalem', - 'Asia/Damascus' : 'Asia/Jerusalem', - 'Asia/Gaza' : 'Asia/Jerusalem', - 'Asia/Hebron' : 'Asia/Jerusalem', - 'Asia/Istanbul' : 'Asia/Jerusalem', - 'Asia/Jerusalem' : 'Asia/Jerusalem', - 'Asia/Nicosia' : 'Asia/Jerusalem', - 'Asia/Tel_Aviv' : 'Asia/Jerusalem', - 'CAT' : 'Asia/Jerusalem', - 'EET' : 'Asia/Jerusalem', - 'Egypt' : 'Asia/Jerusalem', - 'Etc/GMT-2' : 'Asia/Jerusalem', - 'Europe/Athens' : 'Asia/Jerusalem', - 'Europe/Bucharest' : 'Asia/Jerusalem', - 'Europe/Chisinau' : 'Asia/Jerusalem', - 'Europe/Helsinki' : 'Asia/Jerusalem', - 'Europe/Istanbul' : 'Asia/Jerusalem', - 'Europe/Kiev' : 'Asia/Jerusalem', - 'Europe/Mariehamn' : 'Asia/Jerusalem', - 'Europe/Nicosia' : 'Asia/Jerusalem', - 'Europe/Riga' : 'Asia/Jerusalem', - 'Europe/Simferopol' : 'Asia/Jerusalem', - 'Europe/Sofia' : 'Asia/Jerusalem', - 'Europe/Tallinn' : 'Asia/Jerusalem', - 'Europe/Tiraspol' : 'Asia/Jerusalem', - 'Europe/Uzhgorod' : 'Asia/Jerusalem', - 'Europe/Vilnius' : 'Asia/Jerusalem', - 'Europe/Zaporozhye' : 'Asia/Jerusalem', - 'Israel' : 'Asia/Jerusalem', - 'Libya' : 'Asia/Jerusalem', - 'Turkey' : 'Asia/Jerusalem', + 'ART' : 'Asia/Jerusalem', + 'Africa/Blantyre' : 'Asia/Jerusalem', + 'Africa/Bujumbura' : 'Asia/Jerusalem', + 'Africa/Cairo' : 'Asia/Jerusalem', + 'Africa/Gaborone' : 'Asia/Jerusalem', + 'Africa/Harare' : 'Asia/Jerusalem', + 'Africa/Johannesburg' : 'Asia/Jerusalem', + 'Africa/Kigali' : 'Asia/Jerusalem', + 'Africa/Lubumbashi' : 'Asia/Jerusalem', + 'Africa/Lusaka' : 'Asia/Jerusalem', + 'Africa/Maputo' : 'Asia/Jerusalem', + 'Africa/Maseru' : 'Asia/Jerusalem', + 'Africa/Mbabane' : 'Asia/Jerusalem', + 'Africa/Tripoli' : 'Asia/Jerusalem', + 'Asia/Amman' : 'Asia/Jerusalem', + 'Asia/Beirut' : 'Asia/Jerusalem', + 'Asia/Damascus' : 'Asia/Jerusalem', + 'Asia/Gaza' : 'Asia/Jerusalem', + 'Asia/Hebron' : 'Asia/Jerusalem', + 'Asia/Istanbul' : 'Asia/Jerusalem', + 'Asia/Jerusalem' : 'Asia/Jerusalem', + 'Asia/Nicosia' : 'Asia/Jerusalem', + 'Asia/Tel_Aviv' : 'Asia/Jerusalem', + 'CAT' : 'Asia/Jerusalem', + 'EET' : 'Asia/Jerusalem', + 'Egypt' : 'Asia/Jerusalem', + 'Etc/GMT-2' : 'Asia/Jerusalem', + 'Europe/Athens' : 'Asia/Jerusalem', + 'Europe/Bucharest' : 'Asia/Jerusalem', + 'Europe/Chisinau' : 'Asia/Jerusalem', + 'Europe/Helsinki' : 'Asia/Jerusalem', + 'Europe/Istanbul' : 'Asia/Jerusalem', + 'Europe/Kiev' : 'Asia/Jerusalem', + 'Europe/Mariehamn' : 'Asia/Jerusalem', + 'Europe/Nicosia' : 'Asia/Jerusalem', + 'Europe/Riga' : 'Asia/Jerusalem', + 'Europe/Simferopol' : 'Asia/Jerusalem', + 'Europe/Sofia' : 'Asia/Jerusalem', + 'Europe/Tallinn' : 'Asia/Jerusalem', + 'Europe/Tiraspol' : 'Asia/Jerusalem', + 'Europe/Uzhgorod' : 'Asia/Jerusalem', + 'Europe/Vilnius' : 'Asia/Jerusalem', + 'Europe/Zaporozhye' : 'Asia/Jerusalem', + 'Israel' : 'Asia/Jerusalem', + 'Libya' : 'Asia/Jerusalem', + 'Turkey' : 'Asia/Jerusalem', /*+3:00*/ - 'Africa/Addis_Ababa' : 'Africa/Addis_Ababa', - 'Africa/Asmara' : 'Africa/Addis_Ababa', - 'Africa/Asmera' : 'Africa/Addis_Ababa', - 'Africa/Dar_es_Salaam' : 'Africa/Addis_Ababa', - 'Africa/Djibouti' : 'Africa/Addis_Ababa', - 'Africa/Juba' : 'Africa/Addis_Ababa', - 'Africa/Kampala' : 'Africa/Addis_Ababa', - 'Africa/Khartoum' : 'Africa/Addis_Ababa', - 'Africa/Mogadishu' : 'Africa/Addis_Ababa', - 'Africa/Nairobi' : 'Africa/Addis_Ababa', - 'Antarctica/Syowa' : 'Africa/Addis_Ababa', - 'Asia/Aden' : 'Africa/Addis_Ababa', - 'Asia/Baghdad' : 'Africa/Addis_Ababa', - 'Asia/Bahrain' : 'Africa/Addis_Ababa', - 'Asia/Kuwait' : 'Africa/Addis_Ababa', - 'Asia/Qatar' : 'Africa/Addis_Ababa', - 'Asia/Riyadh' : 'Africa/Addis_Ababa', - 'EAT' : 'Africa/Addis_Ababa', - 'Etc/GMT-3' : 'Africa/Addis_Ababa', - 'Europe/Kaliningrad' : 'Africa/Addis_Ababa', - 'Europe/Minsk' : 'Africa/Addis_Ababa', - 'Indian/Antananarivo' : 'Africa/Addis_Ababa', - 'Indian/Comoro' : 'Africa/Addis_Ababa', - 'Indian/Mayotte' : 'Africa/Addis_Ababa', + 'Africa/Addis_Ababa' : 'Africa/Addis_Ababa', + 'Africa/Asmara' : 'Africa/Addis_Ababa', + 'Africa/Asmera' : 'Africa/Addis_Ababa', + 'Africa/Dar_es_Salaam' : 'Africa/Addis_Ababa', + 'Africa/Djibouti' : 'Africa/Addis_Ababa', + 'Africa/Juba' : 'Africa/Addis_Ababa', + 'Africa/Kampala' : 'Africa/Addis_Ababa', + 'Africa/Khartoum' : 'Africa/Addis_Ababa', + 'Africa/Mogadishu' : 'Africa/Addis_Ababa', + 'Africa/Nairobi' : 'Africa/Addis_Ababa', + 'Antarctica/Syowa' : 'Africa/Addis_Ababa', + 'Asia/Aden' : 'Africa/Addis_Ababa', + 'Asia/Baghdad' : 'Africa/Addis_Ababa', + 'Asia/Bahrain' : 'Africa/Addis_Ababa', + 'Asia/Kuwait' : 'Africa/Addis_Ababa', + 'Asia/Qatar' : 'Africa/Addis_Ababa', + 'Asia/Riyadh' : 'Africa/Addis_Ababa', + 'EAT' : 'Africa/Addis_Ababa', + 'Etc/GMT-3' : 'Africa/Addis_Ababa', + 'Europe/Kaliningrad' : 'Africa/Addis_Ababa', + 'Europe/Minsk' : 'Africa/Addis_Ababa', + 'Indian/Antananarivo' : 'Africa/Addis_Ababa', + 'Indian/Comoro' : 'Africa/Addis_Ababa', + 'Indian/Mayotte' : 'Africa/Addis_Ababa', /*+3:30*/ - 'Asia/Tehran' : 'Asia/Tehran', - 'Iran' : 'Asia/Tehran', + 'Asia/Tehran' : 'Asia/Tehran', + 'Iran' : 'Asia/Tehran', /*+4:00*/ - 'Asia/Baku' : 'Asia/Dubai', - 'Asia/Dubai' : 'Asia/Dubai', - 'Asia/Muscat' : 'Asia/Dubai', - 'Asia/Tbilisi' : 'Asia/Dubai', - 'Asia/Yerevan' : 'Asia/Dubai', - 'Etc/GMT-4' : 'Asia/Dubai', - 'Europe/Moscow' : 'Asia/Dubai', - 'Europe/Samara' : 'Asia/Dubai', - 'Europe/Volgograd' : 'Asia/Dubai', - 'Indian/Mahe' : 'Asia/Dubai', - 'Indian/Mauritius' : 'Asia/Dubai', - 'Indian/Reunion' : 'Asia/Dubai', - 'NET' : 'Asia/Dubai', - 'W-SU' : 'Asia/Dubai', + 'Asia/Baku' : 'Asia/Dubai', + 'Asia/Dubai' : 'Asia/Dubai', + 'Asia/Muscat' : 'Asia/Dubai', + 'Asia/Tbilisi' : 'Asia/Dubai', + 'Asia/Yerevan' : 'Asia/Dubai', + 'Etc/GMT-4' : 'Asia/Dubai', + 'Europe/Moscow' : 'Asia/Dubai', + 'Europe/Samara' : 'Asia/Dubai', + 'Europe/Volgograd' : 'Asia/Dubai', + 'Indian/Mahe' : 'Asia/Dubai', + 'Indian/Mauritius' : 'Asia/Dubai', + 'Indian/Reunion' : 'Asia/Dubai', + 'NET' : 'Asia/Dubai', + 'W-SU' : 'Asia/Dubai', /*+4:30*/ - 'Asia/Kabul' : 'Asia/Kabul', + 'Asia/Kabul' : 'Asia/Kabul', /*+5:00*/ - 'Antarctica/Mawson' : 'Antarctica/Mawson', - 'Asia/Aqtau' : 'Antarctica/Mawson', - 'Asia/Aqtobe' : 'Antarctica/Mawson', - 'Asia/Ashgabat' : 'Antarctica/Mawson', - 'Asia/Ashkhabad' : 'Antarctica/Mawson', - 'Asia/Dushanbe' : 'Antarctica/Mawson', - 'Asia/Karachi' : 'Antarctica/Mawson', - 'Asia/Oral' : 'Antarctica/Mawson', - 'Asia/Samarkand' : 'Antarctica/Mawson', - 'Asia/Tashkent' : 'Antarctica/Mawson', - 'Etc/GMT-5' : 'Antarctica/Mawson', - 'Indian/Kerguelen' : 'Antarctica/Mawson', - 'Indian/Maldives' : 'Antarctica/Mawson', - 'PLT' : 'Antarctica/Mawson', + 'Antarctica/Mawson' : 'Antarctica/Mawson', + 'Asia/Aqtau' : 'Antarctica/Mawson', + 'Asia/Aqtobe' : 'Antarctica/Mawson', + 'Asia/Ashgabat' : 'Antarctica/Mawson', + 'Asia/Ashkhabad' : 'Antarctica/Mawson', + 'Asia/Dushanbe' : 'Antarctica/Mawson', + 'Asia/Karachi' : 'Antarctica/Mawson', + 'Asia/Oral' : 'Antarctica/Mawson', + 'Asia/Samarkand' : 'Antarctica/Mawson', + 'Asia/Tashkent' : 'Antarctica/Mawson', + 'Etc/GMT-5' : 'Antarctica/Mawson', + 'Indian/Kerguelen' : 'Antarctica/Mawson', + 'Indian/Maldives' : 'Antarctica/Mawson', + 'PLT' : 'Antarctica/Mawson', /*+5:30*/ - 'Asia/Calcutta' : 'Asia/Colombo', - 'Asia/Colombo' : 'Asia/Colombo', - 'Asia/Kolkata' : 'Asia/Colombo', - 'IST' : 'Asia/Colombo', + 'Asia/Calcutta' : 'Asia/Colombo', + 'Asia/Colombo' : 'Asia/Colombo', + 'Asia/Kolkata' : 'Asia/Colombo', + 'IST' : 'Asia/Colombo', /*+6:00*/ - 'Antarctica/Vostok' : 'Antarctica/Vostok', - 'Asia/Almaty' : 'Antarctica/Vostok', - 'Asia/Bishkek' : 'Antarctica/Vostok', - 'Asia/Dacca' : 'Antarctica/Vostok', - 'Asia/Dhaka' : 'Antarctica/Vostok', - 'Asia/Qyzylorda' : 'Antarctica/Vostok', - 'Asia/Thimbu' : 'Antarctica/Vostok', - 'Asia/Thimphu' : 'Antarctica/Vostok', - 'Asia/Yekaterinburg' : 'Antarctica/Vostok', - 'BST' : 'Antarctica/Vostok', - 'Etc/GMT-6' : 'Antarctica/Vostok', - 'Indian/Chagos' : 'Antarctica/Vostok', + 'Antarctica/Vostok' : 'Antarctica/Vostok', + 'Asia/Almaty' : 'Antarctica/Vostok', + 'Asia/Bishkek' : 'Antarctica/Vostok', + 'Asia/Dacca' : 'Antarctica/Vostok', + 'Asia/Dhaka' : 'Antarctica/Vostok', + 'Asia/Qyzylorda' : 'Antarctica/Vostok', + 'Asia/Thimbu' : 'Antarctica/Vostok', + 'Asia/Thimphu' : 'Antarctica/Vostok', + 'Asia/Yekaterinburg' : 'Antarctica/Vostok', + 'BST' : 'Antarctica/Vostok', + 'Etc/GMT-6' : 'Antarctica/Vostok', + 'Indian/Chagos' : 'Antarctica/Vostok', /*+6:30*/ - 'Asia/Rangoon' : 'Asia/Rangoon', - 'Indian/Cocos' : 'Asia/Rangoon', + 'Asia/Rangoon' : 'Asia/Rangoon', + 'Indian/Cocos' : 'Asia/Rangoon', /*+7:00*/ - 'Antarctica/Davis' : 'Antarctica/Davis', - 'Asia/Bangkok' : 'Antarctica/Davis', - 'Asia/Ho_Chi_Minh' : 'Antarctica/Davis', - 'Asia/Hovd' : 'Antarctica/Davis', - 'Asia/Jakarta' : 'Antarctica/Davis', - 'Asia/Novokuznetsk' : 'Antarctica/Davis', - 'Asia/Novosibirsk' : 'Antarctica/Davis', - 'Asia/Omsk' : 'Antarctica/Davis', - 'Asia/Phnom_Penh' : 'Antarctica/Davis', - 'Asia/Pontianak' : 'Antarctica/Davis', - 'Asia/Saigon' : 'Antarctica/Davis', - 'Asia/Vientiane' : 'Antarctica/Davis', - 'Etc/GMT-7' : 'Antarctica/Davis', - 'Indian/Christmas' : 'Antarctica/Davis', - 'VST' : 'Antarctica/Davis', + 'Antarctica/Davis' : 'Antarctica/Davis', + 'Asia/Bangkok' : 'Antarctica/Davis', + 'Asia/Ho_Chi_Minh' : 'Antarctica/Davis', + 'Asia/Hovd' : 'Antarctica/Davis', + 'Asia/Jakarta' : 'Antarctica/Davis', + 'Asia/Novokuznetsk' : 'Antarctica/Davis', + 'Asia/Novosibirsk' : 'Antarctica/Davis', + 'Asia/Omsk' : 'Antarctica/Davis', + 'Asia/Phnom_Penh' : 'Antarctica/Davis', + 'Asia/Pontianak' : 'Antarctica/Davis', + 'Asia/Saigon' : 'Antarctica/Davis', + 'Asia/Vientiane' : 'Antarctica/Davis', + 'Etc/GMT-7' : 'Antarctica/Davis', + 'Indian/Christmas' : 'Antarctica/Davis', + 'VST' : 'Antarctica/Davis', /*+8:00*/ - 'Antarctica/Casey' : 'Antarctica/Casey', - 'Asia/Brunei' : 'Antarctica/Casey', - 'Asia/Choibalsan' : 'Antarctica/Casey', - 'Asia/Chongqing' : 'Antarctica/Casey', - 'Asia/Chungking' : 'Antarctica/Casey', - 'Asia/Harbin' : 'Antarctica/Casey', - 'Asia/Hong_Kong' : 'Antarctica/Casey', - 'Asia/Kashgar' : 'Antarctica/Casey', - 'Asia/Krasnoyarsk' : 'Antarctica/Casey', - 'Asia/Kuala_Lumpur' : 'Antarctica/Casey', - 'Asia/Kuching' : 'Antarctica/Casey', - 'Asia/Macao' : 'Antarctica/Casey', - 'Asia/Macau' : 'Antarctica/Casey', - 'Asia/Makassar' : 'Antarctica/Casey', - 'Asia/Manila' : 'Antarctica/Casey', - 'Asia/Shanghai' : 'Antarctica/Casey', - 'Asia/Singapore' : 'Antarctica/Casey', - 'Asia/Taipei' : 'Antarctica/Casey', - 'Asia/Ujung_Pandang' : 'Antarctica/Casey', - 'Asia/Ulaanbaatar' : 'Antarctica/Casey', - 'Asia/Ulan_Bator' : 'Antarctica/Casey', - 'Asia/Urumqi' : 'Antarctica/Casey', - 'Australia/Perth' : 'Antarctica/Casey', - 'Australia/West' : 'Antarctica/Casey', - 'CTT' : 'Antarctica/Casey', - 'Etc/GMT-8' : 'Antarctica/Casey', - 'Hongkong' : 'Antarctica/Casey', - 'PRC' : 'Antarctica/Casey', - 'Singapore' : 'Antarctica/Casey', + 'Antarctica/Casey' : 'Antarctica/Casey', + 'Asia/Brunei' : 'Antarctica/Casey', + 'Asia/Choibalsan' : 'Antarctica/Casey', + 'Asia/Chongqing' : 'Antarctica/Casey', + 'Asia/Chungking' : 'Antarctica/Casey', + 'Asia/Harbin' : 'Antarctica/Casey', + 'Asia/Hong_Kong' : 'Antarctica/Casey', + 'Asia/Kashgar' : 'Antarctica/Casey', + 'Asia/Krasnoyarsk' : 'Antarctica/Casey', + 'Asia/Kuala_Lumpur' : 'Antarctica/Casey', + 'Asia/Kuching' : 'Antarctica/Casey', + 'Asia/Macao' : 'Antarctica/Casey', + 'Asia/Macau' : 'Antarctica/Casey', + 'Asia/Makassar' : 'Antarctica/Casey', + 'Asia/Manila' : 'Antarctica/Casey', + 'Asia/Shanghai' : 'Antarctica/Casey', + 'Asia/Singapore' : 'Antarctica/Casey', + 'Asia/Taipei' : 'Antarctica/Casey', + 'Asia/Ujung_Pandang' : 'Antarctica/Casey', + 'Asia/Ulaanbaatar' : 'Antarctica/Casey', + 'Asia/Ulan_Bator' : 'Antarctica/Casey', + 'Asia/Urumqi' : 'Antarctica/Casey', + 'Australia/Perth' : 'Antarctica/Casey', + 'Australia/West' : 'Antarctica/Casey', + 'CTT' : 'Antarctica/Casey', + 'Etc/GMT-8' : 'Antarctica/Casey', + 'Hongkong' : 'Antarctica/Casey', + 'PRC' : 'Antarctica/Casey', + 'Singapore' : 'Antarctica/Casey', /*+9:00*/ - 'Asia/Dili' : 'Asia/Dili', - 'Asia/Irkutsk' : 'Asia/Dili', - 'Asia/Jayapura' : 'Asia/Dili', - 'Asia/Pyongyang' : 'Asia/Dili', - 'Asia/Seoul' : 'Asia/Dili', - 'Asia/Tokyo' : 'Asia/Dili', - 'Etc/GMT-9' : 'Asia/Dili', - 'JST' : 'Asia/Dili', - 'Japan' : 'Asia/Dili', - 'Pacific/Palau' : 'Asia/Dili', - 'ROK' : 'Asia/Dili', + 'Asia/Dili' : 'Asia/Dili', + 'Asia/Irkutsk' : 'Asia/Dili', + 'Asia/Jayapura' : 'Asia/Dili', + 'Asia/Pyongyang' : 'Asia/Dili', + 'Asia/Seoul' : 'Asia/Dili', + 'Asia/Tokyo' : 'Asia/Dili', + 'Etc/GMT-9' : 'Asia/Dili', + 'JST' : 'Asia/Dili', + 'Japan' : 'Asia/Dili', + 'Pacific/Palau' : 'Asia/Dili', + 'ROK' : 'Asia/Dili', /*+9:30*/ - 'ACT' : 'Australia/Darwin', - 'Australia/Adelaide' : 'Australia/Darwin', - 'Australia/Broken_Hill' : 'Australia/Darwin', - 'Australia/Darwin' : 'Australia/Darwin', - 'Australia/North' : 'Australia/Darwin', - 'Australia/South' : 'Australia/Darwin', - 'Australia/Yancowinna' : 'Australia/Darwin', + 'ACT' : 'Australia/Darwin', + 'Australia/Adelaide' : 'Australia/Darwin', + 'Australia/Broken_Hill' : 'Australia/Darwin', + 'Australia/Darwin' : 'Australia/Darwin', + 'Australia/North' : 'Australia/Darwin', + 'Australia/South' : 'Australia/Darwin', + 'Australia/Yancowinna' : 'Australia/Darwin', /*+10:00*/ - 'AET' : 'Australia/Currie', - 'Antarctica/DumontDUrville' : 'Australia/Currie', - 'Asia/Yakutsk' : 'Australia/Currie', - 'Australia/ACT' : 'Australia/Currie', - 'Australia/Brisbane' : 'Australia/Currie', - 'Australia/Canberra' : 'Australia/Currie', - 'Australia/Currie' : 'Australia/Currie', - 'Australia/Hobart' : 'Australia/Currie', - 'Australia/Lindeman' : 'Australia/Currie', - 'Australia/Melbourne' : 'Australia/Currie', - 'Australia/NSW' : 'Australia/Currie', - 'Australia/Queensland' : 'Australia/Currie', - 'Australia/Sydney' : 'Australia/Currie', - 'Australia/Tasmania' : 'Australia/Currie', - 'Australia/Victoria' : 'Australia/Currie', - 'Etc/GMT-10' : 'Australia/Currie', - 'Pacific/Chuuk' : 'Australia/Currie', - 'Pacific/Guam' : 'Australia/Currie', - 'Pacific/Port_Moresby' : 'Australia/Currie', - 'Pacific/Saipan' : 'Australia/Currie', - 'Pacific/Truk' : 'Australia/Currie', - 'Pacific/Yap' : 'Australia/Currie', + 'AET' : 'Australia/Currie', + 'Antarctica/DumontDUrville' : 'Australia/Currie', + 'Asia/Yakutsk' : 'Australia/Currie', + 'Australia/ACT' : 'Australia/Currie', + 'Australia/Brisbane' : 'Australia/Currie', + 'Australia/Canberra' : 'Australia/Currie', + 'Australia/Currie' : 'Australia/Currie', + 'Australia/Hobart' : 'Australia/Currie', + 'Australia/Lindeman' : 'Australia/Currie', + 'Australia/Melbourne' : 'Australia/Currie', + 'Australia/NSW' : 'Australia/Currie', + 'Australia/Queensland' : 'Australia/Currie', + 'Australia/Sydney' : 'Australia/Currie', + 'Australia/Tasmania' : 'Australia/Currie', + 'Australia/Victoria' : 'Australia/Currie', + 'Etc/GMT-10' : 'Australia/Currie', + 'Pacific/Chuuk' : 'Australia/Currie', + 'Pacific/Guam' : 'Australia/Currie', + 'Pacific/Port_Moresby' : 'Australia/Currie', + 'Pacific/Saipan' : 'Australia/Currie', + 'Pacific/Truk' : 'Australia/Currie', + 'Pacific/Yap' : 'Australia/Currie', /*+10:30*/ - 'Australia/LHI' : 'Australia/Lord_Howe', - 'Australia/Lord_Howe' : 'Australia/Lord_Howe', + 'Australia/LHI' : 'Australia/Lord_Howe', + 'Australia/Lord_Howe' : 'Australia/Lord_Howe', /*+11:00*/ - 'Antarctica/Macquarie' : 'Antarctica/Macquarie', - 'Asia/Sakhalin' : 'Antarctica/Macquarie', - 'Asia/Vladivostok' : 'Antarctica/Macquarie', - 'Etc/GMT-11' : 'Antarctica/Macquarie', - 'Pacific/Efate' : 'Antarctica/Macquarie', - 'Pacific/Guadalcanal' : 'Antarctica/Macquarie', - 'Pacific/Kosrae' : 'Antarctica/Macquarie', - 'Pacific/Noumea' : 'Antarctica/Macquarie', - 'Pacific/Pohnpei' : 'Antarctica/Macquarie', - 'Pacific/Ponape' : 'Antarctica/Macquarie', - 'SST' : 'Antarctica/Macquarie', + 'Antarctica/Macquarie' : 'Antarctica/Macquarie', + 'Asia/Sakhalin' : 'Antarctica/Macquarie', + 'Asia/Vladivostok' : 'Antarctica/Macquarie', + 'Etc/GMT-11' : 'Antarctica/Macquarie', + 'Pacific/Efate' : 'Antarctica/Macquarie', + 'Pacific/Guadalcanal' : 'Antarctica/Macquarie', + 'Pacific/Kosrae' : 'Antarctica/Macquarie', + 'Pacific/Noumea' : 'Antarctica/Macquarie', + 'Pacific/Pohnpei' : 'Antarctica/Macquarie', + 'Pacific/Ponape' : 'Antarctica/Macquarie', + 'SST' : 'Antarctica/Macquarie', /*+11:30*/ - 'Pacific/Norfolk' : 'Pacific/Norfolk', + 'Pacific/Norfolk' : 'Pacific/Norfolk', /*+12:00*/ - 'Antarctica/McMurdo' : 'Antarctica/McMurdo', - 'Antarctica/South_Pole' : 'Antarctica/McMurdo', - 'Asia/Anadyr' : 'Antarctica/McMurdo', - 'Asia/Kamchatka' : 'Antarctica/McMurdo', - 'Asia/Magadan' : 'Antarctica/McMurdo', - 'Etc/GMT-12' : 'Antarctica/McMurdo', - 'Kwajalein' : 'Antarctica/McMurdo', - 'NST' : 'Antarctica/McMurdo', - 'NZ' : 'Antarctica/McMurdo', - 'Pacific/Auckland' : 'Antarctica/McMurdo', - 'Pacific/Fiji' : 'Antarctica/McMurdo', - 'Pacific/Funafuti' : 'Antarctica/McMurdo', - 'Pacific/Kwajalein' : 'Antarctica/McMurdo', - 'Pacific/Majuro' : 'Antarctica/McMurdo', - 'Pacific/Nauru' : 'Antarctica/McMurdo', - 'Pacific/Tarawa' : 'Antarctica/McMurdo', - 'Pacific/Wake' : 'Antarctica/McMurdo', - 'Pacific/Wallis' : 'Antarctica/McMurdo', + 'Antarctica/McMurdo' : 'Antarctica/McMurdo', + 'Antarctica/South_Pole' : 'Antarctica/McMurdo', + 'Asia/Anadyr' : 'Antarctica/McMurdo', + 'Asia/Kamchatka' : 'Antarctica/McMurdo', + 'Asia/Magadan' : 'Antarctica/McMurdo', + 'Etc/GMT-12' : 'Antarctica/McMurdo', + 'Kwajalein' : 'Antarctica/McMurdo', + 'NST' : 'Antarctica/McMurdo', + 'NZ' : 'Antarctica/McMurdo', + 'Pacific/Auckland' : 'Antarctica/McMurdo', + 'Pacific/Fiji' : 'Antarctica/McMurdo', + 'Pacific/Funafuti' : 'Antarctica/McMurdo', + 'Pacific/Kwajalein' : 'Antarctica/McMurdo', + 'Pacific/Majuro' : 'Antarctica/McMurdo', + 'Pacific/Nauru' : 'Antarctica/McMurdo', + 'Pacific/Tarawa' : 'Antarctica/McMurdo', + 'Pacific/Wake' : 'Antarctica/McMurdo', + 'Pacific/Wallis' : 'Antarctica/McMurdo', /*+13:00*/ - 'Etc/GMT-13' : 'Pacific/Enderbury', - 'MIT' : 'Pacific/Enderbury', - 'Pacific/Apia' : 'Pacific/Enderbury', - 'Pacific/Enderbury' : 'Pacific/Enderbury', - 'Pacific/Tongatapu' : 'Pacific/Enderbury', + 'Etc/GMT-13' : 'Pacific/Enderbury', + 'MIT' : 'Pacific/Enderbury', + 'Pacific/Apia' : 'Pacific/Enderbury', + 'Pacific/Enderbury' : 'Pacific/Enderbury', + 'Pacific/Tongatapu' : 'Pacific/Enderbury', /*+14:00*/ - 'Etc/GMT-14' : 'Pacific/Kiritimati', - 'Pacific/Fakaofo' : 'Pacific/Kiritimati', - 'Pacific/Kiritimati' : 'Pacific/Kiritimati' + 'Etc/GMT-14' : 'Pacific/Kiritimati', + 'Pacific/Fakaofo' : 'Pacific/Kiritimati', + 'Pacific/Kiritimati' : 'Pacific/Kiritimati' }, - + /* return unmapped timezone... */ - unMap: function(timezone) { + unMap: function (timezone) { return this.map[timezone] !== undefined ? this.map[timezone] : timezone; }, - - getOffset: function(timezone) { + + getOffset: function (timezone) { /* find timezone, this needs to be optimized ;) */ timezone = this.unMap(timezone); var i = 0; - for(i = 0; i < this.store.length; i++) { - if(this.store[i][0] == timezone) { + for (i = 0; i < this.store.length; i++) { + if (this.store[i][0] == timezone) { return (this.store[i][2] * 60000); } } - + return 0; // no offset found... } }); diff --git a/js/dialogs/ImportContentPanel.js b/js/dialogs/ImportContentPanel.js index e325d63..dbd2e17 100644 --- a/js/dialogs/ImportContentPanel.js +++ b/js/dialogs/ImportContentPanel.js @@ -2,7 +2,7 @@ * ImportContentPanel.js zarafa calender to ics im/exporter * * Author: Christoph Haas - * Copyright (C) 2012-2013 Christoph Haas + * Copyright (C) 2012-2016 Christoph Haas * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -42,13 +42,9 @@ Zarafa.plugins.calendarimporter.dialogs.ImportContentPanel = Ext.extend(Zarafa.c */ constructor : function(config) { config = config || {}; - var title = _('Import Calendar File'); - if(container.getSettingsModel().get("zarafa/v1/plugins/calendarimporter/enable_export")){ - title = _('Import/Export Calendar File'); - } Ext.applyIf(config, { layout : 'fit', - title : title, + title : _('Import Calendar File'), closeOnSave : true, width : 800, height : 700, @@ -56,7 +52,8 @@ Zarafa.plugins.calendarimporter.dialogs.ImportContentPanel = Ext.extend(Zarafa.c items : [ { xtype : 'calendarimporter.importpanel', - filename : config.filename + filename : config.filename, + folder : config.folder } ] }); diff --git a/js/dialogs/ImportPanel.js b/js/dialogs/ImportPanel.js index fcea308..abdc201 100644 --- a/js/dialogs/ImportPanel.js +++ b/js/dialogs/ImportPanel.js @@ -2,7 +2,7 @@ * ImportPanel.js zarafa calender to ics im/exporter * * Author: Christoph Haas - * Copyright (C) 2012-2013 Christoph Haas + * Copyright (C) 2012-2016 Christoph Haas * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -29,7 +29,7 @@ Ext.namespace("Zarafa.plugins.calendarimporter.dialogs"); /** * @class Zarafa.plugins.calendarimporter.dialogs.ImportPanel - * @extends Ext.form.FormPanel + * @extends Ext.Panel */ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, { @@ -46,21 +46,16 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, { loadMask: null, /* export event buffer */ - exportResponse: new Array(), + exportResponse: [], /* how many requests are still running? */ runningRequests: null, /* The store for the selection grid */ store: null, - - /** - * The internal 'iframe' which is hidden from the user, which is used for downloading - * attachments. See {@link #doOpen}. - * @property - * @type Ext.Element - */ - downloadFrame : undefined, + + /* selected folder */ + folder : null, /** * @constructor @@ -70,25 +65,31 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, { config = config || {}; var self = this; this.timezone = container.getSettingsModel().get("zarafa/v1/plugins/calendarimporter/default_timezone"); - - if(typeof config.filename !== "undefined") { + + if (!Ext.isEmpty(config.filename)) { this.icsfile = config.filename; } + + if (!Ext.isEmpty(config.folder)) { + this.folder = config.folder; + } // create the data store this.store = new Ext.data.ArrayStore({ fields: [ - {name: 'title'}, - {name: 'start'}, - {name: 'end'}, + {name: 'subject'}, + {name: 'startdate'}, + {name: 'enddate'}, {name: 'location'}, - {name: 'description'}, + {name: 'body'}, {name: 'priority'}, {name: 'label'}, {name: 'busy'}, - {name: 'privatestate'}, + {name: 'class'}, {name: 'organizer'}, - {name: 'trigger'} + {name: 'alarms'}, + {name: 'timezone'}, + {name: 'record'} ] }); @@ -114,29 +115,19 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, { this.createGrid() ], buttons: [ - this.createExportAllButton(), this.createSubmitAllButton(), this.createSubmitButton(), this.createCancelButton() ], listeners: { afterrender: function (cmp) { - Ext.getCmp('importbutton').disable(); - this.loadMask = new Ext.LoadMask(Ext.getCmp("importpanel").getEl(), {msg:'Loading...'}); + this.loadMask = new Ext.LoadMask(this.getEl(), {msg:'Loading...'}); if(this.icsfile != null) { // if we have got the filename from an attachment this.parseCalendar(this.icsfile, this.timezone, this.ignoredst); } }, - close: function (cmp) { - Ext.getCmp('importbutton').enable(); - }, - hide: function (cmp) { - Ext.getCmp('importbutton').enable(); - }, - destroy: function (cmp) { - Ext.getCmp('importbutton').enable(); - } + scope: this } }); @@ -174,22 +165,25 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, { reloadGridStore: function(eventdata) { var parsedData = []; - // this is done to get rid of the local browser timezone.... - // because all timezone specific stuff is done via php - var local_tz_offset = new Date().getTimezoneOffset() * 60000; // getTimezoneOffset returns minutes... we need milliseconds - - if(eventdata !== null) { parsedData = new Array(eventdata.events.length); var i = 0; for(i = 0; i < eventdata.events.length; i++) { - var trigger = null; - - if(eventdata.events[i]["VALARM"]) { - trigger = eventdata.events[i]["VALARM"]["TRIGGER"]; - trigger = new Date(parseInt(trigger) + local_tz_offset); - } - parsedData[i] = new Array(eventdata.events[i]["SUMMARY"], new Date(parseInt(eventdata.events[i]["DTSTART"]) + local_tz_offset), new Date(parseInt(eventdata.events[i]["DTEND"]) + local_tz_offset), eventdata.events[i]["LOCATION"], eventdata.events[i]["DESCRIPTION"],eventdata.events[i]["PRIORITY"],eventdata.events[i]["X-ZARAFA-LABEL"],eventdata.events[i]["X-MICROSOFT-CDO-BUSYSTATUS"],eventdata.events[i]["CLASS"],eventdata.events[i]["ORGANIZER"],trigger); + parsedData[i] = [ + eventdata.events[i]["subject"], + new Date(parseInt(eventdata.events[i]["startdate"]) * 1000), + new Date(parseInt(eventdata.events[i]["duedate"]) * 1000), + eventdata.events[i]["location"], + eventdata.events[i]["body"], + eventdata.events[i]["priority"], + eventdata.events[i]["label"], + eventdata.events[i]["busystatus"], + eventdata.events[i]["private"], + eventdata.events[i]["organizer"], + eventdata.events[i]["alarms"], + eventdata.events[i]["timezone"], + eventdata.events[i] + ]; } } else { return null; @@ -223,17 +217,18 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, { sortable: true }, columns: [ - {id: 'Summary', header: 'Title', width: 200, sortable: true, dataIndex: 'title'}, - {header: 'Start', width: 200, sortable: true, dataIndex: 'start', renderer : Zarafa.common.ui.grid.Renderers.datetime}, - {header: 'End', width: 200, sortable: true, dataIndex: 'end', renderer : Zarafa.common.ui.grid.Renderers.datetime}, + {id: 'Summary', header: 'Title', width: 200, sortable: true, dataIndex: 'subject'}, + {header: 'Start', width: 200, sortable: true, dataIndex: 'startdate', renderer : Zarafa.common.ui.grid.Renderers.datetime}, + {header: 'End', width: 200, sortable: true, dataIndex: 'enddate', renderer : Zarafa.common.ui.grid.Renderers.datetime}, {header: 'Location', width: 150, sortable: true, dataIndex: 'location'}, - {header: 'Description', sortable: true, dataIndex: 'description'}, + {header: 'Description', sortable: true, dataIndex: 'body'}, {header: "Priority", dataIndex: 'priority', hidden: true}, {header: "Label", dataIndex: 'label', hidden: true}, {header: "Busystatus", dataIndex: 'busy', hidden: true}, - {header: "Privacystatus", dataIndex: 'privatestate', hidden: true}, + {header: "Privacystatus", dataIndex: 'class', hidden: true}, {header: "Organizer", dataIndex: 'organizer', hidden: true}, - {header: "Alarm", dataIndex: 'trigger', hidden: true, renderer : Zarafa.common.ui.grid.Renderers.datetime} + {header: "Alarm", dataIndex: 'alarms', hidden: true, renderer : Zarafa.common.ui.grid.Renderers.datetime}, + {header: "Timezone", dataIndex: 'timezone', hidden: true} ] }), sm: new Ext.grid.RowSelectionModel({multiSelect:true}) @@ -241,52 +236,23 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, { }, createSelectBox: function() { - var defaultFolder = container.getHierarchyStore().getDefaultFolder('calendar'); // @type: Zarafa.hierarchy.data.MAPIFolderRecord - var subFolders = defaultFolder.getChildren(); - var myStore = []; - - /* add all local calendar folders */ - var i = 0; - myStore.push(new Array(defaultFolder.getDefaultFolderKey(), defaultFolder.getDisplayName())); - for(i = 0; i < subFolders.length; i++) { - /* Store all subfolders */ - myStore.push(new Array(subFolders[i].getDisplayName(), subFolders[i].getDisplayName(), false)); // 3rd field = isPublicfolder - } - - /* add all shared calendar folders */ - var pubStore = container.getHierarchyStore().getPublicStore(); - - if(typeof pubStore !== "undefined") { - try { - var pubFolder = pubStore.getDefaultFolder("publicfolders"); - var pubSubFolders = pubFolder.getChildren(); - - for(i = 0; i < pubSubFolders.length; i++) { - if(pubSubFolders[i].isContainerClass("IPF.Appointment")){ - myStore.push(new Array(pubSubFolders[i].getDisplayName(), pubSubFolders[i].getDisplayName() + " [Shared]", true)); // 3rd field = isPublicfolder - } - } - } catch (e) { - console.log("Error opening the shared folder..."); - console.log(e); - } - } - + var myStore = Zarafa.plugins.calendarimporter.data.Actions.getAllCalendarFolders(true); + return { xtype: "selectbox", ref: 'calendarselector', - id: 'calendarselector', editable: false, name: "choosen_calendar", - value: container.getSettingsModel().get("zarafa/v1/plugins/calendarimporter/default_calendar"), + value: Ext.isEmpty(this.folder) ? Zarafa.plugins.calendarimporter.data.Actions.getCalendarFolderByName(container.getSettingsModel().get("zarafa/v1/plugins/calendarimporter/default_calendar")).entryid : this.folder, width: 100, - fieldLabel: "Select a calender", + fieldLabel: "Select folder", store: myStore, mode: 'local', labelSeperator: ":", border: false, anchor: "100%", scope: this, + hidden : Ext.isEmpty(this.folder) ? false : true, allowBlank: false } }, @@ -295,12 +261,11 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, { return { xtype: "selectbox", ref: 'timezoneselector', - id: 'timezoneselector', editable: false, name: "choosen_timezone", value: Zarafa.plugins.calendarimporter.data.Timezones.unMap(container.getSettingsModel().get("zarafa/v1/plugins/calendarimporter/default_timezone")), width: 100, - fieldLabel: "Select a timezone (optional)", + fieldLabel: "Timezone", store: Zarafa.plugins.calendarimporter.data.Timezones.store, labelSeperator: ":", mode: 'local', @@ -309,7 +274,7 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, { scope: this, allowBlank: true, listeners: { - 'select': this.onTimezoneSelected, + select: this.onTimezoneSelected, scope: this } } @@ -319,10 +284,9 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, { return { xtype: "checkbox", ref: 'dstcheck', - id: 'dstcheck', name: "dst_check", width: 100, - fieldLabel: "Ignore DST (optional)", + fieldLabel: "Ignore DST", boxLabel: 'This will ignore "Daylight saving time" offsets.', labelSeperator: ":", border: false, @@ -330,7 +294,7 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, { scope: this, allowBlank: true, listeners: { - 'check': this.onDstChecked, + check: this.onDstChecked, scope: this } } @@ -346,10 +310,11 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, { emptyText: 'Select an .ics calendar', border: false, anchor: "100%", + height : "30", scope: this, allowBlank: false, listeners: { - 'fileselected': this.onFileSelected, + fileselected: this.onFileSelected, scope: this } } @@ -358,48 +323,28 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, { createSubmitButton: function() { return { xtype: "button", - ref: "submitButton", - id: "submitButton", + ref: "../submitButton", disabled: true, width: 100, border: false, text: _("Import"), anchor: "100%", handler: this.importCheckedEvents, - scope: this, - allowBlank: false + scope: this } }, createSubmitAllButton: function() { return { xtype: "button", - ref: "submitAllButton", - id: "submitAllButton", + ref: "../submitAllButton", disabled: true, width: 100, border: false, text: _("Import All"), anchor: "100%", handler: this.importAllEvents, - scope: this, - allowBlank: false - } - }, - - createExportAllButton: function() { - return { - xtype: "button", - ref: "exportAllButton", - id: "exportAllButton", - hidden: !container.getSettingsModel().get("zarafa/v1/plugins/calendarimporter/enable_export"), - width: 100, - border: false, - text: _("Export All"), - anchor: "100%", - handler: this.exportAllEvents, - scope: this, - allowBlank: false + scope: this } }, @@ -411,8 +356,7 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, { text: _("Cancel"), anchor: "100%", handler: this.close, - scope: this, - allowBlank: false + scope: this } }, @@ -432,7 +376,7 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, { /** * This is called when the dst checkbox has been selected - * @param {Ext.form.CheckBox} combo + * @param {Ext.form.CheckBox} checkbox * @param {boolean} checked */ onDstChecked : function(checkbox, checked) { @@ -456,8 +400,8 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, { waitMsg: 'Uploading and parsing calendar...', url: 'plugins/calendarimporter/php/upload.php', failure: function(file, action) { - Ext.getCmp('submitButton').disable(); - Ext.getCmp('submitAllButton').disable(); + this.submitButton.disable(); + this.submitAllButton.disable(); Zarafa.common.dialogs.MessageBox.show({ title : _('Error'), msg : _(action.result.error), @@ -478,14 +422,15 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, { parseCalendar: function (icsPath, timezone, ignoredst) { this.loadMask.show(); - // call export function here! + var responseHandler = new Zarafa.plugins.calendarimporter.data.ResponseHandler({ - successCallback: this.handleParsingResult.createDelegate(this) + successCallback: this.handleParsingResult, + scope: this }); container.getRequest().singleRequest( 'calendarmodule', - 'import', + 'load', { ics_filepath: icsPath, timezone: timezone, @@ -496,20 +441,22 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, { }, handleParsingResult: function(response) { - this.loadMask.hide(); + var self = this.scope; + + self.loadMask.hide(); if(response["status"] == true) { - Ext.getCmp('submitButton').enable(); - Ext.getCmp('submitAllButton').enable(); - - if(typeof response.parsed.calendar["X-WR-TIMEZONE"] !== "undefined") {; - this.timezone = response.parsed.calendar["X-WR-TIMEZONE"]; - this.timezoneselector.setValue(Zarafa.plugins.calendarimporter.data.Timezones.unMap(this.timezone)); + self.submitButton.enable(); + self.submitAllButton.enable(); + + if(typeof response.parsed.calendar["X-WR-TIMEZONE"] !== "undefined") { + self.timezone = response.parsed.calendar["X-WR-TIMEZONE"]; + self.timezoneselector.setValue(Zarafa.plugins.calendarimporter.data.Timezones.unMap(this.timezone)); } - this.reloadGridStore(response.parsed); + self.reloadGridStore(response.parsed); } else { - Ext.getCmp('submitButton').disable(); - Ext.getCmp('submitAllButton').disable(); + self.submitButton.disable(); + self.submitAllButton.disable(); Zarafa.common.dialogs.MessageBox.show({ title : _('Parser Error'), msg : _(response["message"]), @@ -524,54 +471,6 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, { this.dialog.close() }, - convertToAppointmentRecord: function (calendarFolder,entry) { - var newRecord = Zarafa.core.data.RecordFactory.createRecordObjectByMessageClass('IPM.Appointment', { - startdate: new Date(entry.start), - duedate: (entry.end != null) ? - new Date(entry.end) : - new Date(entry.start).add(Date.HOUR, 1), - location: entry.location, - subject: entry.title, - body: entry.description, - commonstart: new Date(entry.start), - commonend: (entry.end != null) ? - new Date(entry.end) : - new Date(entry.start).add(Date.HOUR, 1), - timezone: this.timezone, - parent_entryid: calendarFolder.get('entryid'), - store_entryid: calendarFolder.get('store_entryid') - }); - - var busystate = new Array("FREE", "TENTATIVE", "BUSY", "OOF"); - var zlabel = new Array("NONE", "IMPORTANT", "WORK", "PERSONAL", "HOLIDAY", "REQUIRED", "TRAVEL REQUIRED", "PREPARATION REQUIERED", "BIRTHDAY", "SPECIAL DATE", "PHONE INTERVIEW"); - - /* optional fields */ - if(entry.priority !== "") { - newRecord.data.importance = entry.priority; - } - if(entry.label !== "") { - newRecord.data.label = zlabel.indexOf(entry.label); - } - if(entry.busy !== "") { - newRecord.data.busystatus = busystate.indexOf(entry.busy); - } - if(entry.privatestate !== "") { - newRecord.data["private"] = entry.privatestate == "PUBLIC" ? false : true; - } - if(entry.organizer !== "") { - newRecord.data.sent_representing_email_address = entry.organizer; - } - if(entry.trigger != null) { - newRecord.data.reminder = true; - newRecord.data.reminder_minutes = new Date((entry.start - entry.trigger)/60); - newRecord.data.reminder_time = new Date(entry.trigger); - } else { - newRecord.data.reminder = false; - } - - return newRecord; - }, - importCheckedEvents: function () { var newRecords = this.eventgrid.selModel.getSelections(); this.importEvents(newRecords); @@ -584,295 +483,15 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, { this.importEvents(newRecords); }, - exportAllEvents: function () { - //receive existing calendar store - var calValue = this.calendarselector.value; - - if(calValue == undefined) { // no calendar choosen - Zarafa.common.dialogs.MessageBox.show({ - title : _('Error'), - msg : _('You have to choose a calendar!'), - icon : Zarafa.common.dialogs.MessageBox.ERROR, - buttons : Zarafa.common.dialogs.MessageBox.OK - }); - } else { - var calexist = true; - var calendarFolder = container.getHierarchyStore().getDefaultFolder('calendar'); - var pubStore = container.getHierarchyStore().getPublicStore(); - var pubSubFolders = []; - var pubFolder; - - if(typeof pubStore !== "undefined") { - try { - pubFolder = pubStore.getDefaultFolder("publicfolders"); - pubSubFolders = pubFolder.getChildren(); - } catch (e) { - console.log("Error opening the shared folder..."); - console.log(e); - } - } - - if(calValue != "calendar") { - var subFolders = calendarFolder.getChildren(); - var i = 0; - - /* add public folders if any exist */ - for(i = 0; i < pubSubFolders.length; i++) { - if(pubSubFolders[i].isContainerClass("IPF.Appointment")){ - subFolders.push(pubSubFolders[i]); - } - } - - for(i=0;i - * Copyright (C) 2012-2013 Christoph Haas + * Copyright (C) 2012-2016 Christoph Haas * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -19,136 +19,158 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ - + Ext.namespace("Zarafa.plugins.calendarimporter"); // Assign the right namespace Zarafa.plugins.calendarimporter.ImportPlugin = Ext.extend(Zarafa.core.Plugin, { // create new import plugin - /** - * @constructor - * @param {Object} config Configuration object - * - */ + /** + * @constructor + * @param {Object} config Configuration object + * + */ constructor: function (config) { config = config || {}; - + Zarafa.plugins.calendarimporter.ImportPlugin.superclass.constructor.call(this, config); }, - + /** * initialises insertion point for plugin * @protected */ - initPlugin : function() { + initPlugin: function () { Zarafa.plugins.calendarimporter.ImportPlugin.superclass.initPlugin.apply(this, arguments); - + /* our panel */ Zarafa.core.data.SharedComponentType.addProperty('plugins.calendarimporter.dialogs.importevents'); - + /* directly import received icals */ this.registerInsertionPoint('common.contextmenu.attachment.actions', this.createAttachmentImportButton); - /* add import button to south navigation */ - this.registerInsertionPoint("navigation.south", this.createImportButton, this); + /* add settings widget */ this.registerInsertionPoint('context.settings.category.calendar', this.createSettingsWidget); - + + /* export a calendar entry via rightclick */ + this.registerInsertionPoint('context.calendar.contextmenu.actions', this.createItemExportInsertionPoint, this); + /* ical sync stuff */ - if(container.getSettingsModel().get("zarafa/v1/plugins/calendarimporter/enable_sync") === true) { + if (container.getSettingsModel().get("zarafa/v1/plugins/calendarimporter/enable_sync") === true) { /* edit panel */ Zarafa.core.data.SharedComponentType.addProperty('plugins.calendarimporter.settings.dialogs.calsyncedit'); + /* enable the settings widget */ this.registerInsertionPoint('context.settings.category.calendar', this.createSettingsCalSyncWidget); } - }, - - /** - * Creates the button - * - * @return {Object} Configuration object for a {@link Ext.Button button} - * - */ - createImportButton: function () { - var button = { - xtype : 'button', - ref : "importbutton", - id : "importbutton", - text : _('Import Calendar'), - iconCls : 'icon_calendarimporter_button', - navigationContext : container.getContextByName('calendar'), - handler : this.onImportButtonClick, - scope : this - }; - - if(container.getSettingsModel().get("zarafa/v1/plugins/calendarimporter/enable_export")) { - button.text = _('Import/Export Calendar'); - } - - return button; - }, - + /** - * Creates the button - * - * @return {Object} Configuration object for a {@link Ext.Button button} - * - */ + * This method hooks to the contact context menu and allows users to export users to vcf. + * + * @param include + * @param btn + * @returns {Object} + */ + createItemExportInsertionPoint: function (include, btn) { + return { + text : dgettext('plugin_files', 'Export Event'), + handler: this.exportToICS.createDelegate(this, [btn]), + scope : this, + iconCls: 'icon_calendarimporter_export' + }; + }, + + /** + * Generates a request to download the selected records as vCard. + * @param {Ext.Button} btn + */ + exportToICS: function (btn) { + if (btn.records.length == 0) { + return; // skip if no records where given! + } + + var recordIds = []; + + for (var i = 0; i < btn.records.length; i++) { + recordIds.push(btn.records[i].get("entryid")); + } + + var responseHandler = new Zarafa.plugins.calendarimporter.data.ResponseHandler({ + successCallback: Zarafa.plugins.calendarimporter.data.Actions.downloadICS, + scope : this + }); + + // request attachment preperation + container.getRequest().singleRequest( + 'calendarmodule', + 'export', + { + storeid: btn.records[0].get("store_entryid"), + records: recordIds + }, + responseHandler + ); + }, + + /** + * Creates the button + * + * @return {Object} Configuration object for a {@link Ext.Button button} + * + */ createSettingsWidget: function () { return [{ - xtype : 'calendarimporter.settingswidget' + xtype: 'calendarimporter.settingswidget' }]; }, - + /** - * Creates the button - * - * @return {Object} Configuration object for a {@link Ext.Button button} - * - */ + * Creates the button + * + * @return {Object} Configuration object for a {@link Ext.Button button} + * + */ createSettingsCalSyncWidget: function () { return [{ - xtype : 'calendarimporter.settingscalsyncwidget' + xtype: 'calendarimporter.settingscalsyncwidget' }]; }, - + /** * Insert import button in all attachment suggestions - + * @return {Object} Configuration object for a {@link Ext.Button button} */ - createAttachmentImportButton : function(include, btn) { + createAttachmentImportButton: function (include, btn) { return { - text : _('Import Calendar'), - handler : this.getAttachmentFileName.createDelegate(this, [btn, this.gotAttachmentFileName]), - scope : this, - iconCls : 'icon_calendarimporter_button', - beforeShow : function(item, record) { + text : _('Import to Calendar'), + handler : this.getAttachmentFileName.createDelegate(this, [btn]), + scope : this, + iconCls : 'icon_calendarimporter_button', + beforeShow: function (item, record) { var extension = record.data.name.split('.').pop().toLowerCase(); - - if(record.data.filetype == "text/calendar" || extension == "ics" || extension == "ifb" || extension == "ical" || extension == "ifbf") { - item.setDisabled(false); + + if (record.data.filetype == "text/calendar" || extension == "ics" || extension == "ifb" || extension == "ical" || extension == "ifbf") { + item.setVisible(true); } else { - item.setDisabled(true); + item.setVisible(false); } } }; }, - + /** * Callback for getAttachmentFileName */ - gotAttachmentFileName: function(response) { - if(response.status == true) { - Zarafa.core.data.UIFactory.openLayerComponent(Zarafa.core.data.SharedComponentType['plugins.calendarimporter.dialogs.importevents'], undefined, { - manager : Ext.WindowMgr, - filename : response.tmpname - }); + gotAttachmentFileName: function (response) { + if (response.status == true) { + this.scope.openImportDialog(response.tmpname); } else { Zarafa.common.dialogs.MessageBox.show({ - title : _('Error'), - msg : _(response["message"]), - icon : Zarafa.common.dialogs.MessageBox.ERROR, - buttons : Zarafa.common.dialogs.MessageBox.OK + title : _('Error'), + msg : _(response["message"]), + icon : Zarafa.common.dialogs.MessageBox.ERROR, + buttons: Zarafa.common.dialogs.MessageBox.OK }); } }, @@ -158,71 +180,78 @@ Zarafa.plugins.calendarimporter.ImportPlugin = Ext.extend(Zarafa.core.Plugin, { */ getAttachmentFileName: function (btn, callback) { Zarafa.common.dialogs.MessageBox.show({ - title: 'Please wait', - msg: 'Loading attachment...', + title : 'Please wait', + msg : 'Loading attachment...', progressText: 'Initializing...', - width:300, - progress:true, - closable:false + width : 300, + progress : true, + closable : false }); // progress bar... ;) - var f = function(v){ - return function(){ - if(v == 100){ + var f = function (v) { + return function () { + if (v == 100) { Zarafa.common.dialogs.MessageBox.hide(); - }else{ - Zarafa.common.dialogs.MessageBox.updateProgress(v/100, Math.round(v)+'% loaded'); + } else { + Zarafa.common.dialogs.MessageBox.updateProgress(v / 100, Math.round(v) + '% loaded'); } - }; + }; }; - - for(var i = 1; i < 101; i++){ - setTimeout(f(i), 20*i); + + for (var i = 1; i < 101; i++) { + setTimeout(f(i), 20 * i); } - + /* store the attachment to a temporary folder and prepare it for uploading */ var attachmentRecord = btn.records; var attachmentStore = attachmentRecord.store; - + var store = attachmentStore.getParentRecord().get('store_entryid'); var entryid = attachmentStore.getAttachmentParentRecordEntryId(); var attachNum = new Array(1); - if (attachmentRecord.get('attach_num') != -1) + if (attachmentRecord.get('attach_num') != -1) { attachNum[0] = attachmentRecord.get('attach_num'); - else + } else { attachNum[0] = attachmentRecord.get('tmpname'); + } var dialog_attachments = attachmentStore.getId(); var filename = attachmentRecord.data.name; - + var responseHandler = new Zarafa.plugins.calendarimporter.data.ResponseHandler({ - successCallback: callback + successCallback: this.gotAttachmentFileName, + scope : this }); - + // request attachment preperation container.getRequest().singleRequest( 'calendarmodule', - 'attachmentpath', + 'importattachment', { - entryid : entryid, - store: store, - attachNum: attachNum, + entryid : entryid, + store : store, + attachNum : attachNum, dialog_attachments: dialog_attachments, - filename: filename + filename : filename }, responseHandler ); }, - + /** - * Clickhandler for the button + * Open the import dialog. + * @param {String} filename */ - onImportButtonClick: function () { - Zarafa.core.data.UIFactory.openLayerComponent(Zarafa.core.data.SharedComponentType['plugins.calendarimporter.dialogs.importevents'], undefined, { - manager : Ext.WindowMgr - }); + openImportDialog: function (filename) { + var componentType = Zarafa.core.data.SharedComponentType['plugins.calendarimporter.dialogs.importevents']; + var config = { + filename: filename, + modal : true + }; + + Zarafa.core.data.UIFactory.openLayerComponent(componentType, undefined, config); }, - + /** * Bid for the type of shared component * and the given record. @@ -231,15 +260,22 @@ Zarafa.plugins.calendarimporter.ImportPlugin = Ext.extend(Zarafa.core.Plugin, { * @param {Ext.data.Record} record Optionally passed record. * @return {Number} The bid for the shared component */ - bidSharedComponent : function(type, record) { + bidSharedComponent: function (type, record) { var bid = -1; - switch(type) { + switch (type) { case Zarafa.core.data.SharedComponentType['plugins.calendarimporter.dialogs.importevents']: bid = 2; break; case Zarafa.core.data.SharedComponentType['plugins.calendarimporter.settings.dialogs.calsyncedit']: bid = 2; break; + case Zarafa.core.data.SharedComponentType['common.contextmenu']: + if (record instanceof Zarafa.core.data.MAPIRecord) { + if (record.get('object_type') == Zarafa.core.mapi.ObjectType.MAPI_FOLDER && record.get('container_class') == "IPF.Appointment") { + bid = 2; + } + } + break; } return bid; }, @@ -251,15 +287,18 @@ Zarafa.plugins.calendarimporter.ImportPlugin = Ext.extend(Zarafa.core.Plugin, { * @param {Ext.data.Record} record Optionally passed record. * @return {Ext.Component} Component */ - getSharedComponent : function(type, record) { + getSharedComponent: function (type, record) { var component; - switch(type) { + switch (type) { case Zarafa.core.data.SharedComponentType['plugins.calendarimporter.dialogs.importevents']: component = Zarafa.plugins.calendarimporter.dialogs.ImportContentPanel; break; case Zarafa.core.data.SharedComponentType['plugins.calendarimporter.settings.dialogs.calsyncedit']: component = Zarafa.plugins.calendarimporter.settings.dialogs.CalSyncEditContentPanel; break; + case Zarafa.core.data.SharedComponentType['common.contextmenu']: + component = Zarafa.plugins.calendarimporter.ui.ContextMenu; + break; } return component; @@ -270,11 +309,11 @@ Zarafa.plugins.calendarimporter.ImportPlugin = Ext.extend(Zarafa.core.Plugin, { /*############################################################################################################################* * STARTUP *############################################################################################################################*/ -Zarafa.onReady(function() { +Zarafa.onReady(function () { container.registerPlugin(new Zarafa.core.PluginMetaData({ - name : 'calendarimporter', - displayName : _('Calendarimporter Plugin'), - about : Zarafa.plugins.calendarimporter.ABOUT, - pluginConstructor : Zarafa.plugins.calendarimporter.ImportPlugin + name : 'calendarimporter', + displayName : _('Calendarimporter Plugin'), + about : Zarafa.plugins.calendarimporter.ABOUT, + pluginConstructor: Zarafa.plugins.calendarimporter.ImportPlugin })); }); diff --git a/js/settings/SettingsCalSyncWidget.js b/js/settings/SettingsCalSyncWidget.js index aacaed0..1c5efac 100644 --- a/js/settings/SettingsCalSyncWidget.js +++ b/js/settings/SettingsCalSyncWidget.js @@ -27,6 +27,7 @@ Zarafa.plugins.calendarimporter.settings.SettingsCalSyncWidget = Ext.extend(Zara { name : 'pass' }, { name : 'intervall', type : 'int' }, { name : 'calendar' }, + { name : 'calendarname' }, { name : 'lastsync' } ], sortInfo : { @@ -68,7 +69,9 @@ Zarafa.plugins.calendarimporter.settings.SettingsCalSyncWidget = Ext.extend(Zara var icslinks = settingsModel.get('zarafa/v1/contexts/calendar/icssync', true); var syncArray = []; for (var key in icslinks) { - syncArray.push(Ext.apply({}, icslinks[key], { id : key })); + if(icslinks.hasOwnProperty(key)) { // skip inherited props + syncArray.push(Ext.apply({}, icslinks[key], {id: key})); + } } // Load all icslinks into the GridPanel @@ -98,7 +101,8 @@ Zarafa.plugins.calendarimporter.settings.SettingsCalSyncWidget = Ext.extend(Zara 'user' : icslink.get('user'), 'pass' : icslink.get('pass'), 'lastsync' : icslink.get('lastsync'), - 'calendar' : icslink.get('calendar') + 'calendar' : icslink.get('calendar'), + 'calendarname' : Zarafa.plugins.calendarimporter.data.Actions.getCalendarFolderByEntryid(icslink.get('calendar')).display_name }; } settingsModel.set('zarafa/v1/contexts/calendar/icssync', icslinkData); diff --git a/js/settings/SettingsWidget.js b/js/settings/SettingsWidget.js index eb1b889..5d3e7e1 100644 --- a/js/settings/SettingsWidget.js +++ b/js/settings/SettingsWidget.js @@ -24,13 +24,6 @@ Zarafa.plugins.calendarimporter.settings.SettingsWidget = Ext.extend(Zarafa.sett title : _('Calendar Import/Export plugin settings'), xtype : 'calendarimporter.settingswidget', items : [ - { - xtype : 'checkbox', - name : 'zarafa/v1/plugins/calendarimporter/enable_export', - ref : 'enableExport', - fieldLabel : 'Enable exporter', - lazyInit : false - }, { xtype : 'checkbox', name : 'zarafa/v1/plugins/calendarimporter/enable_sync', @@ -47,43 +40,14 @@ Zarafa.plugins.calendarimporter.settings.SettingsWidget = Ext.extend(Zarafa.sett }, createSelectBox: function() { - var defaultFolder = container.getHierarchyStore().getDefaultFolder('calendar'); // @type: Zarafa.hierarchy.data.MAPIFolderRecord - var subFolders = defaultFolder.getChildren(); - var myStore = []; - - /* add all local calendar folders */ - var i = 0; - myStore.push(new Array(defaultFolder.getDefaultFolderKey(), defaultFolder.getDisplayName())); - for(i = 0; i < subFolders.length; i++) { - /* Store all subfolders */ - myStore.push(new Array(subFolders[i].getDisplayName(), subFolders[i].getDisplayName(), false)); // 3rd field = isPublicfolder - } - - /* add all shared calendar folders */ - var pubStore = container.getHierarchyStore().getPublicStore(); - - if(typeof pubStore !== "undefined") { - try { - var pubFolder = pubStore.getDefaultFolder("publicfolders"); - var pubSubFolders = pubFolder.getChildren(); - - for(i = 0; i < pubSubFolders.length; i++) { - if(pubSubFolders[i].isContainerClass("IPF.Appointment")){ - myStore.push(new Array(pubSubFolders[i].getDisplayName(), pubSubFolders[i].getDisplayName() + " [Shared]", true)); // 3rd field = isPublicfolder - } - } - } catch (e) { - console.log("Error opening the shared folder..."); - console.log(e); - } - } - + var myStore = Zarafa.plugins.calendarimporter.data.Actions.getAllCalendarFolders(true); + return { xtype: "selectbox", ref : 'defaultCalendar', editable: false, name: "zarafa/v1/plugins/calendarimporter/default_calendar", - value: container.getSettingsModel().get("zarafa/v1/plugins/calendarimporter/default_calendar"), + value: Zarafa.plugins.calendarimporter.data.Actions.getCalendarFolderByName(container.getSettingsModel().get("zarafa/v1/plugins/calendarimporter/default_calendar")).entryid, width: 100, fieldLabel: "Default calender", store: myStore, @@ -123,9 +87,8 @@ Zarafa.plugins.calendarimporter.settings.SettingsWidget = Ext.extend(Zarafa.sett * @param {Zarafa.settings.SettingsModel} settingsModel The settings to load */ update : function(settingsModel) { - this.enableExport.setValue(settingsModel.get(this.enableExport.name)); this.enableSync.setValue(settingsModel.get(this.enableSync.name)); - this.defaultCalendar.setValue(settingsModel.get(this.defaultCalendar.name)); + this.defaultCalendar.setValue(Zarafa.plugins.calendarimporter.data.Actions.getCalendarFolderByName(settingsModel.get(this.defaultCalendar.name)).entryid); this.defaultTimezone.setValue(settingsModel.get(this.defaultTimezone.name)); }, @@ -136,11 +99,115 @@ Zarafa.plugins.calendarimporter.settings.SettingsWidget = Ext.extend(Zarafa.sett * @param {Zarafa.settings.SettingsModel} settingsModel The settings to update */ updateSettings : function(settingsModel) { - settingsModel.set(this.enableExport.name, this.enableExport.getValue()); - settingsModel.set(this.enableSync.name, this.enableSync.getValue()); - settingsModel.set(this.defaultCalendar.name, this.defaultCalendar.getValue()); - settingsModel.set(this.defaultTimezone.name, this.defaultTimezone.getValue()); - } + // check if the user changed a value + var changed = false; + + if(settingsModel.get(this.enableSync.name) != this.enableSync.getValue()) { + changed = true; + } else if(settingsModel.get(this.defaultCalendar.name) != Zarafa.plugins.calendarimporter.data.Actions.getCalendarFolderByEntryid(this.defaultCalendar.getValue()).display_name) { + changed = true; + } else if(settingsModel.get(this.defaultTimezone.name) != this.defaultTimezone.getValue()) { + changed = true; + } + + if(changed) { + // Really save changes + settingsModel.set(this.enableSync.name, this.enableSync.getValue()); + settingsModel.set(this.defaultCalendar.name, Zarafa.plugins.calendarimporter.data.Actions.getCalendarFolderByEntryid(this.defaultCalendar.getValue()).display_name); // store name + settingsModel.set(this.defaultTimezone.name, this.defaultTimezone.getValue()); + + this.onUpdateSettings(); + } + }, + + /** + * Called after the {@link Zarafa.settings.SettingsModel} fires the {@link Zarafa.settings.SettingsModel#save save} + * event to indicate the settings were successfully saved and it will forcefully realod the webapp. + * settings which were saved to the server. + * @private + */ + onUpdateSettings : function() + { + var message = _('Your WebApp needs to be reloaded to make the changes visible!'); + message += '

'; + message += _('WebApp will automatically restart in order for these changes to take effect'); + message += '
'; + + Zarafa.common.dialogs.MessageBox.addCustomButtons({ + title: _('Restart WebApp'), + msg : message, + icon: Ext.MessageBox.QUESTION, + fn : this.restartWebapp, + customButton : [{ + text : _('Restart'), + name : 'restart' + }, { + text : _('Cancel'), + name : 'cancel' + }], + scope : this + }); + + }, + + /** + * Event handler for {@link #onResetSettings}. This will check if the user + * wishes to reset the default settings or not. + * @param {String} button The button which user pressed. + * @private + */ + restartWebapp : function(button) + { + if (button === 'restart') { + var contextModel = this.ownerCt.settingsContext.getModel(); + var realModel = contextModel.getRealSettingsModel(); + + realModel.save(); + + this.loadMask = new Zarafa.common.ui.LoadMask(Ext.getBody(), { + msg : '' + _('Webapp is reloading, Please wait.') + '' + }); + this.loadMask.show(); + + this.mon(realModel, 'save', this.onSettingsSave, this); + this.mon(realModel, 'exception', this.onSettingsException, this); + } + + }, + + /** + * Called when the {@link Zarafa.settings.} fires the {@link Zarafa.settings.SettingsModel#save save} + * event to indicate the settings were successfully saved and it will forcefully realod the webapp. + * @param {Zarafa.settings.SettingsModel} model The model which fired the event. + * @param {Object} parameters The key-value object containing the action and the corresponding + * settings which were saved to the server. + * @private + */ + onSettingsSave : function(model, parameters) + { + this.mun(model, 'save', this.onSettingsSave, this); + Zarafa.core.Util.reloadWebapp(); + }, + + /** + * Called when the {@link Zarafa.settings.SettingsModel} fires the {@link Zarafa.settings.SettingsModel#exception exception} + * event to indicate the settings were not successfully saved. + * @param {Zarafa.settings.SettingsModel} model The settings model which fired the event + * @param {String} type The value of this parameter will be either 'response' or 'remote'. + * @param {String} action Name of the action (see {@link Ext.data.Api#actions}). + * @param {Object} options The object containing a 'path' and 'value' field indicating + * respectively the Setting and corresponding value for the setting which was being saved. + * @param {Object} response The response object as received from the PHP-side + * @private + */ + onSettingsException : function(model, type, action, options, response) + { + this.loadMask.hide(); + + // Remove event handlers + this.mun(model, 'save', this.onSettingsSave, this); + this.mun(model, 'exception', this.onSettingsException, this); + } }); Ext.reg('calendarimporter.settingswidget', Zarafa.plugins.calendarimporter.settings.SettingsWidget); diff --git a/js/settings/dialogs/CalSyncEditContentPanel.js b/js/settings/dialogs/CalSyncEditContentPanel.js index 09a328f..ce480b0 100644 --- a/js/settings/dialogs/CalSyncEditContentPanel.js +++ b/js/settings/dialogs/CalSyncEditContentPanel.js @@ -23,7 +23,7 @@ Zarafa.plugins.calendarimporter.settings.dialogs.CalSyncEditContentPanel = Ext.e model : true, autoSave : false, width : 400, - height : 350, + height : 400, title : _('ICAL Sync'), items : [{ xtype : 'calendarimporter.calsynceditpanel', diff --git a/js/settings/dialogs/CalSyncEditPanel.js b/js/settings/dialogs/CalSyncEditPanel.js index 1c664c9..a2d78ac 100644 --- a/js/settings/dialogs/CalSyncEditPanel.js +++ b/js/settings/dialogs/CalSyncEditPanel.js @@ -59,8 +59,7 @@ Zarafa.plugins.calendarimporter.settings.dialogs.CalSyncEditPanel = Ext.extend(E var store = this.dialog.store; var id = 0; var record = undefined; - - console.log(this); + if(!this.currentItem) { record = new store.recordType({ id: this.hashCode(this.icsurl.getValue()), @@ -69,6 +68,7 @@ Zarafa.plugins.calendarimporter.settings.dialogs.CalSyncEditPanel = Ext.extend(E user: this.user.getValue(), pass: Ext.util.base64.encode(this.pass.getValue()), calendar: this.calendar.getValue(), + calendarname : Zarafa.plugins.calendarimporter.data.Actions.getCalendarFolderByEntryid(this.calendar.getValue()).display_name, lastsync: "never" }); } @@ -82,6 +82,7 @@ Zarafa.plugins.calendarimporter.settings.dialogs.CalSyncEditPanel = Ext.extend(E this.currentItem.set('user', this.user.getValue()); this.currentItem.set('pass', Ext.util.base64.encode(this.pass.getValue())); this.currentItem.set('calendar', this.calendar.getValue()); + this.currentItem.set('calendarname', Zarafa.plugins.calendarimporter.data.Actions.getCalendarFolderByEntryid(this.calendar.getValue()).display_name); } this.dialog.close(); } @@ -95,48 +96,20 @@ Zarafa.plugins.calendarimporter.settings.dialogs.CalSyncEditPanel = Ext.extend(E createPanelItems : function(config) { var icsurl = ""; - var intervall = ""; + var intervall = "15"; var user = ""; var pass = ""; - var calendar = ""; - - var defaultFolder = container.getHierarchyStore().getDefaultFolder('calendar'); // @type: Zarafa.hierarchy.data.MAPIFolderRecord - var subFolders = defaultFolder.getChildren(); - var myStore = []; - - if(config.item){ + var calendarname = ""; + var calendar = Zarafa.plugins.calendarimporter.data.Actions.getCalendarFolderByName(container.getSettingsModel().get("zarafa/v1/plugins/calendarimporter/default_calendar")).entryid; + var myStore = Zarafa.plugins.calendarimporter.data.Actions.getAllCalendarFolders(true); + + if(config.item){ icsurl = config.item.get('icsurl'); intervall = config.item.get('intervall'); user = config.item.get('user'); pass = Ext.util.base64.decode(config.item.get('pass')); calendar = config.item.get('calendar'); - } - - /* add all local calendar folders */ - var i = 0; - myStore.push(new Array(defaultFolder.getDefaultFolderKey(), defaultFolder.getDisplayName())); - for(i = 0; i < subFolders.length; i++) { - /* Store all subfolders */ - myStore.push(new Array(subFolders[i].getDisplayName(), subFolders[i].getDisplayName(), false)); // 3rd field = isPublicfolder - } - - /* add all shared calendar folders */ - var pubStore = container.getHierarchyStore().getPublicStore(); - - if(typeof pubStore !== "undefined") { - try { - var pubFolder = pubStore.getDefaultFolder("publicfolders"); - var pubSubFolders = pubFolder.getChildren(); - - for(i = 0; i < pubSubFolders.length; i++) { - if(pubSubFolders[i].isContainerClass("IPF.Appointment")){ - myStore.push(new Array(pubSubFolders[i].getDisplayName(), pubSubFolders[i].getDisplayName() + " [Shared]", true)); // 3rd field = isPublicfolder - } - } - } catch (e) { - console.log("Error opening the shared folder..."); - console.log(e); - } + calendarname = config.item.get('calendarname'); } diff --git a/js/settings/ui/CalSyncGrid.js b/js/settings/ui/CalSyncGrid.js index 7535659..6295ac6 100644 --- a/js/settings/ui/CalSyncGrid.js +++ b/js/settings/ui/CalSyncGrid.js @@ -58,6 +58,16 @@ Zarafa.plugins.calendarimporter.settings.ui.CalSyncGrid = Ext.extend(Ext.grid.Gr return value ? "true" : "false"; }, + /** + * Render function + * @return {String} + * @private + */ + renderCalendarColumn : function(value, p, record) + { + return Zarafa.plugins.calendarimporter.data.Actions.getCalendarFolderByEntryid(value).display_name; + }, + /** * Creates a column model object, used in {@link #colModel} config * @return {Ext.grid.ColumnModel} column model object @@ -71,7 +81,7 @@ Zarafa.plugins.calendarimporter.settings.ui.CalSyncGrid = Ext.extend(Ext.grid.Gr renderer : Zarafa.common.ui.grid.Renderers.text }, { - dataIndex : 'calendar', + dataIndex : 'calendarname', header : _('Destination Calender'), renderer : Zarafa.common.ui.grid.Renderers.text }, diff --git a/js/ui/ContextMenu.js b/js/ui/ContextMenu.js new file mode 100644 index 0000000..f66c90c --- /dev/null +++ b/js/ui/ContextMenu.js @@ -0,0 +1,129 @@ +/** + * ContectMenu.js zarafa calender to ics im/exporter + * + * Author: Christoph Haas + * Copyright (C) 2012-2016 Christoph Haas + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +Ext.namespace('Zarafa.plugins.calendarimporter.ui'); + +/** + * @class Zarafa.plugins.calendarimporter.ui.ContextMenu + * @extends Zarafa.hierarchy.ui.ContextMenu + * @xtype calendarimporter.hierarchycontextmenu + */ +Zarafa.plugins.calendarimporter.ui.ContextMenu = Ext.extend(Zarafa.hierarchy.ui.ContextMenu, { + + /** + * @constructor + * @param {Object} config Configuration object + */ + constructor: function (config) { + config = config || {}; + + if (config.contextNode) { + config.contextTree = config.contextNode.getOwnerTree(); + } + + Zarafa.plugins.calendarimporter.ui.ContextMenu.superclass.constructor.call(this, config); + + // add item to menu + var additionalItems = this.createAdditionalContextMenuItems(config); + for (var i = 0; i < additionalItems.length; i++) { + config.items[0].push(additionalItems[i]); + } + + Zarafa.plugins.calendarimporter.ui.ContextMenu.superclass.constructor.call(this, config); // redo ... otherwise menu does not get published + }, + + /** + * Create the Action context menu items. + * @param {Object} config Configuration object for the {@link Zarafa.plugins.calendarimporter.ui.ContextMenu ContextMenu} + * @return {Zarafa.core.ui.menu.ConditionalItem[]} The list of Action context menu items + * @private + * + * Note: All handlers are called within the scope of {@link Zarafa.plugins.calendarimporter.ui.ContextMenu HierarchyContextMenu} + */ + createAdditionalContextMenuItems: function (config) { + return [{ + xtype: 'menuseparator' + }, { + text : _('Import Calendar'), + iconCls : 'icon_calendarimporter_import', + handler : this.onContextItemImport, + beforeShow: function (item, record) { + var access = record.get('access') & Zarafa.core.mapi.Access.ACCESS_MODIFY; + if (!access || (record.isIPMSubTree() && !record.getMAPIStore().isDefaultStore())) { + item.setDisabled(true); + } else { + item.setDisabled(false); + } + } + }, { + text : _('Export Calendar'), + iconCls : 'icon_calendarimporter_export', + handler : this.onContextItemExport, + beforeShow: function (item, record) { + var access = record.get('access') & Zarafa.core.mapi.Access.ACCESS_READ; + if (!access || (record.isIPMSubTree() && !record.getMAPIStore().isDefaultStore())) { + item.setDisabled(true); + } else { + item.setDisabled(false); + } + } + }]; + }, + + /** + * Fires on selecting 'Open' menu option from {@link Zarafa.plugins.calendarimporter.ui.ContextMenu ContextMenu} + * @private + */ + onContextItemExport: function () { + var responseHandler = new Zarafa.plugins.calendarimporter.data.ResponseHandler({ + successCallback: Zarafa.plugins.calendarimporter.data.Actions.downloadICS, + scope : this + }); + + // request attachment preperation + container.getRequest().singleRequest( + 'calendarmodule', + 'export', + { + storeid: this.records.get("store_entryid"), + folder : this.records.get("entryid") + }, + responseHandler + ); + }, + + /** + * Fires on selecting 'Open' menu option from {@link Zarafa.plugins.calendarimporter.ui.ContextMenu ContextMenu} + * @private + */ + onContextItemImport: function () { + var componentType = Zarafa.core.data.SharedComponentType['plugins.calendarimporter.dialogs.importevents']; + var config = { + modal : true, + folder: this.records.get("entryid") + }; + + Zarafa.core.data.UIFactory.openLayerComponent(componentType, undefined, config); + } +}); + +Ext.reg('calendarimporter.hierarchycontextmenu', Zarafa.plugins.calendarimporter.ui.ContextMenu); \ No newline at end of file diff --git a/manifest.xml b/manifest.xml index d6303bc..00e0852 100644 --- a/manifest.xml +++ b/manifest.xml @@ -2,7 +2,7 @@ - @_@PLUGIN_VERSION@_@ + 2.2.0 calendarimporter ICS Calendar Importer/Exporter Christoph Haas @@ -20,13 +20,14 @@ php/module.calendar.php - js/calendarimporter.js + js/calendarimporter-debug.js js/calendarimporter-debug.js js/data/timezones.js - js/external/Ext.util.base64.js - js/plugin.calendarimporter.js + js/data/Actions.js js/data/ResponseHandler.js + js/external/Ext.util.base64.js + js/ui/ContextMenu.js js/dialogs/ImportContentPanel.js js/dialogs/ImportPanel.js js/dialogs/settings/SettingsWidget.js @@ -35,9 +36,10 @@ js/dialogs/settings/ui/CalSyncPanel.js js/dialogs/settings/dialogs/CalSyncEditContentPanel.js js/dialogs/settings/dialogs/CalSyncEditPanel.js + js/plugin.calendarimporter.js - resources/css/calendarimporter-min.css + resources/css/calendarimporter.css resources/css/calendarimporter.css resources/css/calendarimporter-main.css diff --git a/php/.gitignore b/php/.gitignore new file mode 100644 index 0000000..3d60449 --- /dev/null +++ b/php/.gitignore @@ -0,0 +1,5 @@ +composer.phar +.composer.lock +composer.lock +vendor +vendor/* diff --git a/php/composer.json b/php/composer.json new file mode 100644 index 0000000..aa0fd8e --- /dev/null +++ b/php/composer.json @@ -0,0 +1,5 @@ +{ + "require": { + "sabre/vobject": "4.1" + } +} \ No newline at end of file diff --git a/php/download.php b/php/download.php index f94d39e..8f64548 100644 --- a/php/download.php +++ b/php/download.php @@ -1,9 +1,10 @@ - * Copyright (C) 2012-2014 Christoph Haas + * Copyright (C) 2012-2016 Christoph Haas * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,25 +21,54 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ -$basedir = $_GET["basedir"]; -$secid = $_GET["secid"]; -$fileid = $_GET["fileid"]; -$realname = $_GET["realname"]; +namespace calendarimporter; -$secfile = $basedir . "/secid." . $secid; -$icsfile = $basedir . "/" . $fileid . "." . $secid; +class DownloadHandler +{ + /** + * Download the given vcf file. + * @return bool + */ + public static function doDownload() + { + if (isset($_GET["token"])) { + $token = $_GET["token"]; + } else { + return false; + } -// if the secid file exists -> download! -if(file_exists($secfile)) { - @header("Last-Modified: " . @gmdate("D, d M Y H:i:s",time()) . " GMT"); - @header("Content-type: text/calendar"); - header("Content-Length: " . filesize($icsfile)); - header("Content-Disposition: attachment; filename=" . $realname . ".ics"); + if (isset($_GET["filename"])) { + $filename = $_GET["filename"]; + } else { + return false; + } - //write ics - readfile($icsfile); - unlink($secfile); - unlink($icsfile); -} + // validate token + if (!ctype_alnum($token)) { // token is a md5 hash + return false; + } -?> \ No newline at end of file + $file = PLUGIN_CALENDARIMPORTER_TMP_UPLOAD . "ics_" . $token . ".ics"; + + if (!file_exists($file)) { // invalid token + return false; + } + + // set headers here + header('Content-Disposition: attachment; filename="' . $filename . '"'); + + // no caching + header('Expires: 0'); // set expiration time + header('Content-Description: File Transfer'); + header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); + header('Content-Length: ' . filesize($file)); + header('Content-Type: application/octet-stream'); + header('Pragma: public'); + flush(); + + // print the downloaded file + readfile($file); + ignore_user_abort(true); + unlink($file); + } +} \ No newline at end of file diff --git a/php/ical/class.icalcreator.php b/php/ical/class.icalcreator.php deleted file mode 100644 index 4c457fd..0000000 --- a/php/ical/class.icalcreator.php +++ /dev/null @@ -1,10458 +0,0 @@ - - * @since 2.9.6 - 2011-05-14 - */ -class vcalendar { - // calendar property variables - var $calscale; - var $method; - var $prodid; - var $version; - var $xprop; - // container for calendar components - var $components; - // component config variables - var $allowEmpty; - var $unique_id; - var $language; - var $directory; - var $filename; - var $url; - var $delimiter; - var $nl; - var $format; - var $dtzid; - // component internal variables - var $attributeDelimiter; - var $valueInit; - // component xCal declaration container - var $xcaldecl; -/** - * constructor for calendar object - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.9.6 - 2011-05-14 - * @param array $config - * @return void - */ - function vcalendar ( $config = array()) { - $this->_makeVersion(); - $this->calscale = null; - $this->method = null; - $this->_makeUnique_id(); - $this->prodid = null; - $this->xprop = array(); - $this->language = null; - $this->directory = null; - $this->filename = null; - $this->url = null; - $this->dtzid = null; -/** - * language = - */ - if( defined( 'ICAL_LANG' ) && !isset( $config['language'] )) - $config['language'] = ICAL_LANG; - if( !isset( $config['allowEmpty'] )) $config['allowEmpty'] = TRUE; - if( !isset( $config['nl'] )) $config['nl'] = "\r\n"; - if( !isset( $config['format'] )) $config['format'] = 'iCal'; - if( !isset( $config['delimiter'] )) $config['delimiter'] = DIRECTORY_SEPARATOR; - $this->setConfig( $config ); - - $this->xcaldecl = array(); - $this->components = array(); - } -/*********************************************************************************/ -/** - * Property Name: CALSCALE - */ -/** - * creates formatted output for calendar property calscale - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.10.16 - 2011-10-28 - * @return string - */ - function createCalscale() { - if( empty( $this->calscale )) return FALSE; - switch( $this->format ) { - case 'xcal': - return $this->nl.' calscale="'.$this->calscale.'"'; - break; - default: - return 'CALSCALE:'.$this->calscale.$this->nl; - break; - } - } -/** - * set calendar property calscale - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.4.8 - 2008-10-21 - * @param string $value - * @return void - */ - function setCalscale( $value ) { - if( empty( $value )) return FALSE; - $this->calscale = $value; - } -/*********************************************************************************/ -/** - * Property Name: METHOD - */ -/** - * creates formatted output for calendar property method - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.10.16 - 2011-10-28 - * @return string - */ - function createMethod() { - if( empty( $this->method )) return FALSE; - switch( $this->format ) { - case 'xcal': - return $this->nl.' method="'.$this->method.'"'; - break; - default: - return 'METHOD:'.$this->method.$this->nl; - break; - } - } -/** - * set calendar property method - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.4.8 - 2008-20-23 - * @param string $value - * @return bool - */ - function setMethod( $value ) { - if( empty( $value )) return FALSE; - $this->method = $value; - return TRUE; - } -/*********************************************************************************/ -/** - * Property Name: PRODID - * - * The identifier is RECOMMENDED to be the identical syntax to the - * [RFC 822] addr-spec. A good method to assure uniqueness is to put the - * domain name or a domain literal IP address of the host on which.. . - */ -/** - * creates formatted output for calendar property prodid - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.12.11 - 2012-05-13 - * @return string - */ - function createProdid() { - if( !isset( $this->prodid )) - $this->_makeProdid(); - switch( $this->format ) { - case 'xcal': - return $this->nl.' prodid="'.$this->prodid.'"'; - break; - default: - $toolbox = new calendarComponent(); - $toolbox->setConfig( $this->getConfig()); - return $toolbox->_createElement( 'PRODID', '', $this->prodid ); - break; - } - } -/** - * make default value for calendar prodid - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.6.8 - 2009-12-30 - * @return void - */ - function _makeProdid() { - $this->prodid = '-//'.$this->unique_id.'//'.ICALCREATOR_VERSION.'//'.strtoupper( $this->language ); - } -/** - * Conformance: The property MUST be specified once in an iCalendar object. - * Description: The vendor of the implementation SHOULD assure that this - * is a globally unique identifier; using some technique such as an FPI - * value, as defined in [ISO 9070]. - */ -/** - * make default unique_id for calendar prodid - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 0.3.0 - 2006-08-10 - * @return void - */ - function _makeUnique_id() { - $this->unique_id = ( isset( $_SERVER['SERVER_NAME'] )) ? gethostbyname( $_SERVER['SERVER_NAME'] ) : 'localhost'; - } -/*********************************************************************************/ -/** - * Property Name: VERSION - * - * Description: A value of "2.0" corresponds to this memo. - */ -/** - * creates formatted output for calendar property version - - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.10.16 - 2011-10-28 - * @return string - */ - function createVersion() { - if( empty( $this->version )) - $this->_makeVersion(); - switch( $this->format ) { - case 'xcal': - return $this->nl.' version="'.$this->version.'"'; - break; - default: - return 'VERSION:'.$this->version.$this->nl; - break; - } - } -/** - * set default calendar version - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 0.3.0 - 2006-08-10 - * @return void - */ - function _makeVersion() { - $this->version = '2.0'; - } -/** - * set calendar version - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.4.8 - 2008-10-23 - * @param string $value - * @return void - */ - function setVersion( $value ) { - if( empty( $value )) return FALSE; - $this->version = $value; - return TRUE; - } -/*********************************************************************************/ -/** - * Property Name: x-prop - */ -/** - * creates formatted output for calendar property x-prop, iCal format only - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.16.2 - 2012-12-18 - * @return string - */ - function createXprop() { - if( empty( $this->xprop ) || !is_array( $this->xprop )) return FALSE; - $output = null; - $toolbox = new calendarComponent(); - $toolbox->setConfig( $this->getConfig()); - foreach( $this->xprop as $label => $xpropPart ) { - if( !isset($xpropPart['value']) || ( empty( $xpropPart['value'] ) && !is_numeric( $xpropPart['value'] ))) { - $output .= $toolbox->_createElement( $label ); - continue; - } - $attributes = $toolbox->_createParams( $xpropPart['params'], array( 'LANGUAGE' )); - if( is_array( $xpropPart['value'] )) { - foreach( $xpropPart['value'] as $pix => $theXpart ) - $xpropPart['value'][$pix] = iCalUtilityFunctions::_strrep( $theXpart, $this->format, $this->nl ); - $xpropPart['value'] = implode( ',', $xpropPart['value'] ); - } - else - $xpropPart['value'] = iCalUtilityFunctions::_strrep( $xpropPart['value'], $this->format, $this->nl ); - $output .= $toolbox->_createElement( $label, $attributes, $xpropPart['value'] ); - if( is_array( $toolbox->xcaldecl ) && ( 0 < count( $toolbox->xcaldecl ))) { - foreach( $toolbox->xcaldecl as $localxcaldecl ) - $this->xcaldecl[] = $localxcaldecl; - } - } - return $output; - } -/** - * set calendar property x-prop - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.11.9 - 2012-01-16 - * @param string $label - * @param string $value - * @param array $params optional - * @return bool - */ - function setXprop( $label, $value, $params=FALSE ) { - if( empty( $label )) - return FALSE; - if( 'X-' != strtoupper( substr( $label, 0, 2 ))) - return FALSE; - if( empty( $value ) && !is_numeric( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE; - $xprop = array( 'value' => $value ); - $xprop['params'] = iCalUtilityFunctions::_setParams( $params ); - if( !is_array( $this->xprop )) $this->xprop = array(); - $this->xprop[strtoupper( $label )] = $xprop; - return TRUE; - } -/*********************************************************************************/ -/** - * delete calendar property value - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.8.8 - 2011-03-15 - * @param mixed $propName, bool FALSE => X-property - * @param int $propix, optional, if specific property is wanted in case of multiply occurences - * @return bool, if successfull delete - */ - function deleteProperty( $propName=FALSE, $propix=FALSE ) { - $propName = ( $propName ) ? strtoupper( $propName ) : 'X-PROP'; - if( !$propix ) - $propix = ( isset( $this->propdelix[$propName] ) && ( 'X-PROP' != $propName )) ? $this->propdelix[$propName] + 2 : 1; - $this->propdelix[$propName] = --$propix; - $return = FALSE; - switch( $propName ) { - case 'CALSCALE': - if( isset( $this->calscale )) { - $this->calscale = null; - $return = TRUE; - } - break; - case 'METHOD': - if( isset( $this->method )) { - $this->method = null; - $return = TRUE; - } - break; - default: - $reduced = array(); - if( $propName != 'X-PROP' ) { - if( !isset( $this->xprop[$propName] )) { unset( $this->propdelix[$propName] ); return FALSE; } - foreach( $this->xprop as $k => $a ) { - if(( $k != $propName ) && !empty( $a )) - $reduced[$k] = $a; - } - } - else { - if( count( $this->xprop ) <= $propix ) return FALSE; - $xpropno = 0; - foreach( $this->xprop as $xpropkey => $xpropvalue ) { - if( $propix != $xpropno ) - $reduced[$xpropkey] = $xpropvalue; - $xpropno++; - } - } - $this->xprop = $reduced; - if( empty( $this->xprop )) { - unset( $this->propdelix[$propName] ); - return FALSE; - } - return TRUE; - } - return $return; - } -/** - * get calendar property value/params - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.13.4 - 2012-08-08 - * @param string $propName, optional - * @param int $propix, optional, if specific property is wanted in case of multiply occurences - * @param bool $inclParam=FALSE - * @return mixed - */ - function getProperty( $propName=FALSE, $propix=FALSE, $inclParam=FALSE ) { - $propName = ( $propName ) ? strtoupper( $propName ) : 'X-PROP'; - if( 'X-PROP' == $propName ) { - if( !$propix ) - $propix = ( isset( $this->propix[$propName] )) ? $this->propix[$propName] + 2 : 1; - $this->propix[$propName] = --$propix; - } - else - $mProps = array( 'ATTENDEE', 'CATEGORIES', 'CONTACT', 'RELATED-TO', 'RESOURCES' ); - switch( $propName ) { - case 'ATTENDEE': - case 'CATEGORIES': - case 'CONTACT': - case 'DTSTART': - case 'GEOLOCATION': - case 'LOCATION': - case 'ORGANIZER': - case 'PRIORITY': - case 'RESOURCES': - case 'STATUS': - case 'SUMMARY': - case 'RECURRENCE-ID-UID': - case 'RELATED-TO': - case 'R-UID': - case 'UID': - case 'URL': - $output = array(); - foreach ( $this->components as $cix => $component) { - if( !in_array( $component->objName, array('vevent', 'vtodo', 'vjournal', 'vfreebusy' ))) - continue; - if( in_array( strtoupper( $propName ), $mProps )) { - $component->_getProperties( $propName, $output ); - continue; - } - elseif(( 3 < strlen( $propName )) && ( 'UID' == substr( $propName, -3 ))) { - if( FALSE !== ( $content = $component->getProperty( 'RECURRENCE-ID' ))) - $content = $component->getProperty( 'UID' ); - } - elseif( 'GEOLOCATION' == $propName ) { - $content = $component->getProperty( 'LOCATION' ); - $content = ( !empty( $content )) ? $content.' ' : ''; - if(( FALSE === ( $geo = $component->getProperty( 'GEO' ))) || empty( $geo )) - continue; - if( 0.0 < $geo['latitude'] ) - $sign = '+'; - else - $sign = ( 0.0 > $geo['latitude'] ) ? '-' : ''; - $content .= ' '.$sign.sprintf( "%09.6f", abs( $geo['latitude'] )); - $content = rtrim( rtrim( $content, '0' ), '.' ); - if( 0.0 < $geo['longitude'] ) - $sign = '+'; - else - $sign = ( 0.0 > $geo['longitude'] ) ? '-' : ''; - $content .= $sign.sprintf( '%8.6f', abs( $geo['longitude'] )).'/'; - } - elseif( FALSE === ( $content = $component->getProperty( $propName ))) - continue; - if(( FALSE === $content ) || empty( $content )) - continue; - elseif( is_array( $content )) { - if( isset( $content['year'] )) { - $key = sprintf( '%04d%02d%02d', $content['year'], $content['month'], $content['day'] ); - if( !isset( $output[$key] )) - $output[$key] = 1; - else - $output[$key] += 1; - } - else { - foreach( $content as $partValue => $partCount ) { - if( !isset( $output[$partValue] )) - $output[$partValue] = $partCount; - else - $output[$partValue] += $partCount; - } - } - } // end elseif( is_array( $content )) { - elseif( !isset( $output[$content] )) - $output[$content] = 1; - else - $output[$content] += 1; - } // end foreach ( $this->components as $cix => $component) - if( !empty( $output )) - ksort( $output ); - return $output; - break; - case 'CALSCALE': - return ( !empty( $this->calscale )) ? $this->calscale : FALSE; - break; - case 'METHOD': - return ( !empty( $this->method )) ? $this->method : FALSE; - break; - case 'PRODID': - if( empty( $this->prodid )) - $this->_makeProdid(); - return $this->prodid; - break; - case 'VERSION': - return ( !empty( $this->version )) ? $this->version : FALSE; - break; - default: - if( $propName != 'X-PROP' ) { - if( !isset( $this->xprop[$propName] )) return FALSE; - return ( $inclParam ) ? array( $propName, $this->xprop[$propName] ) - : array( $propName, $this->xprop[$propName]['value'] ); - } - else { - if( empty( $this->xprop )) return FALSE; - $xpropno = 0; - foreach( $this->xprop as $xpropkey => $xpropvalue ) { - if( $propix == $xpropno ) - return ( $inclParam ) ? array( $xpropkey, $this->xprop[$xpropkey] ) - : array( $xpropkey, $this->xprop[$xpropkey]['value'] ); - else - $xpropno++; - } - unset( $this->propix[$propName] ); - return FALSE; // not found ?? - } - } - return FALSE; - } -/** - * general vcalendar property setting - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.2.13 - 2007-11-04 - * @param mixed $args variable number of function arguments, - * first argument is ALWAYS component name, - * second ALWAYS component value! - * @return bool - */ - function setProperty () { - $numargs = func_num_args(); - if( 1 > $numargs ) - return FALSE; - $arglist = func_get_args(); - $arglist[0] = strtoupper( $arglist[0] ); - switch( $arglist[0] ) { - case 'CALSCALE': - return $this->setCalscale( $arglist[1] ); - case 'METHOD': - return $this->setMethod( $arglist[1] ); - case 'VERSION': - return $this->setVersion( $arglist[1] ); - default: - if( !isset( $arglist[1] )) $arglist[1] = null; - if( !isset( $arglist[2] )) $arglist[2] = null; - return $this->setXprop( $arglist[0], $arglist[1], $arglist[2] ); - } - return FALSE; - } -/*********************************************************************************/ -/** - * get vcalendar config values or * calendar components - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.11.7 - 2012-01-12 - * @param mixed $config - * @return value - */ - function getConfig( $config = FALSE ) { - if( !$config ) { - $return = array(); - $return['ALLOWEMPTY'] = $this->getConfig( 'ALLOWEMPTY' ); - $return['DELIMITER'] = $this->getConfig( 'DELIMITER' ); - $return['DIRECTORY'] = $this->getConfig( 'DIRECTORY' ); - $return['FILENAME'] = $this->getConfig( 'FILENAME' ); - $return['DIRFILE'] = $this->getConfig( 'DIRFILE' ); - $return['FILESIZE'] = $this->getConfig( 'FILESIZE' ); - $return['FORMAT'] = $this->getConfig( 'FORMAT' ); - if( FALSE !== ( $lang = $this->getConfig( 'LANGUAGE' ))) - $return['LANGUAGE'] = $lang; - $return['NEWLINECHAR'] = $this->getConfig( 'NEWLINECHAR' ); - $return['UNIQUE_ID'] = $this->getConfig( 'UNIQUE_ID' ); - if( FALSE !== ( $url = $this->getConfig( 'URL' ))) - $return['URL'] = $url; - $return['TZID'] = $this->getConfig( 'TZID' ); - return $return; - } - switch( strtoupper( $config )) { - case 'ALLOWEMPTY': - return $this->allowEmpty; - break; - case 'COMPSINFO': - unset( $this->compix ); - $info = array(); - foreach( $this->components as $cix => $component ) { - if( empty( $component )) continue; - $info[$cix]['ordno'] = $cix + 1; - $info[$cix]['type'] = $component->objName; - $info[$cix]['uid'] = $component->getProperty( 'uid' ); - $info[$cix]['props'] = $component->getConfig( 'propinfo' ); - $info[$cix]['sub'] = $component->getConfig( 'compsinfo' ); - } - return $info; - break; - case 'DELIMITER': - return $this->delimiter; - break; - case 'DIRECTORY': - if( empty( $this->directory ) && ( '0' != $this->directory )) - $this->directory = '.'; - return $this->directory; - break; - case 'DIRFILE': - return $this->getConfig( 'directory' ).$this->getConfig( 'delimiter' ).$this->getConfig( 'filename' ); - break; - case 'FILEINFO': - return array( $this->getConfig( 'directory' ) - , $this->getConfig( 'filename' ) - , $this->getConfig( 'filesize' )); - break; - case 'FILENAME': - if( empty( $this->filename ) && ( '0' != $this->filename )) { - if( 'xcal' == $this->format ) - $this->filename = date( 'YmdHis' ).'.xml'; // recommended xcs.. . - else - $this->filename = date( 'YmdHis' ).'.ics'; - } - return $this->filename; - break; - case 'FILESIZE': - $size = 0; - if( empty( $this->url )) { - $dirfile = $this->getConfig( 'dirfile' ); - if( !is_file( $dirfile ) || ( FALSE === ( $size = filesize( $dirfile )))) - $size = 0; - clearstatcache(); - } - return $size; - break; - case 'FORMAT': - return ( $this->format == 'xcal' ) ? 'xCal' : 'iCal'; - break; - case 'LANGUAGE': - /* get language for calendar component as defined in [RFC 1766] */ - return $this->language; - break; - case 'NL': - case 'NEWLINECHAR': - return $this->nl; - break; - case 'TZID': - return $this->dtzid; - break; - case 'UNIQUE_ID': - return $this->unique_id; - break; - case 'URL': - if( !empty( $this->url )) - return $this->url; - else - return FALSE; - break; - } - } -/** - * general vcalendar config setting - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.16.7 - 2013-01-11 - * @param mixed $config - * @param string $value - * @return void - */ - function setConfig( $config, $value = FALSE) { - if( is_array( $config )) { - $ak = array_keys( $config ); - foreach( $ak as $k ) { - if( 'DIRECTORY' == strtoupper( $k )) { - if( FALSE === $this->setConfig( 'DIRECTORY', $config[$k] )) - return FALSE; - unset( $config[$k] ); - } - elseif( 'NEWLINECHAR' == strtoupper( $k )) { - if( FALSE === $this->setConfig( 'NEWLINECHAR', $config[$k] )) - return FALSE; - unset( $config[$k] ); - } - } - foreach( $config as $cKey => $cValue ) { - if( FALSE === $this->setConfig( $cKey, $cValue )) - return FALSE; - } - return TRUE; - } - $res = FALSE; - switch( strtoupper( $config )) { - case 'ALLOWEMPTY': - $this->allowEmpty = $value; - $subcfg = array( 'ALLOWEMPTY' => $value ); - $res = TRUE; - break; - case 'DELIMITER': - $this->delimiter = $value; - return TRUE; - break; - case 'DIRECTORY': - $value = trim( $value ); - $del = $this->getConfig('delimiter'); - if( $del == substr( $value, ( 0 - strlen( $del )))) - $value = substr( $value, 0, ( strlen( $value ) - strlen( $del ))); - if( is_dir( $value )) { - /* local directory */ - clearstatcache(); - $this->directory = $value; - $this->url = null; - return TRUE; - } - else - return FALSE; - break; - case 'FILENAME': - $value = trim( $value ); - if( !empty( $this->url )) { - /* remote directory+file -> URL */ - $this->filename = $value; - return TRUE; - } - $dirfile = $this->getConfig( 'directory' ).$this->getConfig( 'delimiter' ).$value; - if( file_exists( $dirfile )) { - /* local file exists */ - if( is_readable( $dirfile ) || is_writable( $dirfile )) { - clearstatcache(); - $this->filename = $value; - return TRUE; - } - else - return FALSE; - } - elseif( is_readable($this->getConfig( 'directory' ) ) || is_writable( $this->getConfig( 'directory' ) )) { - /* read- or writable directory */ - $this->filename = $value; - return TRUE; - } - else - return FALSE; - break; - case 'FORMAT': - $value = trim( strtolower( $value )); - if( 'xcal' == $value ) { - $this->format = 'xcal'; - $this->attributeDelimiter = $this->nl; - $this->valueInit = null; - } - else { - $this->format = null; - $this->attributeDelimiter = ';'; - $this->valueInit = ':'; - } - $subcfg = array( 'FORMAT' => $value ); - $res = TRUE; - break; - case 'LANGUAGE': // set language for calendar component as defined in [RFC 1766] - $value = trim( $value ); - $this->language = $value; - $this->_makeProdid(); - $subcfg = array( 'LANGUAGE' => $value ); - $res = TRUE; - break; - case 'NL': - case 'NEWLINECHAR': - $this->nl = $value; - if( 'xcal' == $value ) { - $this->attributeDelimiter = $this->nl; - $this->valueInit = null; - } - else { - $this->attributeDelimiter = ';'; - $this->valueInit = ':'; - } - $subcfg = array( 'NL' => $value ); - $res = TRUE; - break; - case 'TZID': - $this->dtzid = $value; - $subcfg = array( 'TZID' => $value ); - $res = TRUE; - break; - case 'UNIQUE_ID': - $value = trim( $value ); - $this->unique_id = $value; - $this->_makeProdid(); - $subcfg = array( 'UNIQUE_ID' => $value ); - $res = TRUE; - break; - case 'URL': - /* remote file - URL */ - $value = str_replace( array( 'HTTP://', 'WEBCAL://', 'webcal://' ), 'http://', trim( $value )); - if( 'http://' != substr( $value, 0, 7 )) - return FALSE; - $s1 = $this->url; - $this->url = $value; - $s2 = $this->directory; - $this->directory = null; - $parts = pathinfo( $value ); - if( FALSE === $this->setConfig( 'filename', $parts['basename'] )) { - $this->url = $s1; - $this->directory = $s2; - return FALSE; - } - else - return TRUE; - break; - default: // any unvalid config key.. . - return TRUE; - } - if( !$res ) return FALSE; - if( isset( $subcfg ) && !empty( $this->components )) { - foreach( $subcfg as $cfgkey => $cfgvalue ) { - foreach( $this->components as $cix => $component ) { - $res = $component->setConfig( $cfgkey, $cfgvalue, TRUE ); - if( !$res ) - break 2; - $this->components[$cix] = $component->copy(); // PHP4 compliant - } - } - } - return $res; - } -/*********************************************************************************/ -/** - * add calendar component to container - * - * alias to setComponent - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 1.x.x - 2007-04-24 - * @param object $component calendar component - * @return void - */ - function addComponent( $component ) { - $this->setComponent( $component ); - } -/** - * delete calendar component from container - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.8.8 - 2011-03-15 - * @param mixed $arg1 ordno / component type / component uid - * @param mixed $arg2 optional, ordno if arg1 = component type - * @return void - */ - function deleteComponent( $arg1, $arg2=FALSE ) { - $argType = $index = null; - if ( ctype_digit( (string) $arg1 )) { - $argType = 'INDEX'; - $index = (int) $arg1 - 1; - } - elseif(( strlen( $arg1 ) <= strlen( 'vfreebusy' )) && ( FALSE === strpos( $arg1, '@' ))) { - $argType = strtolower( $arg1 ); - $index = ( !empty( $arg2 ) && ctype_digit( (string) $arg2 )) ? (( int ) $arg2 - 1 ) : 0; - } - $cix1dC = 0; - foreach ( $this->components as $cix => $component) { - if( empty( $component )) continue; - if(( 'INDEX' == $argType ) && ( $index == $cix )) { - unset( $this->components[$cix] ); - return TRUE; - } - elseif( $argType == $component->objName ) { - if( $index == $cix1dC ) { - unset( $this->components[$cix] ); - return TRUE; - } - $cix1dC++; - } - elseif( !$argType && ($arg1 == $component->getProperty( 'uid' ))) { - unset( $this->components[$cix] ); - return TRUE; - } - } - return FALSE; - } -/** - * get calendar component from container - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.13.5 - 2012-08-08 - * @param mixed $arg1 optional, ordno/component type/ component uid - * @param mixed $arg2 optional, ordno if arg1 = component type - * @return object - */ - function getComponent( $arg1=FALSE, $arg2=FALSE ) { - $index = $argType = null; - if ( !$arg1 ) { // first or next in component chain - $argType = 'INDEX'; - $index = $this->compix['INDEX'] = ( isset( $this->compix['INDEX'] )) ? $this->compix['INDEX'] + 1 : 1; - } - elseif ( ctype_digit( (string) $arg1 )) { // specific component in chain - $argType = 'INDEX'; - $index = (int) $arg1; - unset( $this->compix ); - } - elseif( is_array( $arg1 )) { // array( *[propertyName => propertyValue] ) - $arg2 = implode( '-', array_keys( $arg1 )); - $index = $this->compix[$arg2] = ( isset( $this->compix[$arg2] )) ? $this->compix[$arg2] + 1 : 1; - $dateProps = array( 'DTSTART', 'DTEND', 'DUE', 'CREATED', 'COMPLETED', 'DTSTAMP', 'LAST-MODIFIED', 'RECURRENCE-ID' ); - $otherProps = array( 'ATTENDEE', 'CATEGORIES', 'CONTACT', 'LOCATION', 'ORGANIZER', 'PRIORITY', 'RELATED-TO', 'RESOURCES', 'STATUS', 'SUMMARY', 'UID', 'URL' ); - $mProps = array( 'ATTENDEE', 'CATEGORIES', 'CONTACT', 'RELATED-TO', 'RESOURCES' ); - } - elseif(( strlen( $arg1 ) <= strlen( 'vfreebusy' )) && ( FALSE === strpos( $arg1, '@' ))) { // object class name - unset( $this->compix['INDEX'] ); - $argType = strtolower( $arg1 ); - if( !$arg2 ) - $index = $this->compix[$argType] = ( isset( $this->compix[$argType] )) ? $this->compix[$argType] + 1 : 1; - elseif( isset( $arg2 ) && ctype_digit( (string) $arg2 )) - $index = (int) $arg2; - } - elseif(( strlen( $arg1 ) > strlen( 'vfreebusy' )) && ( FALSE !== strpos( $arg1, '@' ))) { // UID as 1st argument - if( !$arg2 ) - $index = $this->compix[$arg1] = ( isset( $this->compix[$arg1] )) ? $this->compix[$arg1] + 1 : 1; - elseif( isset( $arg2 ) && ctype_digit( (string) $arg2 )) - $index = (int) $arg2; - } - if( isset( $index )) - $index -= 1; - $ckeys = array_keys( $this->components ); - if( !empty( $index) && ( $index > end( $ckeys ))) - return FALSE; - $cix1gC = 0; - foreach ( $this->components as $cix => $component) { - if( empty( $component )) continue; - if(( 'INDEX' == $argType ) && ( $index == $cix )) - return $component->copy(); - elseif( $argType == $component->objName ) { - if( $index == $cix1gC ) - return $component->copy(); - $cix1gC++; - } - elseif( is_array( $arg1 )) { // array( *[propertyName => propertyValue] ) - $hit = array(); - foreach( $arg1 as $pName => $pValue ) { - $pName = strtoupper( $pName ); - if( !in_array( $pName, $dateProps ) && !in_array( $pName, $otherProps )) - continue; - if( in_array( $pName, $mProps )) { // multiple occurrence - $propValues = array(); - $component->_getProperties( $pName, $propValues ); - $propValues = array_keys( $propValues ); - $hit[] = ( in_array( $pValue, $propValues )) ? TRUE : FALSE; - continue; - } // end if(.. .// multiple occurrence - if( FALSE === ( $value = $component->getProperty( $pName ))) { // single occurrence - $hit[] = FALSE; // missing property - continue; - } - if( 'SUMMARY' == $pName ) { // exists within (any case) - $hit[] = ( FALSE !== stripos( $value, $pValue )) ? TRUE : FALSE; - continue; - } - if( in_array( strtoupper( $pName ), $dateProps )) { - $valuedate = sprintf( '%04d%02d%02d', $value['year'], $value['month'], $value['day'] ); - if( 8 < strlen( $pValue )) { - if( isset( $value['hour'] )) { - if( 'T' == substr( $pValue, 8, 1 )) - $pValue = str_replace( 'T', '', $pValue ); - $valuedate .= sprintf( '%02d%02d%02d', $value['hour'], $value['min'], $value['sec'] ); - } - else - $pValue = substr( $pValue, 0, 8 ); - } - $hit[] = ( $pValue == $valuedate ) ? TRUE : FALSE; - continue; - } - elseif( !is_array( $value )) - $value = array( $value ); - foreach( $value as $part ) { - $part = ( FALSE !== strpos( $part, ',' )) ? explode( ',', $part ) : array( $part ); - foreach( $part as $subPart ) { - if( $pValue == $subPart ) { - $hit[] = TRUE; - continue 3; - } - } - } // end foreach( $value as $part ) - $hit[] = FALSE; // no hit in property - } // end foreach( $arg1 as $pName => $pValue ) - if( in_array( TRUE, $hit )) { - if( $index == $cix1gC ) - return $component->copy(); - $cix1gC++; - } - } // end elseif( is_array( $arg1 )) { // array( *[propertyName => propertyValue] ) - elseif( !$argType && ($arg1 == $component->getProperty( 'uid' ))) { // UID - if( $index == $cix1gC ) - return $component->copy(); - $cix1gC++; - } - } // end foreach ( $this->components.. . - /* not found.. . */ - unset( $this->compix ); - return FALSE; - } -/** - * create new calendar component, already included within calendar - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.6.33 - 2011-01-03 - * @param string $compType component type - * @return object (reference) - */ - function & newComponent( $compType ) { - $config = $this->getConfig(); - $keys = array_keys( $this->components ); - $ix = end( $keys) + 1; - switch( strtoupper( $compType )) { - case 'EVENT': - case 'VEVENT': - $this->components[$ix] = new vevent( $config ); - break; - case 'TODO': - case 'VTODO': - $this->components[$ix] = new vtodo( $config ); - break; - case 'JOURNAL': - case 'VJOURNAL': - $this->components[$ix] = new vjournal( $config ); - break; - case 'FREEBUSY': - case 'VFREEBUSY': - $this->components[$ix] = new vfreebusy( $config ); - break; - case 'TIMEZONE': - case 'VTIMEZONE': - array_unshift( $this->components, new vtimezone( $config )); - $ix = 0; - break; - default: - return FALSE; - } - return $this->components[$ix]; - } -/** - * select components from calendar on date or selectOption basis - * - * Ensure DTSTART is set for every component. - * No date controls occurs. - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.16.12 - 2013-02-10 - * @param mixed $startY optional, start Year, default current Year ALT. array selecOptions ( *[ => ] ) - * @param int $startM optional, start Month, default current Month - * @param int $startD optional, start Day, default current Day - * @param int $endY optional, end Year, default $startY - * @param int $endY optional, end Month, default $startM - * @param int $endY optional, end Day, default $startD - * @param mixed $cType optional, calendar component type(-s), default FALSE=all else string/array type(-s) - * @param bool $flat optional, FALSE (default) => output : array[Year][Month][Day][] - * TRUE => output : array[] (ignores split) - * @param bool $any optional, TRUE (default) - select component(-s) that occurs within period - * FALSE - only component(-s) that starts within period - * @param bool $split optional, TRUE (default) - one component copy every DAY it occurs during the - * period (implies flat=FALSE) - * FALSE - one occurance of component only in output array - * @return array or FALSE - */ - function selectComponents( $startY=FALSE, $startM=FALSE, $startD=FALSE, $endY=FALSE, $endM=FALSE, $endD=FALSE, $cType=FALSE, $flat=FALSE, $any=TRUE, $split=TRUE ) { - /* check if empty calendar */ - if( 0 >= count( $this->components )) return FALSE; - if( is_array( $startY )) - return $this->selectComponents2( $startY ); - /* check default dates */ - if( !$startY ) $startY = date( 'Y' ); - if( !$startM ) $startM = date( 'm' ); - if( !$startD ) $startD = date( 'd' ); - $startDate = mktime( 0, 0, 0, $startM, $startD, $startY ); - if( !$endY ) $endY = $startY; - if( !$endM ) $endM = $startM; - if( !$endD ) $endD = $startD; - $endDate = mktime( 23, 59, 59, $endM, $endD, $endY ); -// echo 'selectComp arg='.date( 'Y-m-d H:i:s', $startDate).' -- '.date( 'Y-m-d H:i:s', $endDate)."
\n"; $tcnt = 0;// test ### - /* check component types */ - $validTypes = array('vevent', 'vtodo', 'vjournal', 'vfreebusy' ); - if( is_array( $cType )) { - foreach( $cType as $cix => $theType ) { - $cType[$cix] = $theType = strtolower( $theType ); - if( !in_array( $theType, $validTypes )) - $cType[$cix] = 'vevent'; - } - $cType = array_unique( $cType ); - } - elseif( !empty( $cType )) { - $cType = strtolower( $cType ); - if( !in_array( $cType, $validTypes )) - $cType = array( 'vevent' ); - else - $cType = array( $cType ); - } - else - $cType = $validTypes; - if( 0 >= count( $cType )) - $cType = $validTypes; - if(( FALSE === $flat ) && ( FALSE === $any )) // invalid combination - $split = FALSE; - if(( TRUE === $flat ) && ( TRUE === $split )) // invalid combination - $split = FALSE; - /* iterate components */ - $result = array(); - $this->sort( 'UID' ); - $compUIDcmp = null; - $recurridList = array(); - foreach ( $this->components as $cix => $component ) { - if( empty( $component )) continue; - unset( $start ); - /* deselect unvalid type components */ - if( !in_array( $component->objName, $cType )) - continue; - $start = $component->getProperty( 'dtstart' ); - /* select due when dtstart is missing */ - if( empty( $start ) && ( $component->objName == 'vtodo' ) && ( FALSE === ( $start = $component->getProperty( 'due' )))) - continue; - if( empty( $start )) - continue; - $compUID = $component->getProperty( 'UID' ); - if( $compUIDcmp != $compUID ) { - $compUIDcmp = $compUID; - unset( $exdatelist, $recurridList ); - } - $dtendExist = $dueExist = $durationExist = $endAllDayEvent = $recurrid = FALSE; - unset( $end, $startWdate, $endWdate, $rdurWsecs, $rdur, $workstart, $workend, $endDateFormat ); // clean up - $startWdate = iCalUtilityFunctions::_date2timestamp( $start ); - $startDateFormat = ( isset( $start['hour'] )) ? 'Y-m-d H:i:s' : 'Y-m-d'; - /* get end date from dtend/due/duration properties */ - $end = $component->getProperty( 'dtend' ); - if( !empty( $end )) { - $dtendExist = TRUE; - $endDateFormat = ( isset( $end['hour'] )) ? 'Y-m-d H:i:s' : 'Y-m-d'; - } - if( empty( $end ) && ( $component->objName == 'vtodo' )) { - $end = $component->getProperty( 'due' ); - if( !empty( $end )) { - $dueExist = TRUE; - $endDateFormat = ( isset( $end['hour'] )) ? 'Y-m-d H:i:s' : 'Y-m-d'; - } - } - if( !empty( $end ) && !isset( $end['hour'] )) { - /* a DTEND without time part regards an event that ends the day before, - for an all-day event DTSTART=20071201 DTEND=20071202 (taking place 20071201!!! */ - $endAllDayEvent = TRUE; - $endWdate = mktime( 23, 59, 59, $end['month'], ($end['day'] - 1), $end['year'] ); - $end['year'] = date( 'Y', $endWdate ); - $end['month'] = date( 'm', $endWdate ); - $end['day'] = date( 'd', $endWdate ); - $end['hour'] = 23; - $end['min'] = $end['sec'] = 59; - } - if( empty( $end )) { - $end = $component->getProperty( 'duration', FALSE, FALSE, TRUE );// in dtend (array) format - if( !empty( $end )) - $durationExist = TRUE; - $endDateFormat = ( isset( $start['hour'] )) ? 'Y-m-d H:i:s' : 'Y-m-d'; -// if( !empty($end)) echo 'selectComp 4 start='.implode('-',$start).' end='.implode('-',$end)."
\n"; // test ### - } - if( empty( $end )) { // assume one day duration if missing end date - $end = array( 'year' => $start['year'], 'month' => $start['month'], 'day' => $start['day'], 'hour' => 23, 'min' => 59, 'sec' => 59 ); - } -// if( isset($end)) echo 'selectComp 5 start='.implode('-',$start).' end='.implode('-',$end)."
\n"; // test ### - $endWdate = iCalUtilityFunctions::_date2timestamp( $end ); - if( $endWdate < $startWdate ) { // MUST be after start date!! - $end = array( 'year' => $start['year'], 'month' => $start['month'], 'day' => $start['day'], 'hour' => 23, 'min' => 59, 'sec' => 59 ); - $endWdate = iCalUtilityFunctions::_date2timestamp( $end ); - } - $rdurWsecs = $endWdate - $startWdate; // compute event (component) duration in seconds - /* make a list of optional exclude dates for component occurence from exrule and exdate */ - $exdatelist = array(); - $workstart = iCalUtilityFunctions::_timestamp2date(( $startDate - $rdurWsecs ), 6); - $workend = iCalUtilityFunctions::_timestamp2date(( $endDate + $rdurWsecs ), 6); - while( FALSE !== ( $exrule = $component->getProperty( 'exrule' ))) // check exrule - iCalUtilityFunctions::_recur2date( $exdatelist, $exrule, $start, $workstart, $workend ); - while( FALSE !== ( $exdate = $component->getProperty( 'exdate' ))) { // check exdate - foreach( $exdate as $theExdate ) { - $exWdate = iCalUtilityFunctions::_date2timestamp( $theExdate ); - $exWdate = mktime( 0, 0, 0, date( 'm', $exWdate ), date( 'd', $exWdate ), date( 'Y', $exWdate )); // on a day-basis !!! - if((( $startDate - $rdurWsecs ) <= $exWdate ) && ( $endDate >= $exWdate )) - $exdatelist[$exWdate] = TRUE; - } // end - foreach( $exdate as $theExdate ) - } // end - check exdate - /* check recurrence-id (note, a missing sequence=0, don't test foer sequence), remove hit with reccurr-id date */ - if( FALSE !== ( $recurrid = $component->getProperty( 'recurrence-id' ))) { -// echo "adding ".$recurrid['year'].'-'.$recurrid['month'].'-'.$recurrid['day']." to recurridList
\n"; // test ### - $recurrid = iCalUtilityFunctions::_date2timestamp( $recurrid ); - $recurrid = mktime( 0, 0, 0, date( 'm', $recurrid ), date( 'd', $recurrid ), date( 'Y', $recurrid )); // on a day-basis !!! - $recurridList[$recurrid] = TRUE; // no recurring to start this day - } // end recurrence-id/sequence test - /* select only components with.. . */ - if(( !$any && ( $startWdate >= $startDate ) && ( $startWdate <= $endDate )) || // (dt)start within the period - ( $any && ( $startWdate < $endDate ) && ( $endWdate >= $startDate ))) { // occurs within the period - /* add the selected component (WITHIN valid dates) to output array */ - if( $flat ) { // any=true/false, ignores split - if( !$recurrid ) - $result[$compUID] = $component->copy(); // copy original to output (but not anyone with recurrence-id) - } - elseif( $split ) { // split the original component - if( $endWdate > $endDate ) - $endWdate = $endDate; // use period end date - $rstart = $startWdate; - if( $rstart < $startDate ) - $rstart = $startDate; // use period start date - $startYMD = $rstartYMD = date( 'Ymd', $rstart ); - $endYMD = date( 'Ymd', $endWdate ); - $checkDate = mktime( 0, 0, 0, date( 'm', $rstart ), date( 'd', $rstart ), date( 'Y', $rstart ) ); // on a day-basis !!! -// echo "start org comp = $rstartYMD, endYMD=$endYMD
\n"; // test ### - if( !isset( $exdatelist[$checkDate] )) { // exclude any recurrence START date, found in exdatelist - while( $rstartYMD <= $endYMD ) { // iterate - if( isset( $exdatelist[$checkDate] )) { // exclude any recurrence date, found in exdatelist - $rstart = mktime( date( 'H', $rstart ), date( 'i', $rstart ), date( 's', $rstart ), date( 'm', $rstart ), date( 'd', $rstart ) + 1, date( 'Y', $rstart ) ); // step one day - $rstartYMD = date( 'Ymd', $rstart ); - continue; - } - if( $rstartYMD > $startYMD ) // date after dtstart - $datestring = date( $startDateFormat, $checkDate ); // mktime( 0, 0, 0, date( 'm', $rstart ), date( 'd', $rstart ), date( 'Y', $rstart ))); - else - $datestring = date( $startDateFormat, $rstart ); - if( isset( $start['tz'] )) - $datestring .= ' '.$start['tz']; -// echo "split org comp rstartYMD=$rstartYMD (datestring=$datestring)
\n"; // test ### - $component->setProperty( 'X-CURRENT-DTSTART', $datestring ); - if( $dtendExist || $dueExist || $durationExist ) { - if( $rstartYMD < $endYMD ) // not the last day - $tend = mktime( 23, 59, 59, date( 'm', $rstart ), date( 'd', $rstart ), date( 'Y', $rstart )); - else - $tend = mktime( date( 'H', $endWdate ), date( 'i', $endWdate ), date( 's', $endWdate ), date( 'm', $rstart ), date( 'd', $rstart ), date( 'Y', $rstart ) ); // on a day-basis !!! - if( $endAllDayEvent && $dtendExist ) - $tend += ( 24 * 3600 ); // alldaysevents has an end date 'day after' meaning this day - $datestring = date( $endDateFormat, $tend ); - if( isset( $end['tz'] )) - $datestring .= ' '.$end['tz']; - $propName = ( !$dueExist ) ? 'X-CURRENT-DTEND' : 'X-CURRENT-DUE'; - $component->setProperty( $propName, $datestring ); - } // end if( $dtendExist || $dueExist || $durationExist ) - $wd = getdate( $rstart ); - $result[$wd['year']][$wd['mon']][$wd['mday']][$compUID] = $component->copy(); // copy to output - $rstart = mktime( date( 'H', $rstart ), date( 'i', $rstart ), date( 's', $rstart ), date( 'm', $rstart ), date( 'd', $rstart ) + 1, date( 'Y', $rstart ) ); // step one day - $rstartYMD = date( 'Ymd', $rstart ); - $checkDate = mktime( 0, 0, 0, date( 'm', $rstart ), date( 'd', $rstart ), date( 'Y', $rstart ) ); // on a day-basis !!! - } // end while( $rstart <= $endWdate ) - } - } // end elseif( $split ) - else use component date - elseif( $recurrid && !$flat && !$any && !$split ) - $continue = TRUE; - else { // !$flat && !$split, i.e. no flat array and DTSTART within period - $checkDate = mktime( 0, 0, 0, date( 'm', $startWdate ), date( 'd', $startWdate ), date( 'Y', $startWdate ) ); // on a day-basis !!! - if( !$any || !isset( $exdatelist[$checkDate] )) { // exclude any recurrence date, found in exdatelist - $wd = getdate( $startWdate ); - $result[$wd['year']][$wd['mon']][$wd['mday']][$compUID] = $component->copy(); // copy to output - } - } - } // end if(( $startWdate >= $startDate ) && ( $startWdate <= $endDate )) - /* if 'any' components, check components with reccurrence rules, removing all excluding dates */ - if( TRUE === $any ) { - /* make a list of optional repeating dates for component occurence, rrule, rdate */ - $recurlist = array(); - while( FALSE !== ( $rrule = $component->getProperty( 'rrule' ))) // check rrule - iCalUtilityFunctions::_recur2date( $recurlist, $rrule, $start, $workstart, $workend ); - foreach( $recurlist as $recurkey => $recurvalue ) // key=match date as timestamp - $recurlist[$recurkey] = $rdurWsecs; // add duration in seconds - while( FALSE !== ( $rdate = $component->getProperty( 'rdate' ))) { // check rdate - foreach( $rdate as $theRdate ) { - if( is_array( $theRdate ) && ( 2 == count( $theRdate )) && // all days within PERIOD - array_key_exists( '0', $theRdate ) && array_key_exists( '1', $theRdate )) { - $rstart = iCalUtilityFunctions::_date2timestamp( $theRdate[0] ); - if(( $rstart < ( $startDate - $rdurWsecs )) || ( $rstart > $endDate )) - continue; - if( isset( $theRdate[1]['year'] )) // date-date period - $rend = iCalUtilityFunctions::_date2timestamp( $theRdate[1] ); - else { // date-duration period - $rend = iCalUtilityFunctions::_duration2date( $theRdate[0], $theRdate[1] ); - $rend = iCalUtilityFunctions::_date2timestamp( $rend ); - } - while( $rstart < $rend ) { - $recurlist[$rstart] = $rdurWsecs; // set start date for recurrence instance + rdate duration in seconds - $rstart = mktime( date( 'H', $rstart ), date( 'i', $rstart ), date( 's', $rstart ), date( 'm', $rstart ), date( 'd', $rstart ) + 1, date( 'Y', $rstart ) ); // step one day - } - } // PERIOD end - else { // single date - $theRdate = iCalUtilityFunctions::_date2timestamp( $theRdate ); - if((( $startDate - $rdurWsecs ) <= $theRdate ) && ( $endDate >= $theRdate )) - $recurlist[$theRdate] = $rdurWsecs; // set start date for recurrence instance + event duration in seconds - } - } - } // end - check rdate - foreach( $recurlist as $recurkey => $durvalue ) { // remove all recurrence START dates found in the exdatelist - $checkDate = mktime( 0, 0, 0, date( 'm', $recurkey ), date( 'd', $recurkey ), date( 'Y', $recurkey ) ); // on a day-basis !!! - if( isset( $exdatelist[$checkDate] )) // no recurring to start this day - unset( $recurlist[$recurkey] ); - } - if( 0 < count( $recurlist )) { - ksort( $recurlist ); - $xRecurrence = 1; - $component2 = $component->copy(); - $compUID = $component2->getProperty( 'UID' ); - foreach( $recurlist as $recurkey => $durvalue ) { -// echo "recurKey=".date( 'Y-m-d H:i:s', $recurkey ).' dur='.iCalUtilityFunctions::offsetSec2His( $durvalue )."
\n"; // test ###; - if((( $startDate - $rdurWsecs ) > $recurkey ) || ( $endDate < $recurkey )) // not within period - continue; - $checkDate = mktime( 0, 0, 0, date( 'm', $recurkey ), date( 'd', $recurkey ), date( 'Y', $recurkey ) ); // on a day-basis !!! - if( isset( $recurridList[$checkDate] )) // no recurring to start this day - continue; - if( isset( $exdatelist[$checkDate] )) // check excluded dates - continue; - if( $startWdate >= $recurkey ) // exclude component start date - continue; - $rstart = $recurkey; - $rend = $recurkey + $durvalue; - /* add repeating components within valid dates to output array, only start date set */ - if( $flat ) { - if( !isset( $result[$compUID] )) // only one comp - $result[$compUID] = $component2->copy(); // copy to output - } - /* add repeating components within valid dates to output array, one each day */ - elseif( $split ) { - $xRecurrence += 1; - if( $rend > $endDate ) - $rend = $endDate; - $startYMD = $rstartYMD = date( 'Ymd', $rstart ); - $endYMD = date( 'Ymd', $rend ); -// echo "splitStart=".date( 'Y-m-d H:i:s', $rstart ).' end='.date( 'Y-m-d H:i:s', $rend )."
\n"; // test ###; - while( $rstart <= $rend ) { // iterate.. . - $checkDate = mktime( 0, 0, 0, date( 'm', $rstart ), date( 'd', $rstart ), date( 'Y', $rstart ) ); // on a day-basis !!! - if( isset( $recurridList[$checkDate] )) // no recurring to start this day - break; - if( isset( $exdatelist[$checkDate] )) // exclude any recurrence START date, found in exdatelist - break; -// echo "checking date after startdate=".date( 'Y-m-d H:i:s', $rstart ).' mot '.date( 'Y-m-d H:i:s', $startDate )."
"; // test ###; - if( $rstart >= $startDate ) { // date after dtstart - if( $rstartYMD > $startYMD ) // date after dtstart - $datestring = date( $startDateFormat, $checkDate ); - else - $datestring = date( $startDateFormat, $rstart ); - if( isset( $start['tz'] )) - $datestring .= ' '.$start['tz']; -// echo "spliting = $datestring
\n"; // test ### - $component2->setProperty( 'X-CURRENT-DTSTART', $datestring ); - if( $dtendExist || $dueExist || $durationExist ) { - if( $rstartYMD < $endYMD ) // not the last day - $tend = mktime( 23, 59, 59, date( 'm', $rstart ), date( 'd', $rstart ), date( 'Y', $rstart )); - else - $tend = mktime( date( 'H', $endWdate ), date( 'i', $endWdate ), date( 's', $endWdate ), date( 'm', $rstart ), date( 'd', $rstart ), date( 'Y', $rstart ) ); // on a day-basis !!! - if( $endAllDayEvent && $dtendExist ) - $tend += ( 24 * 3600 ); // alldaysevents has an end date 'day after' meaning this day - $datestring = date( $endDateFormat, $tend ); - if( isset( $end['tz'] )) - $datestring .= ' '.$end['tz']; - $propName = ( !$dueExist ) ? 'X-CURRENT-DTEND' : 'X-CURRENT-DUE'; - $component2->setProperty( $propName, $datestring ); - } // end if( $dtendExist || $dueExist || $durationExist ) - $component2->setProperty( 'X-RECURRENCE', $xRecurrence ); - $wd = getdate( $rstart ); - $result[$wd['year']][$wd['mon']][$wd['mday']][$compUID] = $component2->copy(); // copy to output - } // end if( $checkDate > $startYMD ) { // date after dtstart - $rstart = mktime( date( 'H', $rstart ), date( 'i', $rstart ), date( 's', $rstart ), date( 'm', $rstart ), date( 'd', $rstart ) + 1, date( 'Y', $rstart ) ); // step one day - $rstartYMD = date( 'Ymd', $rstart ); - } // end while( $rstart <= $rend ) - } // end elseif( $split ) - elseif( $rstart >= $startDate ) { // date within period //* flat=FALSE && split=FALSE => one comp every recur startdate *// - $xRecurrence += 1; - $checkDate = mktime( 0, 0, 0, date( 'm', $rstart ), date( 'd', $rstart ), date( 'Y', $rstart ) ); // on a day-basis !!! - if( !isset( $exdatelist[$checkDate] )) { // exclude any recurrence START date, found in exdatelist - $datestring = date( $startDateFormat, $rstart ); - if( isset( $start['tz'] )) - $datestring .= ' '.$start['tz']; -//echo "X-CURRENT-DTSTART 2 = $datestring xRecurrence=$xRecurrence tcnt =".++$tcnt."
";$component2->setProperty( 'X-CNT', $tcnt ); // test ### - $component2->setProperty( 'X-CURRENT-DTSTART', $datestring ); - if( $dtendExist || $dueExist || $durationExist ) { - $tend = $rstart + $rdurWsecs; - if( date( 'Ymd', $tend ) < date( 'Ymd', $endWdate )) - $tend = mktime( 23, 59, 59, date( 'm', $tend ), date( 'd', $tend ), date( 'Y', $tend )); - else - $tend = mktime( date( 'H', $endWdate ), date( 'i', $endWdate ), date( 's', $endWdate ), date( 'm', $tend ), date( 'd', $tend ), date( 'Y', $tend ) ); // on a day-basis !!! - if( $endAllDayEvent && $dtendExist ) - $tend += ( 24 * 3600 ); // alldaysevents has an end date 'day after' meaning this day - $datestring = date( $endDateFormat, $tend ); - if( isset( $end['tz'] )) - $datestring .= ' '.$end['tz']; - $propName = ( !$dueExist ) ? 'X-CURRENT-DTEND' : 'X-CURRENT-DUE'; - $component2->setProperty( $propName, $datestring ); - } // end if( $dtendExist || $dueExist || $durationExist ) - $component2->setProperty( 'X-RECURRENCE', $xRecurrence ); - $wd = getdate( $rstart ); - $result[$wd['year']][$wd['mon']][$wd['mday']][$compUID] = $component2->copy(); // copy to output - } // end if( !isset( $exdatelist[$checkDate] )) - } // end elseif( $rstart >= $startDate ) - } // end foreach( $recurlist as $recurkey => $durvalue ) - unset( $component2 ); - } // end if( 0 < count( $recurlist )) - /* deselect components with startdate/enddate not within period */ - if(( $endWdate < $startDate ) || ( $startWdate > $endDate )) - continue; - } // end if( TRUE === $any ) - } // end foreach ( $this->components as $cix => $component ) - unset( $dtendExist, $dueExist, $durationExist, $endAllDayEvent, $recurrid, $recurridList, - $end, $startWdate, $endWdate, $rdurWsecs, $rdur, $exdatelist, $recurlist, $workstart, $workend, $endDateFormat ); // clean up - if( 0 >= count( $result )) return FALSE; - elseif( !$flat ) { - foreach( $result as $y => $yeararr ) { - foreach( $yeararr as $m => $montharr ) { - foreach( $montharr as $d => $dayarr ) { - if( empty( $result[$y][$m][$d] )) - unset( $result[$y][$m][$d] ); - else - $result[$y][$m][$d] = array_values( $dayarr ); // skip tricky UID-index, hoping they are in hour order.. . - } - if( empty( $result[$y][$m] )) - unset( $result[$y][$m] ); - else - ksort( $result[$y][$m] ); - } - if( empty( $result[$y] )) - unset( $result[$y] ); - else - ksort( $result[$y] ); - } - if( empty( $result )) - unset( $result ); - else - ksort( $result ); - } // end elseif( !$flat ) - if( 0 >= count( $result )) - return FALSE; - return $result; - } -/** - * select components from calendar on based on specific property value(-s) - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.16.6 - 2012-12-26 - * @param array $selectOptions, (string) key => (mixed) value, (key=propertyName) - * @return array - */ - function selectComponents2( $selectOptions ) { - $output = array(); - $allowedComps = array('vevent', 'vtodo', 'vjournal', 'vfreebusy' ); - $allowedProperties = array( 'ATTENDEE', 'CATEGORIES', 'CONTACT', 'LOCATION', 'ORGANIZER', 'PRIORITY', 'RELATED-TO', 'RESOURCES', 'STATUS', 'SUMMARY', 'UID', 'URL' ); - foreach( $this->components as $cix => $component3 ) { - if( !in_array( $component3->objName, $allowedComps )) - continue; - $uid = $component3->getProperty( 'UID' ); - foreach( $selectOptions as $propName => $pvalue ) { - $propName = strtoupper( $propName ); - if( !in_array( $propName, $allowedProperties )) - continue; - if( !is_array( $pvalue )) - $pvalue = array( $pvalue ); - if(( 'UID' == $propName ) && in_array( $uid, $pvalue )) { - $output[$uid][] = $component3->copy(); - continue; - } - elseif(( 'ATTENDEE' == $propName ) || ( 'CATEGORIES' == $propName ) || ( 'CONTACT' == $propName ) || ( 'RELATED-TO' == $propName ) || ( 'RESOURCES' == $propName )) { // multiple occurrence? - $propValues = array(); - $component3->_getProperties( $propName, $propValues ); - $propValues = array_keys( $propValues ); - foreach( $pvalue as $theValue ) { - if( in_array( $theValue, $propValues )) { // && !isset( $output[$uid] )) { - $output[$uid][] = $component3->copy(); - break; - } - } - continue; - } // end elseif( // multiple occurrence? - elseif( FALSE === ( $d = $component3->getProperty( $propName ))) // single occurrence - continue; - if( is_array( $d )) { - foreach( $d as $part ) { - if( in_array( $part, $pvalue ) && !isset( $output[$uid] )) - $output[$uid][] = $component3->copy(); - } - } - elseif(( 'SUMMARY' == $propName ) && !isset( $output[$uid] )) { - foreach( $pvalue as $pval ) { - if( FALSE !== stripos( $d, $pval )) { - $output[$uid][] = $component3->copy(); - break; - } - } - } - elseif( in_array( $d, $pvalue ) && !isset( $output[$uid] )) - $output[$uid][] = $component3->copy(); - } // end foreach( $selectOptions as $propName => $pvalue ) { - } // end foreach( $this->components as $cix => $component3 ) { - if( !empty( $output )) { - ksort( $output ); // uid order - $output2 = array(); - foreach( $output as $uid => $components ) { - foreach( $components as $component ) - $output2[] = $component; - } - $output = $output2; - } - return $output; - } -/** - * add calendar component to container - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.8.8 - 2011-03-15 - * @param object $component calendar component - * @param mixed $arg1 optional, ordno/component type/ component uid - * @param mixed $arg2 optional, ordno if arg1 = component type - * @return void - */ - function setComponent( $component, $arg1=FALSE, $arg2=FALSE ) { - $component->setConfig( $this->getConfig(), FALSE, TRUE ); - if( !in_array( $component->objName, array( 'valarm', 'vtimezone' ))) { - /* make sure dtstamp and uid is set */ - $dummy1 = $component->getProperty( 'dtstamp' ); - $dummy2 = $component->getProperty( 'uid' ); - } - if( !$arg1 ) { // plain insert, last in chain - $this->components[] = $component->copy(); - return TRUE; - } - $argType = $index = null; - if ( ctype_digit( (string) $arg1 )) { // index insert/replace - $argType = 'INDEX'; - $index = (int) $arg1 - 1; - } - elseif( in_array( strtolower( $arg1 ), array( 'vevent', 'vtodo', 'vjournal', 'vfreebusy', 'valarm', 'vtimezone' ))) { - $argType = strtolower( $arg1 ); - $index = ( ctype_digit( (string) $arg2 )) ? ((int) $arg2) - 1 : 0; - } - // else if arg1 is set, arg1 must be an UID - $cix1sC = 0; - foreach ( $this->components as $cix => $component2) { - if( empty( $component2 )) continue; - if(( 'INDEX' == $argType ) && ( $index == $cix )) { // index insert/replace - $this->components[$cix] = $component->copy(); - return TRUE; - } - elseif( $argType == $component2->objName ) { // component Type index insert/replace - if( $index == $cix1sC ) { - $this->components[$cix] = $component->copy(); - return TRUE; - } - $cix1sC++; - } - elseif( !$argType && ( $arg1 == $component2->getProperty( 'uid' ))) { // UID insert/replace - $this->components[$cix] = $component->copy(); - return TRUE; - } - } - /* arg1=index and not found.. . insert at index .. .*/ - if( 'INDEX' == $argType ) { - $this->components[$index] = $component->copy(); - ksort( $this->components, SORT_NUMERIC ); - } - else /* not found.. . insert last in chain anyway .. .*/ - $this->components[] = $component->copy(); - return TRUE; - } -/** - * sort iCal compoments - * - * ascending sort on properties (if exist) x-current-dtstart, dtstart, - * x-current-dtend, dtend, x-current-due, due, duration, created, dtstamp, uid if called without arguments, - * otherwise sorting on specific (argument) property values - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.16.4 - 2012-12-17 - * @param string $sortArg, optional - * @return void - * - */ - function sort( $sortArg=FALSE ) { - if( is_array( $this->components )) { - if( $sortArg ) { - $sortArg = strtoupper( $sortArg ); - if( !in_array( $sortArg, array( 'ATTENDEE', 'CATEGORIES', 'CONTACT', 'DTSTAMP', 'LOCATION', 'ORGANIZER', 'PRIORITY', 'RELATED-TO', 'RESOURCES', 'STATUS', 'SUMMARY', 'UID', 'URL' ))) - $sortArg = FALSE; - } - /* set sort parameters for each component */ - foreach( $this->components as $cix => & $c ) { - $c->srtk = array( '0', '0', '0', '0' ); - if( 'vtimezone' == $c->objName ) { - if( FALSE === ( $c->srtk[0] = $c->getProperty( 'tzid' ))) - $c->srtk[0] = 0; - continue; - } - elseif( $sortArg ) { - if(( 'ATTENDEE' == $sortArg ) || ( 'CATEGORIES' == $sortArg ) || ( 'CONTACT' == $sortArg ) || ( 'RELATED-TO' == $sortArg ) || ( 'RESOURCES' == $sortArg )) { - $propValues = array(); - $c->_getProperties( $sortArg, $propValues ); - if( !empty( $propValues )) { - $sk = array_keys( $propValues ); - $c->srtk[0] = $sk[0]; - if( 'RELATED-TO' == $sortArg ) - $c->srtk[0] .= $c->getProperty( 'uid' ); - } - elseif( 'RELATED-TO' == $sortArg ) - $c->srtk[0] = $c->getProperty( 'uid' ); - } - elseif( FALSE !== ( $d = $c->getProperty( $sortArg ))) { - $c->srtk[0] = $d; - if( 'UID' == $sortArg ) { - if( FALSE !== ( $d = $c->getProperty( 'recurrence-id' ))) { - $c->srtk[1] = iCalUtilityFunctions::_date2strdate( $d ); - if( FALSE === ( $c->srtk[2] = $c->getProperty( 'sequence' ))) - $c->srtk[2] = PHP_INT_MAX; - } - else - $c->srtk[1] = $c->srtk[2] = PHP_INT_MAX; - } - } - continue; - } - if( FALSE !== ( $d = $c->getProperty( 'X-CURRENT-DTSTART' ))) { - $c->srtk[0] = iCalUtilityFunctions::_strdate2date( $d[1] ); - unset( $c->srtk[0]['unparsedtext'] ); - } - elseif( FALSE === ( $c->srtk[0] = $c->getProperty( 'dtstart' ))) - $c->srtk[1] = 0; // sortkey 0 : dtstart - if( FALSE !== ( $d = $c->getProperty( 'X-CURRENT-DTEND' ))) { - $c->srtk[1] = iCalUtilityFunctions::_strdate2date( $d[1] ); // sortkey 1 : dtend/due(/dtstart+duration) - unset( $c->srtk[1]['unparsedtext'] ); - } - elseif( FALSE === ( $c->srtk[1] = $c->getProperty( 'dtend' ))) { - if( FALSE !== ( $d = $c->getProperty( 'X-CURRENT-DUE' ))) { - $c->srtk[1] = iCalUtilityFunctions::_strdate2date( $d[1] ); - unset( $c->srtk[1]['unparsedtext'] ); - } - elseif( FALSE === ( $c->srtk[1] = $c->getProperty( 'due' ))) - if( FALSE === ( $c->srtk[1] = $c->getProperty( 'duration', FALSE, FALSE, TRUE ))) - $c->srtk[1] = 0; - } - if( FALSE === ( $c->srtk[2] = $c->getProperty( 'created' ))) // sortkey 2 : created/dtstamp - if( FALSE === ( $c->srtk[2] = $c->getProperty( 'dtstamp' ))) - $c->srtk[2] = 0; - if( FALSE === ( $c->srtk[3] = $c->getProperty( 'uid' ))) // sortkey 3 : uid - $c->srtk[3] = 0; - } // end foreach( $this->components as & $c - /* sort */ - usort( $this->components, array( 'iCalUtilityFunctions', '_cmpfcn' )); - } - } -/** - * parse iCal text/file into vcalendar, components, properties and parameters - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.16.2 - 2012-12-18 - * @param mixed $unparsedtext, optional, strict rfc2445 formatted, single property string or array of property strings - * @return bool FALSE if error occurs during parsing - * - */ - function parse( $unparsedtext=FALSE ) { - $nl = $this->getConfig( 'nl' ); - if(( FALSE === $unparsedtext ) || empty( $unparsedtext )) { - /* directory+filename is set previously via setConfig directory+filename or url */ - if( FALSE === ( $filename = $this->getConfig( 'url' ))) - $filename = $this->getConfig( 'dirfile' ); - /* READ FILE */ - if( FALSE === ( $rows = file_get_contents( $filename ))) - return FALSE; /* err 1 */ - } - elseif( is_array( $unparsedtext )) - $rows = implode( '\n'.$nl, $unparsedtext ); - else - $rows = & $unparsedtext; - /* fix line folding */ - $rows = explode( $nl, iCalUtilityFunctions::convEolChar( $rows, $nl )); - /* skip leading (empty/invalid) lines */ - foreach( $rows as $lix => $line ) { - if( FALSE !== stripos( $line, 'BEGIN:VCALENDAR' )) - break; - unset( $rows[$lix] ); - } - $rcnt = count( $rows ); - if( 3 > $rcnt ) /* err 10 */ - return FALSE; - /* skip trailing empty lines and ensure an end row */ - $lix = array_keys( $rows ); - $lix = end( $lix ); - while( 3 < $lix ) { - $tst = trim( $rows[$lix] ); - if(( '\n' == $tst ) || empty( $tst )) { - unset( $rows[$lix] ); - $lix--; - continue; - } - if( FALSE === stripos( $rows[$lix], 'END:VCALENDAR' )) - $rows[] = 'END:VCALENDAR'; - break; - } - $comp = & $this; - $calsync = $compsync = 0; - /* identify components and update unparsed data within component */ - $config = $this->getConfig(); - $endtxt = array( 'END:VE', 'END:VF', 'END:VJ', 'END:VT' ); - foreach( $rows as $lix => $line ) { - if( 'BEGIN:VCALENDAR' == strtoupper( substr( $line, 0, 15 ))) { - $calsync++; - continue; - } - elseif( 'END:VCALENDAR' == strtoupper( substr( $line, 0, 13 ))) { - if( 0 < $compsync ) - $this->components[] = $comp->copy(); - $compsync--; - $calsync--; - break; - } - elseif( 1 != $calsync ) - return FALSE; /* err 20 */ - elseif( in_array( strtoupper( substr( $line, 0, 6 )), $endtxt )) { - $this->components[] = $comp->copy(); - $compsync--; - continue; - } - if( 'BEGIN:VEVENT' == strtoupper( substr( $line, 0, 12 ))) { - $comp = new vevent( $config ); - $compsync++; - } - elseif( 'BEGIN:VFREEBUSY' == strtoupper( substr( $line, 0, 15 ))) { - $comp = new vfreebusy( $config ); - $compsync++; - } - elseif( 'BEGIN:VJOURNAL' == strtoupper( substr( $line, 0, 14 ))) { - $comp = new vjournal( $config ); - $compsync++; - } - elseif( 'BEGIN:VTODO' == strtoupper( substr( $line, 0, 11 ))) { - $comp = new vtodo( $config ); - $compsync++; - } - elseif( 'BEGIN:VTIMEZONE' == strtoupper( substr( $line, 0, 15 ))) { - $comp = new vtimezone( $config ); - $compsync++; - } - else { /* update component with unparsed data */ - $comp->unparsed[] = $line; - } - } // end foreach( $rows as $line ) - unset( $config, $endtxt ); - /* parse data for calendar (this) object */ - if( isset( $this->unparsed ) && is_array( $this->unparsed ) && ( 0 < count( $this->unparsed ))) { - /* concatenate property values spread over several lines */ - $propnames = array( 'calscale','method','prodid','version','x-' ); - $proprows = array(); - for( $i = 0; $i < count( $this->unparsed ); $i++ ) { // concatenate lines - $line = rtrim( $this->unparsed[$i], $nl ); - while( isset( $this->unparsed[$i+1] ) && !empty( $this->unparsed[$i+1] ) && ( ' ' == $this->unparsed[$i+1]{0} )) - $line .= rtrim( substr( $this->unparsed[++$i], 1 ), $nl ); - $proprows[] = $line; - } - $paramMStz = array( 'utc-', 'utc+', 'gmt-', 'gmt+' ); - $paramProto3 = array( 'fax:', 'cid:', 'sms:', 'tel:', 'urn:' ); - $paramProto4 = array( 'crid:', 'news:', 'pres:' ); - foreach( $proprows as $line ) { - if( '\n' == substr( $line, -2 )) - $line = substr( $line, 0, -2 ); - /* get property name */ - $propname = ''; - $cix = 0; - while( FALSE !== ( $char = substr( $line, $cix, 1 ))) { - if( in_array( $char, array( ':', ';' ))) - break; - else - $propname .= $char; - $cix++; - } - /* skip non standard property names */ - if(( 'x-' != strtolower( substr( $propname, 0, 2 ))) && !in_array( strtolower( $propname ), $propnames )) - continue; - /* ignore version/prodid properties */ - if( in_array( strtolower( $propname ), array( 'version', 'prodid' ))) - continue; - /* rest of the line is opt.params and value */ - $line = substr( $line, $cix); - /* separate attributes from value */ - $attr = array(); - $attrix = -1; - $strlen = strlen( $line ); - $WithinQuotes = FALSE; - $cix = 0; - while( FALSE !== substr( $line, $cix, 1 )) { - if( ( ':' == $line[$cix] ) && - ( substr( $line,$cix, 3 ) != '://' ) && - ( !in_array( strtolower( substr( $line,$cix - 6, 4 )), $paramMStz )) && - ( !in_array( strtolower( substr( $line,$cix - 3, 4 )), $paramProto3 )) && - ( !in_array( strtolower( substr( $line,$cix - 4, 5 )), $paramProto4 )) && - ( strtolower( substr( $line,$cix - 6, 7 )) != 'mailto:' ) && - !$WithinQuotes ) { - $attrEnd = TRUE; - if(( $cix < ( $strlen - 4 )) && - ctype_digit( substr( $line, $cix+1, 4 ))) { // an URI with a (4pos) portnr?? - for( $c2ix = $cix; 3 < $c2ix; $c2ix-- ) { - if( '://' == substr( $line, $c2ix - 2, 3 )) { - $attrEnd = FALSE; - break; // an URI with a portnr!! - } - } - } - if( $attrEnd) { - $line = substr( $line, ( $cix + 1 )); - break; - } - } - if( '"' == $line[$cix] ) - $WithinQuotes = ( FALSE === $WithinQuotes ) ? TRUE : FALSE; - if( ';' == $line[$cix] ) - $attr[++$attrix] = null; - else - $attr[$attrix] .= $line[$cix]; - $cix++; - } - /* make attributes in array format */ - $propattr = array(); - foreach( $attr as $attribute ) { - $attrsplit = explode( '=', $attribute, 2 ); - if( 1 < count( $attrsplit )) - $propattr[$attrsplit[0]] = $attrsplit[1]; - else - $propattr[] = $attribute; - } - /* update Property */ - if( FALSE !== strpos( $line, ',' )) { - $content = array( 0 => '' ); - $cix = $lix = 0; - while( FALSE !== substr( $line, $lix, 1 )) { - if(( 0 < $lix ) && ( ',' == $line[$lix] ) && ( "\\" != $line[( $lix - 1 )])) { - $cix++; - $content[$cix] = ''; - } - else - $content[$cix] .= $line[$lix]; - $lix++; - } - if( 1 < count( $content )) { - foreach( $content as $cix => $contentPart ) - $content[$cix] = iCalUtilityFunctions::_strunrep( $contentPart ); - $this->setProperty( $propname, $content, $propattr ); - continue; - } - else - $line = reset( $content ); - $line = iCalUtilityFunctions::_strunrep( $line ); - } - $this->setProperty( $propname, rtrim( $line, "\x00..\x1F" ), $propattr ); - } // end - foreach( $this->unparsed.. . - } // end - if( is_array( $this->unparsed.. . - unset( $unparsedtext, $rows, $this->unparsed, $proprows ); - /* parse Components */ - if( is_array( $this->components ) && ( 0 < count( $this->components ))) { - $ckeys = array_keys( $this->components ); - foreach( $ckeys as $ckey ) { - if( !empty( $this->components[$ckey] ) && !empty( $this->components[$ckey]->unparsed )) { - $this->components[$ckey]->parse(); - } - } - } - else - return FALSE; /* err 91 or something.. . */ - return TRUE; - } -/*********************************************************************************/ -/** - * creates formatted output for calendar object instance - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.10.16 - 2011-10-28 - * @return string - */ - function createCalendar() { - $calendarInit = $calendarxCaldecl = $calendarStart = $calendar = ''; - switch( $this->format ) { - case 'xcal': - $calendarInit = ''.$this->nl. - 'nl. - '"http://www.ietf.org/internet-drafts/draft-ietf-calsch-many-xcal-01.txt"'; - $calendarStart = '>'.$this->nl.'nl; - break; - } - $calendarStart .= $this->createVersion(); - $calendarStart .= $this->createProdid(); - $calendarStart .= $this->createCalscale(); - $calendarStart .= $this->createMethod(); - if( 'xcal' == $this->format ) - $calendarStart .= '>'.$this->nl; - $calendar .= $this->createXprop(); - - foreach( $this->components as $component ) { - if( empty( $component )) continue; - $component->setConfig( $this->getConfig(), FALSE, TRUE ); - $calendar .= $component->createComponent( $this->xcaldecl ); - } - if(( 'xcal' == $this->format ) && ( 0 < count( $this->xcaldecl ))) { // xCal only - $calendarInit .= ' ['; - $old_xcaldecl = array(); - foreach( $this->xcaldecl as $declix => $declPart ) { - if(( 0 < count( $old_xcaldecl)) && - isset( $declPart['uri'] ) && isset( $declPart['external'] ) && - isset( $old_xcaldecl['uri'] ) && isset( $old_xcaldecl['external'] ) && - ( in_array( $declPart['uri'], $old_xcaldecl['uri'] )) && - ( in_array( $declPart['external'], $old_xcaldecl['external'] ))) - continue; // no duplicate uri and ext. references - if(( 0 < count( $old_xcaldecl)) && - !isset( $declPart['uri'] ) && !isset( $declPart['uri'] ) && - isset( $declPart['ref'] ) && isset( $old_xcaldecl['ref'] ) && - ( in_array( $declPart['ref'], $old_xcaldecl['ref'] ))) - continue; // no duplicate element declarations - $calendarxCaldecl .= $this->nl.' $declValue ) { - switch( $declKey ) { // index - case 'xmldecl': // no 1 - $calendarxCaldecl .= $declValue.' '; - break; - case 'uri': // no 2 - $calendarxCaldecl .= $declValue.' '; - $old_xcaldecl['uri'][] = $declValue; - break; - case 'ref': // no 3 - $calendarxCaldecl .= $declValue.' '; - $old_xcaldecl['ref'][] = $declValue; - break; - case 'external': // no 4 - $calendarxCaldecl .= '"'.$declValue.'" '; - $old_xcaldecl['external'][] = $declValue; - break; - case 'type': // no 5 - $calendarxCaldecl .= $declValue.' '; - break; - case 'type2': // no 6 - $calendarxCaldecl .= $declValue; - break; - } - } - $calendarxCaldecl .= '>'; - } - $calendarxCaldecl .= $this->nl.']'; - } - switch( $this->format ) { - case 'xcal': - $calendar .= ''.$this->nl; - break; - default: - $calendar .= 'END:VCALENDAR'.$this->nl; - break; - } - return $calendarInit.$calendarxCaldecl.$calendarStart.$calendar; - } -/** - * a HTTP redirect header is sent with created, updated and/or parsed calendar - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.10.24 - 2011-12-23 - * @param bool $utf8Encode - * @param bool $gzip - * @return redirect - */ - function returnCalendar( $utf8Encode=FALSE, $gzip=FALSE ) { - $filename = $this->getConfig( 'filename' ); - $output = $this->createCalendar(); - if( $utf8Encode ) - $output = utf8_encode( $output ); - if( $gzip ) { - $output = gzencode( $output, 9 ); - header( 'Content-Encoding: gzip' ); - header( 'Vary: *' ); - header( 'Content-Length: '.strlen( $output )); - } - if( 'xcal' == $this->format ) - header( 'Content-Type: application/calendar+xml; charset=utf-8' ); - else - header( 'Content-Type: text/calendar; charset=utf-8' ); - header( 'Content-Disposition: attachment; filename="'.$filename.'"' ); - header( 'Cache-Control: max-age=10' ); - die( $output ); - } -/** - * save content in a file - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.2.12 - 2007-12-30 - * @param string $directory optional - * @param string $filename optional - * @param string $delimiter optional - * @return bool - */ - function saveCalendar( $directory=FALSE, $filename=FALSE, $delimiter=FALSE ) { - if( $directory ) - $this->setConfig( 'directory', $directory ); - if( $filename ) - $this->setConfig( 'filename', $filename ); - if( $delimiter && ($delimiter != DIRECTORY_SEPARATOR )) - $this->setConfig( 'delimiter', $delimiter ); - if( FALSE === ( $dirfile = $this->getConfig( 'url' ))) - $dirfile = $this->getConfig( 'dirfile' ); - $iCalFile = @fopen( $dirfile, 'w' ); - if( $iCalFile ) { - if( FALSE === fwrite( $iCalFile, $this->createCalendar() )) - return FALSE; - fclose( $iCalFile ); - return TRUE; - } - else - return FALSE; - } -/** - * if recent version of calendar file exists (default one hour), an HTTP redirect header is sent - * else FALSE is returned - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.2.12 - 2007-10-28 - * @param string $directory optional alt. int timeout - * @param string $filename optional - * @param string $delimiter optional - * @param int timeout optional, default 3600 sec - * @return redirect/FALSE - */ - function useCachedCalendar( $directory=FALSE, $filename=FALSE, $delimiter=FALSE, $timeout=3600) { - if ( $directory && ctype_digit( (string) $directory ) && !$filename ) { - $timeout = (int) $directory; - $directory = FALSE; - } - if( $directory ) - $this->setConfig( 'directory', $directory ); - if( $filename ) - $this->setConfig( 'filename', $filename ); - if( $delimiter && ( $delimiter != DIRECTORY_SEPARATOR )) - $this->setConfig( 'delimiter', $delimiter ); - $filesize = $this->getConfig( 'filesize' ); - if( 0 >= $filesize ) - return FALSE; - $dirfile = $this->getConfig( 'dirfile' ); - if( time() - filemtime( $dirfile ) < $timeout) { - clearstatcache(); - $dirfile = $this->getConfig( 'dirfile' ); - $filename = $this->getConfig( 'filename' ); -// if( headers_sent( $filename, $linenum )) -// die( "Headers already sent in $filename on line $linenum\n" ); - if( 'xcal' == $this->format ) - header( 'Content-Type: application/calendar+xml; charset=utf-8' ); - else - header( 'Content-Type: text/calendar; charset=utf-8' ); - header( 'Content-Length: '.$filesize ); - header( 'Content-Disposition: attachment; filename="'.$filename.'"' ); - header( 'Cache-Control: max-age=10' ); - $fp = @fopen( $dirfile, 'r' ); - if( $fp ) { - fpassthru( $fp ); - fclose( $fp ); - } - die(); - } - else - return FALSE; - } -} -/*********************************************************************************/ -/*********************************************************************************/ -/** - * abstract class for calendar components - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.9.6 - 2011-05-14 - */ -class calendarComponent { - // component property variables - var $uid; - var $dtstamp; - - // component config variables - var $allowEmpty; - var $language; - var $nl; - var $unique_id; - var $format; - var $objName; // created automatically at instance creation - var $dtzid; // default (local) timezone - // component internal variables - var $componentStart1; - var $componentStart2; - var $componentEnd1; - var $componentEnd2; - var $elementStart1; - var $elementStart2; - var $elementEnd1; - var $elementEnd2; - var $intAttrDelimiter; - var $attributeDelimiter; - var $valueInit; - // component xCal declaration container - var $xcaldecl; -/** - * constructor for calendar component object - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.9.6 - 2011-05-17 - */ - function calendarComponent() { - $this->objName = ( isset( $this->timezonetype )) ? - strtolower( $this->timezonetype ) : get_class ( $this ); - $this->uid = array(); - $this->dtstamp = array(); - - $this->language = null; - $this->nl = null; - $this->unique_id = null; - $this->format = null; - $this->dtzid = null; - $this->allowEmpty = TRUE; - $this->xcaldecl = array(); - - $this->_createFormat(); - $this->_makeDtstamp(); - } -/*********************************************************************************/ -/** - * Property Name: ACTION - */ -/** - * creates formatted output for calendar component property action - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.4.8 - 2008-10-22 - * @return string - */ - function createAction() { - if( empty( $this->action )) return FALSE; - if( empty( $this->action['value'] )) - return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'ACTION' ) : FALSE; - $attributes = $this->_createParams( $this->action['params'] ); - return $this->_createElement( 'ACTION', $attributes, $this->action['value'] ); - } -/** - * set calendar component property action - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.4.8 - 2008-11-04 - * @param string $value "AUDIO" / "DISPLAY" / "EMAIL" / "PROCEDURE" - * @param mixed $params - * @return bool - */ - function setAction( $value, $params=FALSE ) { - if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE; - $this->action = array( 'value' => $value, 'params' => iCalUtilityFunctions::_setParams( $params )); - return TRUE; - } -/*********************************************************************************/ -/** - * Property Name: ATTACH - */ -/** - * creates formatted output for calendar component property attach - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.11.16 - 2012-02-04 - * @return string - */ - function createAttach() { - if( empty( $this->attach )) return FALSE; - $output = null; - foreach( $this->attach as $attachPart ) { - if( !empty( $attachPart['value'] )) { - $attributes = $this->_createParams( $attachPart['params'] ); - if(( 'xcal' != $this->format ) && isset( $attachPart['params']['VALUE'] ) && ( 'BINARY' == $attachPart['params']['VALUE'] )) { - $attributes = str_replace( $this->intAttrDelimiter, $this->attributeDelimiter, $attributes ); - $str = 'ATTACH'.$attributes.$this->valueInit.$attachPart['value']; - $output = substr( $str, 0, 75 ).$this->nl; - $str = substr( $str, 75 ); - $output .= ' '.chunk_split( $str, 74, $this->nl.' ' ); - if( ' ' == substr( $output, -1 )) - $output = rtrim( $output ); - if( $this->nl != substr( $output, ( 0 - strlen( $this->nl )))) - $output .= $this->nl; - return $output; - } - $output .= $this->_createElement( 'ATTACH', $attributes, $attachPart['value'] ); - } - elseif( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'ATTACH' ); - } - return $output; - } -/** - * set calendar component property attach - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.5.1 - 2008-11-06 - * @param string $value - * @param array $params, optional - * @param integer $index, optional - * @return bool - */ - function setAttach( $value, $params=FALSE, $index=FALSE ) { - if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE; - iCalUtilityFunctions::_setMval( $this->attach, $value, $params, FALSE, $index ); - return TRUE; - } -/*********************************************************************************/ -/** - * Property Name: ATTENDEE - */ -/** - * creates formatted output for calendar component property attendee - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.11.12 - 2012-01-31 - * @return string - */ - function createAttendee() { - if( empty( $this->attendee )) return FALSE; - $output = null; - foreach( $this->attendee as $attendeePart ) { // start foreach 1 - if( empty( $attendeePart['value'] )) { - if( $this->getConfig( 'allowEmpty' )) - $output .= $this->_createElement( 'ATTENDEE' ); - continue; - } - $attendee1 = $attendee2 = null; - foreach( $attendeePart as $paramlabel => $paramvalue ) { // start foreach 2 - if( 'value' == $paramlabel ) - $attendee2 .= $paramvalue; - elseif(( 'params' == $paramlabel ) && ( is_array( $paramvalue ))) { // start elseif - $mParams = array( 'MEMBER', 'DELEGATED-TO', 'DELEGATED-FROM' ); - foreach( $paramvalue as $pKey => $pValue ) { // fix (opt) quotes - if( is_array( $pValue ) || in_array( $pKey, $mParams )) - continue; - if(( FALSE !== strpos( $pValue, ':' )) || - ( FALSE !== strpos( $pValue, ';' )) || - ( FALSE !== strpos( $pValue, ',' ))) - $paramvalue[$pKey] = '"'.$pValue.'"'; - } - // set attenddee parameters in rfc2445 order - if( isset( $paramvalue['CUTYPE'] )) - $attendee1 .= $this->intAttrDelimiter.'CUTYPE='.$paramvalue['CUTYPE']; - if( isset( $paramvalue['MEMBER'] )) { - $attendee1 .= $this->intAttrDelimiter.'MEMBER='; - foreach( $paramvalue['MEMBER'] as $cix => $opv ) - $attendee1 .= ( $cix ) ? ',"'.$opv.'"' : '"'.$opv.'"' ; - } - if( isset( $paramvalue['ROLE'] )) - $attendee1 .= $this->intAttrDelimiter.'ROLE='.$paramvalue['ROLE']; - if( isset( $paramvalue['PARTSTAT'] )) - $attendee1 .= $this->intAttrDelimiter.'PARTSTAT='.$paramvalue['PARTSTAT']; - if( isset( $paramvalue['RSVP'] )) - $attendee1 .= $this->intAttrDelimiter.'RSVP='.$paramvalue['RSVP']; - if( isset( $paramvalue['DELEGATED-TO'] )) { - $attendee1 .= $this->intAttrDelimiter.'DELEGATED-TO='; - foreach( $paramvalue['DELEGATED-TO'] as $cix => $opv ) - $attendee1 .= ( $cix ) ? ',"'.$opv.'"' : '"'.$opv.'"' ; - } - if( isset( $paramvalue['DELEGATED-FROM'] )) { - $attendee1 .= $this->intAttrDelimiter.'DELEGATED-FROM='; - foreach( $paramvalue['DELEGATED-FROM'] as $cix => $opv ) - $attendee1 .= ( $cix ) ? ',"'.$opv.'"' : '"'.$opv.'"' ; - } - if( isset( $paramvalue['SENT-BY'] )) - $attendee1 .= $this->intAttrDelimiter.'SENT-BY='.$paramvalue['SENT-BY']; - if( isset( $paramvalue['CN'] )) - $attendee1 .= $this->intAttrDelimiter.'CN='.$paramvalue['CN']; - if( isset( $paramvalue['DIR'] )) { - $delim = ( FALSE === strpos( $paramvalue['DIR'], '"' )) ? '"' : ''; - $attendee1 .= $this->intAttrDelimiter.'DIR='.$delim.$paramvalue['DIR'].$delim; - } - if( isset( $paramvalue['LANGUAGE'] )) - $attendee1 .= $this->intAttrDelimiter.'LANGUAGE='.$paramvalue['LANGUAGE']; - $xparams = array(); - foreach( $paramvalue as $optparamlabel => $optparamvalue ) { // start foreach 3 - if( ctype_digit( (string) $optparamlabel )) { - $xparams[] = $optparamvalue; - continue; - } - if( !in_array( $optparamlabel, array( 'CUTYPE', 'MEMBER', 'ROLE', 'PARTSTAT', 'RSVP', 'DELEGATED-TO', 'DELEGATED-FROM', 'SENT-BY', 'CN', 'DIR', 'LANGUAGE' ))) - $xparams[$optparamlabel] = $optparamvalue; - } // end foreach 3 - ksort( $xparams, SORT_STRING ); - foreach( $xparams as $paramKey => $paramValue ) { - if( ctype_digit( (string) $paramKey )) - $attendee1 .= $this->intAttrDelimiter.$paramValue; - else - $attendee1 .= $this->intAttrDelimiter."$paramKey=$paramValue"; - } // end foreach 3 - } // end elseif(( 'params' == $paramlabel ) && ( is_array( $paramvalue ))) - } // end foreach 2 - $output .= $this->_createElement( 'ATTENDEE', $attendee1, $attendee2 ); - } // end foreach 1 - return $output; - } -/** - * set calendar component property attach - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.12.18 - 2012-07-13 - * @param string $value - * @param array $params, optional - * @param integer $index, optional - * @return bool - */ - function setAttendee( $value, $params=FALSE, $index=FALSE ) { - if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE; - // ftp://, http://, mailto:, file://, gopher://, news:, nntp://, telnet://, wais://, prospero:// may exist.. . also in params - if( !empty( $value )) { - if( FALSE === ( $pos = strpos( substr( $value, 0, 9 ), ':' ))) - $value = 'MAILTO:'.$value; - elseif( !empty( $value )) - $value = strtolower( substr( $value, 0, $pos )).substr( $value, $pos ); - $value = str_replace( 'mailto:', 'MAILTO:', $value ); - } - $params2 = array(); - if( is_array($params )) { - $optarrays = array(); - foreach( $params as $optparamlabel => $optparamvalue ) { - $optparamlabel = strtoupper( $optparamlabel ); - switch( $optparamlabel ) { - case 'MEMBER': - case 'DELEGATED-TO': - case 'DELEGATED-FROM': - if( !is_array( $optparamvalue )) - $optparamvalue = array( $optparamvalue ); - foreach( $optparamvalue as $part ) { - $part = trim( $part ); - if(( '"' == substr( $part, 0, 1 )) && - ( '"' == substr( $part, -1 ))) - $part = substr( $part, 1, ( strlen( $part ) - 2 )); - if( 'mailto:' != strtolower( substr( $part, 0, 7 ))) - $part = "MAILTO:$part"; - else - $part = 'MAILTO:'.substr( $part, 7 ); - $optarrays[$optparamlabel][] = $part; - } - break; - default: - if(( '"' == substr( $optparamvalue, 0, 1 )) && - ( '"' == substr( $optparamvalue, -1 ))) - $optparamvalue = substr( $optparamvalue, 1, ( strlen( $optparamvalue ) - 2 )); - if( 'SENT-BY' == $optparamlabel ) { - if( 'mailto:' != strtolower( substr( $optparamvalue, 0, 7 ))) - $optparamvalue = "MAILTO:$optparamvalue"; - else - $optparamvalue = 'MAILTO:'.substr( $optparamvalue, 7 ); - } - $params2[$optparamlabel] = $optparamvalue; - break; - } // end switch( $optparamlabel.. . - } // end foreach( $optparam.. . - foreach( $optarrays as $optparamlabel => $optparams ) - $params2[$optparamlabel] = $optparams; - } - // remove defaults - iCalUtilityFunctions::_existRem( $params2, 'CUTYPE', 'INDIVIDUAL' ); - iCalUtilityFunctions::_existRem( $params2, 'PARTSTAT', 'NEEDS-ACTION' ); - iCalUtilityFunctions::_existRem( $params2, 'ROLE', 'REQ-PARTICIPANT' ); - iCalUtilityFunctions::_existRem( $params2, 'RSVP', 'FALSE' ); - // check language setting - if( isset( $params2['CN' ] )) { - $lang = $this->getConfig( 'language' ); - if( !isset( $params2['LANGUAGE' ] ) && !empty( $lang )) - $params2['LANGUAGE' ] = $lang; - } - iCalUtilityFunctions::_setMval( $this->attendee, $value, $params2, FALSE, $index ); - return TRUE; - } -/*********************************************************************************/ -/** - * Property Name: CATEGORIES - */ -/** - * creates formatted output for calendar component property categories - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.16.2 - 2012-12-18 - * @return string - */ - function createCategories() { - if( empty( $this->categories )) return FALSE; - $output = null; - foreach( $this->categories as $category ) { - if( empty( $category['value'] )) { - if ( $this->getConfig( 'allowEmpty' )) - $output .= $this->_createElement( 'CATEGORIES' ); - continue; - } - $attributes = $this->_createParams( $category['params'], array( 'LANGUAGE' )); - if( is_array( $category['value'] )) { - foreach( $category['value'] as $cix => $categoryPart ) - $category['value'][$cix] = iCalUtilityFunctions::_strrep( $categoryPart, $this->format, $this->nl ); - $content = implode( ',', $category['value'] ); - } - else - $content = iCalUtilityFunctions::_strrep( $category['value'], $this->format, $this->nl ); - $output .= $this->_createElement( 'CATEGORIES', $attributes, $content ); - } - return $output; - } -/** - * set calendar component property categories - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.5.1 - 2008-11-06 - * @param mixed $value - * @param array $params, optional - * @param integer $index, optional - * @return bool - */ - function setCategories( $value, $params=FALSE, $index=FALSE ) { - if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE; - iCalUtilityFunctions::_setMval( $this->categories, $value, $params, FALSE, $index ); - return TRUE; - } -/*********************************************************************************/ -/** - * Property Name: CLASS - */ -/** - * creates formatted output for calendar component property class - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 0.9.7 - 2006-11-20 - * @return string - */ - function createClass() { - if( empty( $this->class )) return FALSE; - if( empty( $this->class['value'] )) - return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'CLASS' ) : FALSE; - $attributes = $this->_createParams( $this->class['params'] ); - return $this->_createElement( 'CLASS', $attributes, $this->class['value'] ); - } -/** - * set calendar component property class - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.4.8 - 2008-11-04 - * @param string $value "PUBLIC" / "PRIVATE" / "CONFIDENTIAL" / iana-token / x-name - * @param array $params optional - * @return bool - */ - function setClass( $value, $params=FALSE ) { - if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE; - $this->class = array( 'value' => $value, 'params' => iCalUtilityFunctions::_setParams( $params )); - return TRUE; - } -/*********************************************************************************/ -/** - * Property Name: COMMENT - */ -/** - * creates formatted output for calendar component property comment - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.16.2 - 2012-12-18 - * @return string - */ - function createComment() { - if( empty( $this->comment )) return FALSE; - $output = null; - foreach( $this->comment as $commentPart ) { - if( empty( $commentPart['value'] )) { - if( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'COMMENT' ); - continue; - } - $attributes = $this->_createParams( $commentPart['params'], array( 'ALTREP', 'LANGUAGE' )); - $content = iCalUtilityFunctions::_strrep( $commentPart['value'], $this->format, $this->nl ); - $output .= $this->_createElement( 'COMMENT', $attributes, $content ); - } - return $output; - } -/** - * set calendar component property comment - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.5.1 - 2008-11-06 - * @param string $value - * @param array $params, optional - * @param integer $index, optional - * @return bool - */ - function setComment( $value, $params=FALSE, $index=FALSE ) { - if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE; - iCalUtilityFunctions::_setMval( $this->comment, $value, $params, FALSE, $index ); - return TRUE; - } -/*********************************************************************************/ -/** - * Property Name: COMPLETED - */ -/** - * creates formatted output for calendar component property completed - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.4.8 - 2008-10-22 - * @return string - */ - function createCompleted( ) { - if( empty( $this->completed )) return FALSE; - if( !isset( $this->completed['value']['year'] ) && - !isset( $this->completed['value']['month'] ) && - !isset( $this->completed['value']['day'] ) && - !isset( $this->completed['value']['hour'] ) && - !isset( $this->completed['value']['min'] ) && - !isset( $this->completed['value']['sec'] )) - if( $this->getConfig( 'allowEmpty' )) - return $this->_createElement( 'COMPLETED' ); - else return FALSE; - $formatted = iCalUtilityFunctions::_date2strdate( $this->completed['value'], 7 ); - $attributes = $this->_createParams( $this->completed['params'] ); - return $this->_createElement( 'COMPLETED', $attributes, $formatted ); - } -/** - * set calendar component property completed - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.4.8 - 2008-10-23 - * @param mixed $year - * @param mixed $month optional - * @param int $day optional - * @param int $hour optional - * @param int $min optional - * @param int $sec optional - * @param array $params optional - * @return bool - */ - function setCompleted( $year, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $params=FALSE ) { - if( empty( $year )) { - if( $this->getConfig( 'allowEmpty' )) { - $this->completed = array( 'value' => null, 'params' => iCalUtilityFunctions::_setParams( $params )); - return TRUE; - } - else - return FALSE; - } - $this->completed = iCalUtilityFunctions::_setDate2( $year, $month, $day, $hour, $min, $sec, $params ); - return TRUE; - } -/*********************************************************************************/ -/** - * Property Name: CONTACT - */ -/** - * creates formatted output for calendar component property contact - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.16.2 - 2012-12-18 - * @return string - */ - function createContact() { - if( empty( $this->contact )) return FALSE; - $output = null; - foreach( $this->contact as $contact ) { - if( !empty( $contact['value'] )) { - $attributes = $this->_createParams( $contact['params'], array( 'ALTREP', 'LANGUAGE' )); - $content = iCalUtilityFunctions::_strrep( $contact['value'], $this->format, $this->nl ); - $output .= $this->_createElement( 'CONTACT', $attributes, $content ); - } - elseif( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'CONTACT' ); - } - return $output; - } -/** - * set calendar component property contact - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.5.1 - 2008-11-05 - * @param string $value - * @param array $params, optional - * @param integer $index, optional - * @return bool - */ - function setContact( $value, $params=FALSE, $index=FALSE ) { - if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE; - iCalUtilityFunctions::_setMval( $this->contact, $value, $params, FALSE, $index ); - return TRUE; - } -/*********************************************************************************/ -/** - * Property Name: CREATED - */ -/** - * creates formatted output for calendar component property created - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.4.8 - 2008-10-21 - * @return string - */ - function createCreated() { - if( empty( $this->created )) return FALSE; - $formatted = iCalUtilityFunctions::_date2strdate( $this->created['value'], 7 ); - $attributes = $this->_createParams( $this->created['params'] ); - return $this->_createElement( 'CREATED', $attributes, $formatted ); - } -/** - * set calendar component property created - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.4.8 - 2008-10-23 - * @param mixed $year optional - * @param mixed $month optional - * @param int $day optional - * @param int $hour optional - * @param int $min optional - * @param int $sec optional - * @param mixed $params optional - * @return bool - */ - function setCreated( $year=FALSE, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $params=FALSE ) { - if( !isset( $year )) { - $year = date('Ymd\THis', mktime( date( 'H' ), date( 'i' ), date( 's' ) - date( 'Z'), date( 'm' ), date( 'd' ), date( 'Y' ))); - } - $this->created = iCalUtilityFunctions::_setDate2( $year, $month, $day, $hour, $min, $sec, $params ); - return TRUE; - } -/*********************************************************************************/ -/** - * Property Name: DESCRIPTION - */ -/** - * creates formatted output for calendar component property description - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.16.2 - 2012-12-18 - * @return string - */ - function createDescription() { - if( empty( $this->description )) return FALSE; - $output = null; - foreach( $this->description as $description ) { - if( !empty( $description['value'] )) { - $attributes = $this->_createParams( $description['params'], array( 'ALTREP', 'LANGUAGE' )); - $content = iCalUtilityFunctions::_strrep( $description['value'], $this->format, $this->nl ); - $output .= $this->_createElement( 'DESCRIPTION', $attributes, $content ); - } - elseif( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'DESCRIPTION' ); - } - return $output; - } -/** - * set calendar component property description - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.6.24 - 2010-11-06 - * @param string $value - * @param array $params, optional - * @param integer $index, optional - * @return bool - */ - function setDescription( $value, $params=FALSE, $index=FALSE ) { - if( empty( $value )) { if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE; } - if( 'vjournal' != $this->objName ) - $index = 1; - iCalUtilityFunctions::_setMval( $this->description, $value, $params, FALSE, $index ); - return TRUE; - } -/*********************************************************************************/ -/** - * Property Name: DTEND - */ -/** - * creates formatted output for calendar component property dtend - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.14.4 - 2012-09-26 - * @return string - */ - function createDtend() { - if( empty( $this->dtend )) return FALSE; - if( !isset( $this->dtend['value']['year'] ) && - !isset( $this->dtend['value']['month'] ) && - !isset( $this->dtend['value']['day'] ) && - !isset( $this->dtend['value']['hour'] ) && - !isset( $this->dtend['value']['min'] ) && - !isset( $this->dtend['value']['sec'] )) - if( $this->getConfig( 'allowEmpty' )) - return $this->_createElement( 'DTEND' ); - else return FALSE; - $parno = ( isset( $this->dtend['params']['VALUE'] ) && ( 'DATE' == $this->dtend['params']['VALUE'] )) ? 3 : null; - $formatted = iCalUtilityFunctions::_date2strdate( $this->dtend['value'], $parno ); - $attributes = $this->_createParams( $this->dtend['params'] ); - return $this->_createElement( 'DTEND', $attributes, $formatted ); - } -/** - * set calendar component property dtend - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.9.6 - 2011-05-14 - * @param mixed $year - * @param mixed $month optional - * @param int $day optional - * @param int $hour optional - * @param int $min optional - * @param int $sec optional - * @param string $tz optional - * @param array params optional - * @return bool - */ - function setDtend( $year, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $tz=FALSE, $params=FALSE ) { - if( empty( $year )) { - if( $this->getConfig( 'allowEmpty' )) { - $this->dtend = array( 'value' => null, 'params' => iCalUtilityFunctions::_setParams( $params )); - return TRUE; - } - else - return FALSE; - } - $this->dtend = iCalUtilityFunctions::_setDate( $year, $month, $day, $hour, $min, $sec, $tz, $params, null, null, $this->getConfig( 'TZID' )); - return TRUE; - } -/*********************************************************************************/ -/** - * Property Name: DTSTAMP - */ -/** - * creates formatted output for calendar component property dtstamp - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.4.4 - 2008-03-07 - * @return string - */ - function createDtstamp() { - if( !isset( $this->dtstamp['value']['year'] ) && - !isset( $this->dtstamp['value']['month'] ) && - !isset( $this->dtstamp['value']['day'] ) && - !isset( $this->dtstamp['value']['hour'] ) && - !isset( $this->dtstamp['value']['min'] ) && - !isset( $this->dtstamp['value']['sec'] )) - $this->_makeDtstamp(); - $formatted = iCalUtilityFunctions::_date2strdate( $this->dtstamp['value'], 7 ); - $attributes = $this->_createParams( $this->dtstamp['params'] ); - return $this->_createElement( 'DTSTAMP', $attributes, $formatted ); - } -/** - * computes datestamp for calendar component object instance dtstamp - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.14.1 - 2012-09-29 - * @return void - */ - function _makeDtstamp() { - $d = date( 'Y-m-d-H-i-s', mktime( date('H'), date('i'), (date('s') - date( 'Z' )), date('m'), date('d'), date('Y'))); - $date = explode( '-', $d ); - $this->dtstamp['value'] = array( 'year' => $date[0], 'month' => $date[1], 'day' => $date[2], 'hour' => $date[3], 'min' => $date[4], 'sec' => $date[5], 'tz' => 'Z' ); - $this->dtstamp['params'] = null; - } -/** - * set calendar component property dtstamp - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.4.8 - 2008-10-23 - * @param mixed $year - * @param mixed $month optional - * @param int $day optional - * @param int $hour optional - * @param int $min optional - * @param int $sec optional - * @param array $params optional - * @return TRUE - */ - function setDtstamp( $year, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $params=FALSE ) { - if( empty( $year )) - $this->_makeDtstamp(); - else - $this->dtstamp = iCalUtilityFunctions::_setDate2( $year, $month, $day, $hour, $min, $sec, $params ); - return TRUE; - } -/*********************************************************************************/ -/** - * Property Name: DTSTART - */ -/** - * creates formatted output for calendar component property dtstart - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.14.4 - 2012-09-26 - * @return string - */ - function createDtstart() { - if( empty( $this->dtstart )) return FALSE; - if( !isset( $this->dtstart['value']['year'] ) && - !isset( $this->dtstart['value']['month'] ) && - !isset( $this->dtstart['value']['day'] ) && - !isset( $this->dtstart['value']['hour'] ) && - !isset( $this->dtstart['value']['min'] ) && - !isset( $this->dtstart['value']['sec'] )) { - if( $this->getConfig( 'allowEmpty' )) - return $this->_createElement( 'DTSTART' ); - else return FALSE; - } - if( in_array( $this->objName, array( 'vtimezone', 'standard', 'daylight' ))) - unset( $this->dtstart['value']['tz'], $this->dtstart['params']['TZID'] ); - $parno = ( isset( $this->dtstart['params']['VALUE'] ) && ( 'DATE' == $this->dtstart['params']['VALUE'] )) ? 3 : null; - $formatted = iCalUtilityFunctions::_date2strdate( $this->dtstart['value'], $parno ); - $attributes = $this->_createParams( $this->dtstart['params'] ); - return $this->_createElement( 'DTSTART', $attributes, $formatted ); - } -/** - * set calendar component property dtstart - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.6.22 - 2010-09-22 - * @param mixed $year - * @param mixed $month optional - * @param int $day optional - * @param int $hour optional - * @param int $min optional - * @param int $sec optional - * @param string $tz optional - * @param array $params optional - * @return bool - */ - function setDtstart( $year, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $tz=FALSE, $params=FALSE ) { - if( empty( $year )) { - if( $this->getConfig( 'allowEmpty' )) { - $this->dtstart = array( 'value' => null, 'params' => iCalUtilityFunctions::_setParams( $params )); - return TRUE; - } - else - return FALSE; - } - $this->dtstart = iCalUtilityFunctions::_setDate( $year, $month, $day, $hour, $min, $sec, $tz, $params, 'dtstart', $this->objName, $this->getConfig( 'TZID' )); - return TRUE; - } -/*********************************************************************************/ -/** - * Property Name: DUE - */ -/** - * creates formatted output for calendar component property due - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.14.4 - 2012-09-26 - * @return string - */ - function createDue() { - if( empty( $this->due )) return FALSE; - if( !isset( $this->due['value']['year'] ) && - !isset( $this->due['value']['month'] ) && - !isset( $this->due['value']['day'] ) && - !isset( $this->due['value']['hour'] ) && - !isset( $this->due['value']['min'] ) && - !isset( $this->due['value']['sec'] )) { - if( $this->getConfig( 'allowEmpty' )) - return $this->_createElement( 'DUE' ); - else - return FALSE; - } - $parno = ( isset( $this->due['params']['VALUE'] ) && ( 'DATE' == $this->due['params']['VALUE'] )) ? 3 : null; - $formatted = iCalUtilityFunctions::_date2strdate( $this->due['value'], $parno ); - $attributes = $this->_createParams( $this->due['params'] ); - return $this->_createElement( 'DUE', $attributes, $formatted ); - } -/** - * set calendar component property due - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.4.8 - 2008-11-04 - * @param mixed $year - * @param mixed $month optional - * @param int $day optional - * @param int $hour optional - * @param int $min optional - * @param int $sec optional - * @param array $params optional - * @return bool - */ - function setDue( $year, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $tz=FALSE, $params=FALSE ) { - if( empty( $year )) { - if( $this->getConfig( 'allowEmpty' )) { - $this->due = array( 'value' => null, 'params' => iCalUtilityFunctions::_setParams( $params )); - return TRUE; - } - else - return FALSE; - } - $this->due = iCalUtilityFunctions::_setDate( $year, $month, $day, $hour, $min, $sec, $tz, $params, null, null, $this->getConfig( 'TZID' )); - return TRUE; - } -/*********************************************************************************/ -/** - * Property Name: DURATION - */ -/** - * creates formatted output for calendar component property duration - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.4.8 - 2008-10-21 - * @return string - */ - function createDuration() { - if( empty( $this->duration )) return FALSE; - if( !isset( $this->duration['value']['week'] ) && - !isset( $this->duration['value']['day'] ) && - !isset( $this->duration['value']['hour'] ) && - !isset( $this->duration['value']['min'] ) && - !isset( $this->duration['value']['sec'] )) - if( $this->getConfig( 'allowEmpty' )) - return $this->_createElement( 'DURATION', array(), null ); - else return FALSE; - $attributes = $this->_createParams( $this->duration['params'] ); - return $this->_createElement( 'DURATION', $attributes, iCalUtilityFunctions::_duration2str( $this->duration['value'] )); - } -/** - * set calendar component property duration - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.4.8 - 2008-11-04 - * @param mixed $week - * @param mixed $day optional - * @param int $hour optional - * @param int $min optional - * @param int $sec optional - * @param array $params optional - * @return bool - */ - function setDuration( $week, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $params=FALSE ) { - if( empty( $week )) if( $this->getConfig( 'allowEmpty' )) $week = null; else return FALSE; - if( is_array( $week ) && ( 1 <= count( $week ))) - $this->duration = array( 'value' => iCalUtilityFunctions::_duration2arr( $week ), 'params' => iCalUtilityFunctions::_setParams( $day )); - elseif( is_string( $week ) && ( 3 <= strlen( trim( $week )))) { - $week = trim( $week ); - if( in_array( substr( $week, 0, 1 ), array( '+', '-' ))) - $week = substr( $week, 1 ); - $this->duration = array( 'value' => iCalUtilityFunctions::_durationStr2arr( $week ), 'params' => iCalUtilityFunctions::_setParams( $day )); - } - elseif( empty( $week ) && empty( $day ) && empty( $hour ) && empty( $min ) && empty( $sec )) - return FALSE; - else - $this->duration = array( 'value' => iCalUtilityFunctions::_duration2arr( array( $week, $day, $hour, $min, $sec )), 'params' => iCalUtilityFunctions::_setParams( $params )); - return TRUE; - } -/*********************************************************************************/ -/** - * Property Name: EXDATE - */ -/** - * creates formatted output for calendar component property exdate - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.16.5 - 2012-12-28 - * @return string - */ - function createExdate() { - if( empty( $this->exdate )) return FALSE; - $output = null; - $exdates = array(); - foreach( $this->exdate as $theExdate ) { - if( empty( $theExdate['value'] )) { - if( $this->getConfig( 'allowEmpty' )) - $output .= $this->_createElement( 'EXDATE' ); - continue; - } - if( 1 < count( $theExdate['value'] )) - usort( $theExdate['value'], array( 'iCalUtilityFunctions', '_sortExdate1' )); - $exdates[] = $theExdate; - } - if( 1 < count( $exdates )) - usort( $exdates, array( 'iCalUtilityFunctions', '_sortExdate2' )); - foreach( $exdates as $theExdate ) { - $content = $attributes = null; - foreach( $theExdate['value'] as $eix => $exdatePart ) { - $parno = count( $exdatePart ); - $formatted = iCalUtilityFunctions::_date2strdate( $exdatePart, $parno ); - if( isset( $theExdate['params']['TZID'] )) - $formatted = str_replace( 'Z', '', $formatted); - if( 0 < $eix ) { - if( isset( $theExdate['value'][0]['tz'] )) { - if( ctype_digit( substr( $theExdate['value'][0]['tz'], -4 )) || - ( 'Z' == $theExdate['value'][0]['tz'] )) { - if( 'Z' != substr( $formatted, -1 )) - $formatted .= 'Z'; - } - else - $formatted = str_replace( 'Z', '', $formatted ); - } - else - $formatted = str_replace( 'Z', '', $formatted ); - } // end if( 0 < $eix ) - $content .= ( 0 < $eix ) ? ','.$formatted : $formatted; - } // end foreach( $theExdate['value'] as $eix => $exdatePart ) - $attributes .= $this->_createParams( $theExdate['params'] ); - $output .= $this->_createElement( 'EXDATE', $attributes, $content ); - } // end foreach( $exdates as $theExdate ) - return $output; - } -/** - * set calendar component property exdate - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.14.1 - 2012-10-02 - * @param array exdates - * @param array $params, optional - * @param integer $index, optional - * @return bool - */ - function setExdate( $exdates, $params=FALSE, $index=FALSE ) { - if( empty( $exdates )) { - if( $this->getConfig( 'allowEmpty' )) { - iCalUtilityFunctions::_setMval( $this->exdate, null, $params, FALSE, $index ); - return TRUE; - } - else - return FALSE; - } - $input = array( 'params' => iCalUtilityFunctions::_setParams( $params, array( 'VALUE' => 'DATE-TIME' ))); - $toZ = ( isset( $input['params']['TZID'] ) && in_array( strtoupper( $input['params']['TZID'] ), array( 'GMT', 'UTC', 'Z' ))) ? TRUE : FALSE; - /* ev. check 1:st date and save ev. timezone **/ - iCalUtilityFunctions::_chkdatecfg( reset( $exdates ), $parno, $input['params'] ); - iCalUtilityFunctions::_existRem( $input['params'], 'VALUE', 'DATE-TIME' ); // remove default parameter - foreach( $exdates as $eix => $theExdate ) { - iCalUtilityFunctions::_strDate2arr( $theExdate ); - if( iCalUtilityFunctions::_isArrayTimestampDate( $theExdate )) { - if( isset( $theExdate['tz'] ) && !iCalUtilityFunctions::_isOffset( $theExdate['tz'] )) { - if( isset( $input['params']['TZID'] )) - $theExdate['tz'] = $input['params']['TZID']; - else - $input['params']['TZID'] = $theExdate['tz']; - } - $exdatea = iCalUtilityFunctions::_timestamp2date( $theExdate, $parno ); - } - elseif( is_array( $theExdate )) { - $d = iCalUtilityFunctions::_chkDateArr( $theExdate, $parno ); - if( isset( $d['tz'] ) && ( 'Z' != $d['tz'] ) && iCalUtilityFunctions::_isOffset( $d['tz'] )) { - $strdate = sprintf( '%04d-%02d-%02d %02d:%02d:%02d %s', $d['year'], $d['month'], $d['day'], $d['hour'], $d['min'], $d['sec'], $d['tz'] ); - $exdatea = iCalUtilityFunctions::_strdate2date( $strdate, 7 ); - unset( $exdatea['unparsedtext'] ); - } - else - $exdatea = $d; - } - elseif( 8 <= strlen( trim( $theExdate ))) { // ex. 2006-08-03 10:12:18 - $exdatea = iCalUtilityFunctions::_strdate2date( $theExdate, $parno ); - unset( $exdatea['unparsedtext'] ); - } - if( 3 == $parno ) - unset( $exdatea['hour'], $exdatea['min'], $exdatea['sec'], $exdatea['tz'] ); - elseif( isset( $exdatea['tz'] )) - $exdatea['tz'] = (string) $exdatea['tz']; - if( isset( $input['params']['TZID'] ) || - ( isset( $exdatea['tz'] ) && !iCalUtilityFunctions::_isOffset( $exdatea['tz'] )) || - ( isset( $input['value'][0] ) && ( !isset( $input['value'][0]['tz'] ))) || - ( isset( $input['value'][0]['tz'] ) && !iCalUtilityFunctions::_isOffset( $input['value'][0]['tz'] ))) - unset( $exdatea['tz'] ); - if( $toZ ) // time zone Z - $exdatea['tz'] = 'Z'; - $input['value'][] = $exdatea; - } - if( 0 >= count( $input['value'] )) - return FALSE; - if( 3 == $parno ) { - $input['params']['VALUE'] = 'DATE'; - unset( $input['params']['TZID'] ); - } - if( $toZ ) // time zone Z - unset( $input['params']['TZID'] ); - iCalUtilityFunctions::_setMval( $this->exdate, $input['value'], $input['params'], FALSE, $index ); - return TRUE; - } -/*********************************************************************************/ -/** - * Property Name: EXRULE - */ -/** - * creates formatted output for calendar component property exrule - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.4.8 - 2008-10-22 - * @return string - */ - function createExrule() { - if( empty( $this->exrule )) return FALSE; - return $this->_format_recur( 'EXRULE', $this->exrule ); - } -/** - * set calendar component property exdate - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.5.1 - 2008-11-05 - * @param array $exruleset - * @param array $params, optional - * @param integer $index, optional - * @return bool - */ - function setExrule( $exruleset, $params=FALSE, $index=FALSE ) { - if( empty( $exruleset )) if( $this->getConfig( 'allowEmpty' )) $exruleset = null; else return FALSE; - iCalUtilityFunctions::_setMval( $this->exrule, iCalUtilityFunctions::_setRexrule( $exruleset ), $params, FALSE, $index ); - return TRUE; - } -/*********************************************************************************/ -/** - * Property Name: FREEBUSY - */ -/** - * creates formatted output for calendar component property freebusy - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.1.23 - 2012-02-16 - * @return string - */ - function createFreebusy() { - if( empty( $this->freebusy )) return FALSE; - $output = null; - foreach( $this->freebusy as $freebusyPart ) { - if( empty( $freebusyPart['value'] ) || (( 1 == count( $freebusyPart['value'] )) && isset( $freebusyPart['value']['fbtype'] ))) { - if( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'FREEBUSY' ); - continue; - } - $attributes = $content = null; - if( isset( $freebusyPart['value']['fbtype'] )) { - $attributes .= $this->intAttrDelimiter.'FBTYPE='.$freebusyPart['value']['fbtype']; - unset( $freebusyPart['value']['fbtype'] ); - $freebusyPart['value'] = array_values( $freebusyPart['value'] ); - } - else - $attributes .= $this->intAttrDelimiter.'FBTYPE=BUSY'; - $attributes .= $this->_createParams( $freebusyPart['params'] ); - $fno = 1; - $cnt = count( $freebusyPart['value']); - foreach( $freebusyPart['value'] as $periodix => $freebusyPeriod ) { - $formatted = iCalUtilityFunctions::_date2strdate( $freebusyPeriod[0] ); - $content .= $formatted; - $content .= '/'; - $cnt2 = count( $freebusyPeriod[1]); - if( array_key_exists( 'year', $freebusyPeriod[1] )) // date-time - $cnt2 = 7; - elseif( array_key_exists( 'week', $freebusyPeriod[1] )) // duration - $cnt2 = 5; - if(( 7 == $cnt2 ) && // period= -> date-time - isset( $freebusyPeriod[1]['year'] ) && - isset( $freebusyPeriod[1]['month'] ) && - isset( $freebusyPeriod[1]['day'] )) { - $content .= iCalUtilityFunctions::_date2strdate( $freebusyPeriod[1] ); - } - else { // period= -> dur-time - $content .= iCalUtilityFunctions::_duration2str( $freebusyPeriod[1] ); - } - if( $fno < $cnt ) - $content .= ','; - $fno++; - } - $output .= $this->_createElement( 'FREEBUSY', $attributes, $content ); - } - return $output; - } -/** - * set calendar component property freebusy - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.10.30 - 2012-01-16 - * @param string $fbType - * @param array $fbValues - * @param array $params, optional - * @param integer $index, optional - * @return bool - */ - function setFreebusy( $fbType, $fbValues, $params=FALSE, $index=FALSE ) { - if( empty( $fbValues )) { - if( $this->getConfig( 'allowEmpty' )) { - iCalUtilityFunctions::_setMval( $this->freebusy, null, $params, FALSE, $index ); - return TRUE; - } - else - return FALSE; - } - $fbType = strtoupper( $fbType ); - if(( !in_array( $fbType, array( 'FREE', 'BUSY', 'BUSY-UNAVAILABLE', 'BUSY-TENTATIVE' ))) && - ( 'X-' != substr( $fbType, 0, 2 ))) - $fbType = 'BUSY'; - $input = array( 'fbtype' => $fbType ); - foreach( $fbValues as $fbPeriod ) { // periods => period - if( empty( $fbPeriod )) - continue; - $freebusyPeriod = array(); - foreach( $fbPeriod as $fbMember ) { // pairs => singlepart - $freebusyPairMember = array(); - if( is_array( $fbMember )) { - if( iCalUtilityFunctions::_isArrayDate( $fbMember )) { // date-time value - $freebusyPairMember = iCalUtilityFunctions::_chkDateArr( $fbMember, 7 ); - $freebusyPairMember['tz'] = 'Z'; - } - elseif( iCalUtilityFunctions::_isArrayTimestampDate( $fbMember )) { // timestamp value - $freebusyPairMember = iCalUtilityFunctions::_timestamp2date( $fbMember['timestamp'], 7 ); - $freebusyPairMember['tz'] = 'Z'; - } - else { // array format duration - $freebusyPairMember = iCalUtilityFunctions::_duration2arr( $fbMember ); - } - } - elseif(( 3 <= strlen( trim( $fbMember ))) && // string format duration - ( in_array( $fbMember{0}, array( 'P', '+', '-' )))) { - if( 'P' != $fbMember{0} ) - $fbmember = substr( $fbMember, 1 ); - $freebusyPairMember = iCalUtilityFunctions::_durationStr2arr( $fbMember ); - } - elseif( 8 <= strlen( trim( $fbMember ))) { // text date ex. 2006-08-03 10:12:18 - $freebusyPairMember = iCalUtilityFunctions::_strdate2date( $fbMember, 7 ); - unset( $freebusyPairMember['unparsedtext'] ); - $freebusyPairMember['tz'] = 'Z'; - } - $freebusyPeriod[] = $freebusyPairMember; - } - $input[] = $freebusyPeriod; - } - iCalUtilityFunctions::_setMval( $this->freebusy, $input, $params, FALSE, $index ); - return TRUE; - } -/*********************************************************************************/ -/** - * Property Name: GEO - */ -/** - * creates formatted output for calendar component property geo - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.12.6 - 2012-04-21 - * @return string - */ - function createGeo() { - if( empty( $this->geo )) return FALSE; - if( empty( $this->geo['value'] )) - return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'GEO' ) : FALSE; - $attributes = $this->_createParams( $this->geo['params'] ); - if( 0.0 < $this->geo['value']['latitude'] ) - $sign = '+'; - else - $sign = ( 0.0 > $this->geo['value']['latitude'] ) ? '-' : ''; - $content = $sign.sprintf( "%09.6f", abs( $this->geo['value']['latitude'] )); // sprintf && lpad && float && sign !"#¤%&/( - $content = rtrim( rtrim( $content, '0' ), '.' ); - if( 0.0 < $this->geo['value']['longitude'] ) - $sign = '+'; - else - $sign = ( 0.0 > $this->geo['value']['longitude'] ) ? '-' : ''; - $content .= ';'.$sign.sprintf( '%8.6f', abs( $this->geo['value']['longitude'] )); // sprintf && lpad && float && sign !"#¤%&/( - $content = rtrim( rtrim( $content, '0' ), '.' ); - return $this->_createElement( 'GEO', $attributes, $content ); - } -/** - * set calendar component property geo - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.12.5 - 2012-04-21 - * @param float $latitude - * @param float $longitude - * @param array $params optional - * @return bool - */ - function setGeo( $latitude, $longitude, $params=FALSE ) { - if(( !empty( $latitude ) || ( 0 == $latitude )) && - ( !empty( $longitude ) || ( 0 == $longitude ))) { - if( !is_array( $this->geo )) $this->geo = array(); - $this->geo['value']['latitude'] = (float) $latitude; - $this->geo['value']['longitude'] = (float) $longitude; - $this->geo['params'] = iCalUtilityFunctions::_setParams( $params ); - } - elseif( $this->getConfig( 'allowEmpty' )) - $this->geo = array( 'value' => null, 'params' => iCalUtilityFunctions::_setParams( $params ) ); - else - return FALSE; - return TRUE; - } -/*********************************************************************************/ -/** - * Property Name: LAST-MODIFIED - */ -/** - * creates formatted output for calendar component property last-modified - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.4.8 - 2008-10-21 - * @return string - */ - function createLastModified() { - if( empty( $this->lastmodified )) return FALSE; - $attributes = $this->_createParams( $this->lastmodified['params'] ); - $formatted = iCalUtilityFunctions::_date2strdate( $this->lastmodified['value'], 7 ); - return $this->_createElement( 'LAST-MODIFIED', $attributes, $formatted ); - } -/** - * set calendar component property completed - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.4.8 - 2008-10-23 - * @param mixed $year optional - * @param mixed $month optional - * @param int $day optional - * @param int $hour optional - * @param int $min optional - * @param int $sec optional - * @param array $params optional - * @return boll - */ - function setLastModified( $year=FALSE, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $params=FALSE ) { - if( empty( $year )) - $year = date('Ymd\THis', mktime( date( 'H' ), date( 'i' ), date( 's' ) - date( 'Z'), date( 'm' ), date( 'd' ), date( 'Y' ))); - $this->lastmodified = iCalUtilityFunctions::_setDate2( $year, $month, $day, $hour, $min, $sec, $params ); - return TRUE; - } -/*********************************************************************************/ -/** - * Property Name: LOCATION - */ -/** - * creates formatted output for calendar component property location - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.16.2 - 2012-12-18 - * @return string - */ - function createLocation() { - if( empty( $this->location )) return FALSE; - if( empty( $this->location['value'] )) - return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'LOCATION' ) : FALSE; - $attributes = $this->_createParams( $this->location['params'], array( 'ALTREP', 'LANGUAGE' )); - $content = iCalUtilityFunctions::_strrep( $this->location['value'], $this->format, $this->nl ); - return $this->_createElement( 'LOCATION', $attributes, $content ); - } -/** - * set calendar component property location - ' - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.4.8 - 2008-11-04 - * @param string $value - * @param array params optional - * @return bool - */ - function setLocation( $value, $params=FALSE ) { - if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE; - $this->location = array( 'value' => $value, 'params' => iCalUtilityFunctions::_setParams( $params )); - return TRUE; - } -/*********************************************************************************/ -/** - * Property Name: ORGANIZER - */ -/** - * creates formatted output for calendar component property organizer - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.6.33 - 2010-12-17 - * @return string - */ - function createOrganizer() { - if( empty( $this->organizer )) return FALSE; - if( empty( $this->organizer['value'] )) - return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'ORGANIZER' ) : FALSE; - $attributes = $this->_createParams( $this->organizer['params'] - , array( 'CN', 'DIR', 'SENT-BY', 'LANGUAGE' )); - return $this->_createElement( 'ORGANIZER', $attributes, $this->organizer['value'] ); - } -/** - * set calendar component property organizer - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.12.18 - 2012-07-13 - * @param string $value - * @param array params optional - * @return bool - */ - function setOrganizer( $value, $params=FALSE ) { - if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE; - if( !empty( $value )) { - if( FALSE === ( $pos = strpos( substr( $value, 0, 9 ), ':' ))) - $value = 'MAILTO:'.$value; - elseif( !empty( $value )) - $value = strtolower( substr( $value, 0, $pos )).substr( $value, $pos ); - $value = str_replace( 'mailto:', 'MAILTO:', $value ); - } - $this->organizer = array( 'value' => $value, 'params' => iCalUtilityFunctions::_setParams( $params )); - if( isset( $this->organizer['params']['SENT-BY'] )){ - if( 'mailto:' !== strtolower( substr( $this->organizer['params']['SENT-BY'], 0, 7 ))) - $this->organizer['params']['SENT-BY'] = 'MAILTO:'.$this->organizer['params']['SENT-BY']; - else - $this->organizer['params']['SENT-BY'] = 'MAILTO:'.substr( $this->organizer['params']['SENT-BY'], 7 ); - } - return TRUE; - } -/*********************************************************************************/ -/** - * Property Name: PERCENT-COMPLETE - */ -/** - * creates formatted output for calendar component property percent-complete - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.9.3 - 2011-05-14 - * @return string - */ - function createPercentComplete() { - if( !isset($this->percentcomplete) || ( empty( $this->percentcomplete ) && !is_numeric( $this->percentcomplete ))) return FALSE; - if( !isset( $this->percentcomplete['value'] ) || ( empty( $this->percentcomplete['value'] ) && !is_numeric( $this->percentcomplete['value'] ))) - return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'PERCENT-COMPLETE' ) : FALSE; - $attributes = $this->_createParams( $this->percentcomplete['params'] ); - return $this->_createElement( 'PERCENT-COMPLETE', $attributes, $this->percentcomplete['value'] ); - } -/** - * set calendar component property percent-complete - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.9.3 - 2011-05-14 - * @param int $value - * @param array $params optional - * @return bool - */ - function setPercentComplete( $value, $params=FALSE ) { - if( empty( $value ) && !is_numeric( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE; - $this->percentcomplete = array( 'value' => $value, 'params' => iCalUtilityFunctions::_setParams( $params )); - return TRUE; - } -/*********************************************************************************/ -/** - * Property Name: PRIORITY - */ -/** - * creates formatted output for calendar component property priority - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.9.3 - 2011-05-14 - * @return string - */ - function createPriority() { - if( !isset($this->priority) || ( empty( $this->priority ) && !is_numeric( $this->priority ))) return FALSE; - if( !isset( $this->priority['value'] ) || ( empty( $this->priority['value'] ) && !is_numeric( $this->priority['value'] ))) - return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'PRIORITY' ) : FALSE; - $attributes = $this->_createParams( $this->priority['params'] ); - return $this->_createElement( 'PRIORITY', $attributes, $this->priority['value'] ); - } -/** - * set calendar component property priority - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.9.3 - 2011-05-14 - * @param int $value - * @param array $params optional - * @return bool - */ - function setPriority( $value, $params=FALSE ) { - if( empty( $value ) && !is_numeric( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE; - $this->priority = array( 'value' => $value, 'params' => iCalUtilityFunctions::_setParams( $params )); - return TRUE; - } -/*********************************************************************************/ -/** - * Property Name: RDATE - */ -/** - * creates formatted output for calendar component property rdate - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.16.9 - 2013-01-09 - * @return string - */ - function createRdate() { - if( empty( $this->rdate )) return FALSE; - $utctime = ( in_array( $this->objName, array( 'vtimezone', 'standard', 'daylight' ))) ? TRUE : FALSE; - $output = null; - $rdates = array(); - foreach( $this->rdate as $rpix => $theRdate ) { - if( empty( $theRdate['value'] )) { - if( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'RDATE' ); - continue; - } - if( $utctime ) - unset( $theRdate['params']['TZID'] ); - if( 1 < count( $theRdate['value'] )) - usort( $theRdate['value'], array( 'iCalUtilityFunctions', '_sortRdate1' )); - $rdates[] = $theRdate; - } - if( 1 < count( $rdates )) - usort( $rdates, array( 'iCalUtilityFunctions', '_sortRdate2' )); - foreach( $rdates as $rpix => $theRdate ) { - $attributes = $this->_createParams( $theRdate['params'] ); - $cnt = count( $theRdate['value'] ); - $content = null; - $rno = 1; - foreach( $theRdate['value'] as $rix => $rdatePart ) { - $contentPart = null; - if( is_array( $rdatePart ) && - isset( $theRdate['params']['VALUE'] ) && ( 'PERIOD' == $theRdate['params']['VALUE'] )) { // PERIOD - if( $utctime ) - unset( $rdatePart[0]['tz'] ); - $formatted = iCalUtilityFunctions::_date2strdate( $rdatePart[0] ); // PERIOD part 1 - if( $utctime || !empty( $theRdate['params']['TZID'] )) - $formatted = str_replace( 'Z', '', $formatted); - $contentPart .= $formatted; - $contentPart .= '/'; - $cnt2 = count( $rdatePart[1]); - if( array_key_exists( 'year', $rdatePart[1] )) { - if( array_key_exists( 'hour', $rdatePart[1] )) - $cnt2 = 7; // date-time - else - $cnt2 = 3; // date - } - elseif( array_key_exists( 'week', $rdatePart[1] )) // duration - $cnt2 = 5; - if(( 7 == $cnt2 ) && // period= -> date-time - isset( $rdatePart[1]['year'] ) && - isset( $rdatePart[1]['month'] ) && - isset( $rdatePart[1]['day'] )) { - if( $utctime ) - unset( $rdatePart[1]['tz'] ); - $formatted = iCalUtilityFunctions::_date2strdate( $rdatePart[1] ); // PERIOD part 2 - if( $utctime || !empty( $theRdate['params']['TZID'] )) - $formatted = str_replace( 'Z', '', $formatted ); - $contentPart .= $formatted; - } - else { // period= -> dur-time - $contentPart .= iCalUtilityFunctions::_duration2str( $rdatePart[1] ); - } - } // PERIOD end - else { // SINGLE date start - if( $utctime ) - unset( $rdatePart['tz'] ); - $parno = ( isset( $theRdate['params']['VALUE'] ) && ( 'DATE' == isset( $theRdate['params']['VALUE'] ))) ? 3 : null; - $formatted = iCalUtilityFunctions::_date2strdate( $rdatePart, $parno ); - if( $utctime || !empty( $theRdate['params']['TZID'] )) - $formatted = str_replace( 'Z', '', $formatted); - $contentPart .= $formatted; - } - $content .= $contentPart; - if( $rno < $cnt ) - $content .= ','; - $rno++; - } - $output .= $this->_createElement( 'RDATE', $attributes, $content ); - } - return $output; - } -/** - * set calendar component property rdate - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.14.1 - 2012-10-04 - * @param array $rdates - * @param array $params, optional - * @param integer $index, optional - * @return bool - */ - function setRdate( $rdates, $params=FALSE, $index=FALSE ) { - if( empty( $rdates )) { - if( $this->getConfig( 'allowEmpty' )) { - iCalUtilityFunctions::_setMval( $this->rdate, null, $params, FALSE, $index ); - return TRUE; - } - else - return FALSE; - } - $input = array( 'params' => iCalUtilityFunctions::_setParams( $params, array( 'VALUE' => 'DATE-TIME' ))); - if( in_array( $this->objName, array( 'vtimezone', 'standard', 'daylight' ))) { - unset( $input['params']['TZID'] ); - $input['params']['VALUE'] = 'DATE-TIME'; - } - $zArr = array( 'GMT', 'UTC', 'Z' ); - $toZ = ( isset( $params['TZID'] ) && in_array( strtoupper( $params['TZID'] ), $zArr )) ? TRUE : FALSE; - /* check if PERIOD, if not set */ - if((!isset( $input['params']['VALUE'] ) || !in_array( $input['params']['VALUE'], array( 'DATE', 'PERIOD' ))) && - isset( $rdates[0] ) && is_array( $rdates[0] ) && ( 2 == count( $rdates[0] )) && - isset( $rdates[0][0] ) && isset( $rdates[0][1] ) && !isset( $rdates[0]['timestamp'] ) && - (( is_array( $rdates[0][0] ) && ( isset( $rdates[0][0]['timestamp'] ) || - iCalUtilityFunctions::_isArrayDate( $rdates[0][0] ))) || - ( is_string( $rdates[0][0] ) && ( 8 <= strlen( trim( $rdates[0][0] ))))) && - ( is_array( $rdates[0][1] ) || ( is_string( $rdates[0][1] ) && ( 3 <= strlen( trim( $rdates[0][1] )))))) - $input['params']['VALUE'] = 'PERIOD'; - /* check 1:st date, upd. $parno (opt) and save ev. timezone **/ - $date = reset( $rdates ); - if( isset( $input['params']['VALUE'] ) && ( 'PERIOD' == $input['params']['VALUE'] )) // PERIOD - $date = reset( $date ); - iCalUtilityFunctions::_chkdatecfg( $date, $parno, $input['params'] ); - iCalUtilityFunctions::_existRem( $input['params'], 'VALUE', 'DATE-TIME' ); // remove default - foreach( $rdates as $rpix => $theRdate ) { - $inputa = null; - iCalUtilityFunctions::_strDate2arr( $theRdate ); - if( is_array( $theRdate )) { - if( isset( $input['params']['VALUE'] ) && ( 'PERIOD' == $input['params']['VALUE'] )) { // PERIOD - foreach( $theRdate as $rix => $rPeriod ) { - iCalUtilityFunctions::_strDate2arr( $theRdate ); - if( is_array( $rPeriod )) { - if( iCalUtilityFunctions::_isArrayTimestampDate( $rPeriod )) { // timestamp - if( isset( $rPeriod['tz'] ) && !iCalUtilityFunctions::_isOffset( $rPeriod['tz'] )) { - if( isset( $input['params']['TZID'] )) - $rPeriod['tz'] = $input['params']['TZID']; - else - $input['params']['TZID'] = $rPeriod['tz']; - } - $inputab = iCalUtilityFunctions::_timestamp2date( $rPeriod, $parno ); - } - elseif( iCalUtilityFunctions::_isArrayDate( $rPeriod )) { - $d = ( 3 < count ( $rPeriod )) ? iCalUtilityFunctions::_chkDateArr( $rPeriod, $parno ) : iCalUtilityFunctions::_chkDateArr( $rPeriod, 6 ); - if( isset( $d['tz'] ) && ( 'Z' != $d['tz'] ) && iCalUtilityFunctions::_isOffset( $d['tz'] )) { - $strdate = sprintf( '%04d-%02d-%02d %02d:%02d:%02d %s', $d['year'], $d['month'], $d['day'], $d['hour'], $d['min'], $d['sec'], $d['tz'] ); - $inputab = iCalUtilityFunctions::_strdate2date( $strdate, 7 ); - unset( $inputab['unparsedtext'] ); - } - else - $inputab = $d; - } - elseif (( 1 == count( $rPeriod )) && ( 8 <= strlen( reset( $rPeriod )))) { // text-date - $inputab = iCalUtilityFunctions::_strdate2date( reset( $rPeriod ), $parno ); - unset( $inputab['unparsedtext'] ); - } - else // array format duration - $inputab = iCalUtilityFunctions::_duration2arr( $rPeriod ); - } - elseif(( 3 <= strlen( trim( $rPeriod ))) && // string format duration - ( in_array( $rPeriod[0], array( 'P', '+', '-' )))) { - if( 'P' != $rPeriod[0] ) - $rPeriod = substr( $rPeriod, 1 ); - $inputab = iCalUtilityFunctions::_durationStr2arr( $rPeriod ); - } - elseif( 8 <= strlen( trim( $rPeriod ))) { // text date ex. 2006-08-03 10:12:18 - $inputab = iCalUtilityFunctions::_strdate2date( $rPeriod, $parno ); - unset( $inputab['unparsedtext'] ); - } - if(( 0 == $rpix ) && ( 0 == $rix )) { - if( isset( $inputab['tz'] ) && in_array( strtoupper( $inputab['tz'] ), $zArr )) { - $inputab['tz'] = 'Z'; - $toZ = TRUE; - } - } - else { - if( isset( $inputa[0]['tz'] ) && ( 'Z' == $inputa[0]['tz'] ) && isset( $inputab['year'] )) - $inputab['tz'] = 'Z'; - else - unset( $inputab['tz'] ); - } - if( $toZ && isset( $inputab['year'] ) ) - $inputab['tz'] = 'Z'; - $inputa[] = $inputab; - } - } // PERIOD end - elseif ( iCalUtilityFunctions::_isArrayTimestampDate( $theRdate )) { // timestamp - if( isset( $theRdate['tz'] ) && !iCalUtilityFunctions::_isOffset( $theRdate['tz'] )) { - if( isset( $input['params']['TZID'] )) - $theRdate['tz'] = $input['params']['TZID']; - else - $input['params']['TZID'] = $theRdate['tz']; - } - $inputa = iCalUtilityFunctions::_timestamp2date( $theRdate, $parno ); - } - else { // date[-time] - $inputa = iCalUtilityFunctions::_chkDateArr( $theRdate, $parno ); - if( isset( $inputa['tz'] ) && ( 'Z' != $inputa['tz'] ) && iCalUtilityFunctions::_isOffset( $inputa['tz'] )) { - $strdate = sprintf( '%04d-%02d-%02d %02d:%02d:%02d %s', $inputa['year'], $inputa['month'], $inputa['day'], $inputa['hour'], $inputa['min'], $inputa['sec'], $inputa['tz'] ); - $inputa = iCalUtilityFunctions::_strdate2date( $strdate, 7 ); - unset( $inputa['unparsedtext'] ); - } - } - } - elseif( 8 <= strlen( trim( $theRdate ))) { // text date ex. 2006-08-03 10:12:18 - $inputa = iCalUtilityFunctions::_strdate2date( $theRdate, $parno ); - unset( $inputa['unparsedtext'] ); - if( $toZ ) - $inputa['tz'] = 'Z'; - } - if( !isset( $input['params']['VALUE'] ) || ( 'PERIOD' != $input['params']['VALUE'] )) { // no PERIOD - if(( 0 == $rpix ) && !$toZ ) - $toZ = ( isset( $inputa['tz'] ) && in_array( strtoupper( $inputa['tz'] ), $zArr )) ? TRUE : FALSE; - if( $toZ ) - $inputa['tz'] = 'Z'; - if( 3 == $parno ) - unset( $inputa['hour'], $inputa['min'], $inputa['sec'], $inputa['tz'] ); - elseif( isset( $inputa['tz'] )) - $inputa['tz'] = (string) $inputa['tz']; - if( isset( $input['params']['TZID'] ) || ( isset( $input['value'][0] ) && ( !isset( $input['value'][0]['tz'] )))) - if( !$toZ ) - unset( $inputa['tz'] ); - } - $input['value'][] = $inputa; - } - if( 3 == $parno ) { - $input['params']['VALUE'] = 'DATE'; - unset( $input['params']['TZID'] ); - } - if( $toZ ) - unset( $input['params']['TZID'] ); - iCalUtilityFunctions::_setMval( $this->rdate, $input['value'], $input['params'], FALSE, $index ); - return TRUE; - } -/*********************************************************************************/ -/** - * Property Name: RECURRENCE-ID - */ -/** - * creates formatted output for calendar component property recurrence-id - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.14.4 - 2012-09-26 - * @return string - */ - function createRecurrenceid() { - if( empty( $this->recurrenceid )) return FALSE; - if( empty( $this->recurrenceid['value'] )) - return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'RECURRENCE-ID' ) : FALSE; - $parno = ( isset( $this->recurrenceid['params']['VALUE'] ) && ( 'DATE' == $this->recurrenceid['params']['VALUE'] )) ? 3 : null; - $formatted = iCalUtilityFunctions::_date2strdate( $this->recurrenceid['value'], $parno ); - $attributes = $this->_createParams( $this->recurrenceid['params'] ); - return $this->_createElement( 'RECURRENCE-ID', $attributes, $formatted ); - } -/** - * set calendar component property recurrence-id - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.9.6 - 2011-05-15 - * @param mixed $year - * @param mixed $month optional - * @param int $day optional - * @param int $hour optional - * @param int $min optional - * @param int $sec optional - * @param array $params optional - * @return bool - */ - function setRecurrenceid( $year, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $tz=FALSE, $params=FALSE ) { - if( empty( $year )) { - if( $this->getConfig( 'allowEmpty' )) { - $this->recurrenceid = array( 'value' => null, 'params' => null ); - return TRUE; - } - else - return FALSE; - } - $this->recurrenceid = iCalUtilityFunctions::_setDate( $year, $month, $day, $hour, $min, $sec, $tz, $params, null, null, $this->getConfig( 'TZID' )); - return TRUE; - } -/*********************************************************************************/ -/** - * Property Name: RELATED-TO - */ -/** - * creates formatted output for calendar component property related-to - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.16.2 - 2012-12-18 - * @return string - */ - function createRelatedTo() { - if( empty( $this->relatedto )) return FALSE; - $output = null; - foreach( $this->relatedto as $relation ) { - if( !empty( $relation['value'] )) - $output .= $this->_createElement( 'RELATED-TO', $this->_createParams( $relation['params'] ), iCalUtilityFunctions::_strrep( $relation['value'], $this->format, $this->nl )); - elseif( $this->getConfig( 'allowEmpty' )) - $output .= $this->_createElement( 'RELATED-TO', $this->_createParams( $relation['params'] )); - } - return $output; - } -/** - * set calendar component property related-to - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.11.24 - 2012-02-23 - * @param float $relid - * @param array $params, optional - * @param index $index, optional - * @return bool - */ - function setRelatedTo( $value, $params=FALSE, $index=FALSE ) { - if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE; - iCalUtilityFunctions::_existRem( $params, 'RELTYPE', 'PARENT', TRUE ); // remove default - iCalUtilityFunctions::_setMval( $this->relatedto, $value, $params, FALSE, $index ); - return TRUE; - } -/*********************************************************************************/ -/** - * Property Name: REPEAT - */ -/** - * creates formatted output for calendar component property repeat - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.9.3 - 2011-05-14 - * @return string - */ - function createRepeat() { - if( !isset( $this->repeat ) || ( empty( $this->repeat ) && !is_numeric( $this->repeat ))) return FALSE; - if( !isset( $this->repeat['value']) || ( empty( $this->repeat['value'] ) && !is_numeric( $this->repeat['value'] ))) - return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'REPEAT' ) : FALSE; - $attributes = $this->_createParams( $this->repeat['params'] ); - return $this->_createElement( 'REPEAT', $attributes, $this->repeat['value'] ); - } -/** - * set calendar component property repeat - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.9.3 - 2011-05-14 - * @param string $value - * @param array $params optional - * @return void - */ - function setRepeat( $value, $params=FALSE ) { - if( empty( $value ) && !is_numeric( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE; - $this->repeat = array( 'value' => $value, 'params' => iCalUtilityFunctions::_setParams( $params )); - return TRUE; - } -/*********************************************************************************/ -/** - * Property Name: REQUEST-STATUS - */ -/** - * creates formatted output for calendar component property request-status - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.16.2 - 2012-12-18 - * @return string - */ - function createRequestStatus() { - if( empty( $this->requeststatus )) return FALSE; - $output = null; - foreach( $this->requeststatus as $rstat ) { - if( empty( $rstat['value']['statcode'] )) { - if( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'REQUEST-STATUS' ); - continue; - } - $attributes = $this->_createParams( $rstat['params'], array( 'LANGUAGE' )); - $content = number_format( (float) $rstat['value']['statcode'], 2, '.', ''); - $content .= ';'.iCalUtilityFunctions::_strrep( $rstat['value']['text'], $this->format, $this->nl ); - if( isset( $rstat['value']['extdata'] )) - $content .= ';'.iCalUtilityFunctions::_strrep( $rstat['value']['extdata'], $this->format, $this->nl ); - $output .= $this->_createElement( 'REQUEST-STATUS', $attributes, $content ); - } - return $output; - } -/** - * set calendar component property request-status - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.5.1 - 2008-11-05 - * @param float $statcode - * @param string $text - * @param string $extdata, optional - * @param array $params, optional - * @param integer $index, optional - * @return bool - */ - function setRequestStatus( $statcode, $text, $extdata=FALSE, $params=FALSE, $index=FALSE ) { - if( empty( $statcode ) || empty( $text )) if( $this->getConfig( 'allowEmpty' )) $statcode = $text = null; else return FALSE; - $input = array( 'statcode' => $statcode, 'text' => $text ); - if( $extdata ) - $input['extdata'] = $extdata; - iCalUtilityFunctions::_setMval( $this->requeststatus, $input, $params, FALSE, $index ); - return TRUE; - } -/*********************************************************************************/ -/** - * Property Name: RESOURCES - */ -/** - * creates formatted output for calendar component property resources - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.16.2 - 2012-12-18 - * @return string - */ - function createResources() { - if( empty( $this->resources )) return FALSE; - $output = null; - foreach( $this->resources as $resource ) { - if( empty( $resource['value'] )) { - if( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'RESOURCES' ); - continue; - } - $attributes = $this->_createParams( $resource['params'], array( 'ALTREP', 'LANGUAGE' )); - if( is_array( $resource['value'] )) { - foreach( $resource['value'] as $rix => $resourcePart ) - $resource['value'][$rix] = iCalUtilityFunctions::_strrep( $resourcePart, $this->format, $this->nl ); - $content = implode( ',', $resource['value'] ); - } - else - $content = iCalUtilityFunctions::_strrep( $resource['value'], $this->format, $this->nl ); - $output .= $this->_createElement( 'RESOURCES', $attributes, $content ); - } - return $output; - } -/** - * set calendar component property recources - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.5.1 - 2008-11-05 - * @param mixed $value - * @param array $params, optional - * @param integer $index, optional - * @return bool - */ - function setResources( $value, $params=FALSE, $index=FALSE ) { - if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE; - iCalUtilityFunctions::_setMval( $this->resources, $value, $params, FALSE, $index ); - return TRUE; - } -/*********************************************************************************/ -/** - * Property Name: RRULE - */ -/** - * creates formatted output for calendar component property rrule - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.4.8 - 2008-10-21 - * @return string - */ - function createRrule() { - if( empty( $this->rrule )) return FALSE; - return $this->_format_recur( 'RRULE', $this->rrule ); - } -/** - * set calendar component property rrule - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.5.1 - 2008-11-05 - * @param array $rruleset - * @param array $params, optional - * @param integer $index, optional - * @return void - */ - function setRrule( $rruleset, $params=FALSE, $index=FALSE ) { - if( empty( $rruleset )) if( $this->getConfig( 'allowEmpty' )) $rruleset = null; else return FALSE; - iCalUtilityFunctions::_setMval( $this->rrule, iCalUtilityFunctions::_setRexrule( $rruleset ), $params, FALSE, $index ); - return TRUE; - } -/*********************************************************************************/ -/** - * Property Name: SEQUENCE - */ -/** - * creates formatted output for calendar component property sequence - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.9.3 - 2011-05-14 - * @return string - */ - function createSequence() { - if( !isset( $this->sequence ) || ( empty( $this->sequence ) && !is_numeric( $this->sequence ))) return FALSE; - if(( !isset($this->sequence['value'] ) || ( empty( $this->sequence['value'] ) && !is_numeric( $this->sequence['value'] ))) && - ( '0' != $this->sequence['value'] )) - return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'SEQUENCE' ) : FALSE; - $attributes = $this->_createParams( $this->sequence['params'] ); - return $this->_createElement( 'SEQUENCE', $attributes, $this->sequence['value'] ); - } -/** - * set calendar component property sequence - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.10.8 - 2011-09-19 - * @param int $value optional - * @param array $params optional - * @return bool - */ - function setSequence( $value=FALSE, $params=FALSE ) { - if(( empty( $value ) && !is_numeric( $value )) && ( '0' != $value )) - $value = ( isset( $this->sequence['value'] ) && ( -1 < $this->sequence['value'] )) ? $this->sequence['value'] + 1 : '0'; - $this->sequence = array( 'value' => $value, 'params' => iCalUtilityFunctions::_setParams( $params )); - return TRUE; - } -/*********************************************************************************/ -/** - * Property Name: STATUS - */ -/** - * creates formatted output for calendar component property status - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.4.8 - 2008-10-21 - * @return string - */ - function createStatus() { - if( empty( $this->status )) return FALSE; - if( empty( $this->status['value'] )) - return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'STATUS' ) : FALSE; - $attributes = $this->_createParams( $this->status['params'] ); - return $this->_createElement( 'STATUS', $attributes, $this->status['value'] ); - } -/** - * set calendar component property status - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.4.8 - 2008-11-04 - * @param string $value - * @param array $params optional - * @return bool - */ - function setStatus( $value, $params=FALSE ) { - if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE; - $this->status = array( 'value' => $value, 'params' => iCalUtilityFunctions::_setParams( $params )); - return TRUE; - } -/*********************************************************************************/ -/** - * Property Name: SUMMARY - */ -/** - * creates formatted output for calendar component property summary - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.16.2 - 2012-12-18 - * @return string - */ - function createSummary() { - if( empty( $this->summary )) return FALSE; - if( empty( $this->summary['value'] )) - return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'SUMMARY' ) : FALSE; - $attributes = $this->_createParams( $this->summary['params'], array( 'ALTREP', 'LANGUAGE' )); - $content = iCalUtilityFunctions::_strrep( $this->summary['value'], $this->format, $this->nl ); - return $this->_createElement( 'SUMMARY', $attributes, $content ); - } -/** - * set calendar component property summary - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.4.8 - 2008-11-04 - * @param string $value - * @param string $params optional - * @return bool - */ - function setSummary( $value, $params=FALSE ) { - if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE; - $this->summary = array( 'value' => $value, 'params' => iCalUtilityFunctions::_setParams( $params )); - return TRUE; - } -/*********************************************************************************/ -/** - * Property Name: TRANSP - */ -/** - * creates formatted output for calendar component property transp - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.4.8 - 2008-10-21 - * @return string - */ - function createTransp() { - if( empty( $this->transp )) return FALSE; - if( empty( $this->transp['value'] )) - return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'TRANSP' ) : FALSE; - $attributes = $this->_createParams( $this->transp['params'] ); - return $this->_createElement( 'TRANSP', $attributes, $this->transp['value'] ); - } -/** - * set calendar component property transp - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.4.8 - 2008-11-04 - * @param string $value - * @param string $params optional - * @return bool - */ - function setTransp( $value, $params=FALSE ) { - if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE; - $this->transp = array( 'value' => $value, 'params' => iCalUtilityFunctions::_setParams( $params )); - return TRUE; - } -/*********************************************************************************/ -/** - * Property Name: TRIGGER - */ -/** - * creates formatted output for calendar component property trigger - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.4.16 - 2008-10-21 - * @return string - */ - function createTrigger() { - if( empty( $this->trigger )) return FALSE; - if( empty( $this->trigger['value'] )) - return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'TRIGGER' ) : FALSE; - $content = $attributes = null; - if( isset( $this->trigger['value']['year'] ) && - isset( $this->trigger['value']['month'] ) && - isset( $this->trigger['value']['day'] )) - $content .= iCalUtilityFunctions::_date2strdate( $this->trigger['value'] ); - else { - if( TRUE !== $this->trigger['value']['relatedStart'] ) - $attributes .= $this->intAttrDelimiter.'RELATED=END'; - if( $this->trigger['value']['before'] ) - $content .= '-'; - $content .= iCalUtilityFunctions::_duration2str( $this->trigger['value'] ); - } - $attributes .= $this->_createParams( $this->trigger['params'] ); - return $this->_createElement( 'TRIGGER', $attributes, $content ); - } -/** - * set calendar component property trigger - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.14.1 - 2012-09-20 - * @param mixed $year - * @param mixed $month optional - * @param int $day optional - * @param int $week optional - * @param int $hour optional - * @param int $min optional - * @param int $sec optional - * @param bool $relatedStart optional - * @param bool $before optional - * @param array $params optional - * @return bool - */ - function setTrigger( $year, $month=null, $day=null, $week=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $relatedStart=TRUE, $before=TRUE, $params=FALSE ) { - if( empty( $year ) && empty( $month ) && empty( $day ) && empty( $week ) && empty( $hour ) && empty( $min ) && empty( $sec )) - if( $this->getConfig( 'allowEmpty' )) { - $this->trigger = array( 'value' => null, 'params' => iCalUtilityFunctions::_setParams( $params ) ); - return TRUE; - } - else - return FALSE; - if( iCalUtilityFunctions::_isArrayTimestampDate( $year )) { // timestamp UTC - $params = iCalUtilityFunctions::_setParams( $month ); - $date = iCalUtilityFunctions::_timestamp2date( $year, 7 ); - foreach( $date as $k => $v ) - $$k = $v; - } - elseif( is_array( $year ) && ( is_array( $month ) || empty( $month ))) { - $params = iCalUtilityFunctions::_setParams( $month ); - if(!(array_key_exists( 'year', $year ) && // exclude date-time - array_key_exists( 'month', $year ) && - array_key_exists( 'day', $year ))) { // when this must be a duration - if( isset( $params['RELATED'] ) && ( 'END' == strtoupper( $params['RELATED'] ))) - $relatedStart = FALSE; - else - $relatedStart = ( array_key_exists( 'relatedStart', $year ) && ( TRUE !== $year['relatedStart'] )) ? FALSE : TRUE; - $before = ( array_key_exists( 'before', $year ) && ( TRUE !== $year['before'] )) ? FALSE : TRUE; - } - $SSYY = ( array_key_exists( 'year', $year )) ? $year['year'] : null; - $month = ( array_key_exists( 'month', $year )) ? $year['month'] : null; - $day = ( array_key_exists( 'day', $year )) ? $year['day'] : null; - $week = ( array_key_exists( 'week', $year )) ? $year['week'] : null; - $hour = ( array_key_exists( 'hour', $year )) ? $year['hour'] : 0; //null; - $min = ( array_key_exists( 'min', $year )) ? $year['min'] : 0; //null; - $sec = ( array_key_exists( 'sec', $year )) ? $year['sec'] : 0; //null; - $year = $SSYY; - } - elseif(is_string( $year ) && ( is_array( $month ) || empty( $month ))) { // duration or date in a string - $params = iCalUtilityFunctions::_setParams( $month ); - if( in_array( $year[0], array( 'P', '+', '-' ))) { // duration - $relatedStart = ( isset( $params['RELATED'] ) && ( 'END' == strtoupper( $params['RELATED'] ))) ? FALSE : TRUE; - $before = ( '-' == $year[0] ) ? TRUE : FALSE; - if( 'P' != $year[0] ) - $year = substr( $year, 1 ); - $date = iCalUtilityFunctions::_durationStr2arr( $year); - } - else // date - $date = iCalUtilityFunctions::_strdate2date( $year, 7 ); - unset( $year, $month, $day, $date['unparsedtext'] ); - if( empty( $date )) - $sec = 0; - else - foreach( $date as $k => $v ) - $$k = $v; - } - else // single values in function input parameters - $params = iCalUtilityFunctions::_setParams( $params ); - if( !empty( $year ) && !empty( $month ) && !empty( $day )) { // date - $params['VALUE'] = 'DATE-TIME'; - $hour = ( $hour ) ? $hour : 0; - $min = ( $min ) ? $min : 0; - $sec = ( $sec ) ? $sec : 0; - $this->trigger = array( 'params' => $params ); - $this->trigger['value'] = array( 'year' => $year - , 'month' => $month - , 'day' => $day - , 'hour' => $hour - , 'min' => $min - , 'sec' => $sec - , 'tz' => 'Z' ); - return TRUE; - } - elseif(( empty( $year ) && empty( $month )) && // duration - (( !empty( $week ) || ( 0 == $week )) || - ( !empty( $day ) || ( 0 == $day )) || - ( !empty( $hour ) || ( 0 == $hour )) || - ( !empty( $min ) || ( 0 == $min )) || - ( !empty( $sec ) || ( 0 == $sec )))) { - unset( $params['RELATED'] ); // set at output creation (END only) - unset( $params['VALUE'] ); // 'DURATION' default - $this->trigger = array( 'params' => $params ); - $this->trigger['value'] = array(); - if( !empty( $week )) $this->trigger['value']['week'] = $week; - if( !empty( $day )) $this->trigger['value']['day'] = $day; - if( !empty( $hour )) $this->trigger['value']['hour'] = $hour; - if( !empty( $min )) $this->trigger['value']['min'] = $min; - if( !empty( $sec )) $this->trigger['value']['sec'] = $sec; - if( empty( $this->trigger['value'] )) { - $this->trigger['value']['sec'] = 0; - $before = FALSE; - } - $relatedStart = ( FALSE !== $relatedStart ) ? TRUE : FALSE; - $before = ( FALSE !== $before ) ? TRUE : FALSE; - $this->trigger['value']['relatedStart'] = $relatedStart; - $this->trigger['value']['before'] = $before; - return TRUE; - } - return FALSE; - } -/*********************************************************************************/ -/** - * Property Name: TZID - */ -/** - * creates formatted output for calendar component property tzid - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.16.2 - 2012-12-18 - * @return string - */ - function createTzid() { - if( empty( $this->tzid )) return FALSE; - if( empty( $this->tzid['value'] )) - return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'TZID' ) : FALSE; - $attributes = $this->_createParams( $this->tzid['params'] ); - return $this->_createElement( 'TZID', $attributes, iCalUtilityFunctions::_strrep( $this->tzid['value'], $this->format, $this->nl )); - } -/** - * set calendar component property tzid - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.4.8 - 2008-11-04 - * @param string $value - * @param array $params optional - * @return bool - */ - function setTzid( $value, $params=FALSE ) { - if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE; - $this->tzid = array( 'value' => $value, 'params' => iCalUtilityFunctions::_setParams( $params )); - return TRUE; - } -/*********************************************************************************/ -/** - * .. . - * Property Name: TZNAME - */ -/** - * creates formatted output for calendar component property tzname - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.16.2 - 2012-12-18 - * @return string - */ - function createTzname() { - if( empty( $this->tzname )) return FALSE; - $output = null; - foreach( $this->tzname as $theName ) { - if( !empty( $theName['value'] )) { - $attributes = $this->_createParams( $theName['params'], array( 'LANGUAGE' )); - $output .= $this->_createElement( 'TZNAME', $attributes, iCalUtilityFunctions::_strrep( $theName['value'], $this->format, $this->nl )); - } - elseif( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'TZNAME' ); - } - return $output; - } -/** - * set calendar component property tzname - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.5.1 - 2008-11-05 - * @param string $value - * @param string $params, optional - * @param integer $index, optional - * @return bool - */ - function setTzname( $value, $params=FALSE, $index=FALSE ) { - if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE; - iCalUtilityFunctions::_setMval( $this->tzname, $value, $params, FALSE, $index ); - return TRUE; - } -/*********************************************************************************/ -/** - * Property Name: TZOFFSETFROM - */ -/** - * creates formatted output for calendar component property tzoffsetfrom - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.4.8 - 2008-10-21 - * @return string - */ - function createTzoffsetfrom() { - if( empty( $this->tzoffsetfrom )) return FALSE; - if( empty( $this->tzoffsetfrom['value'] )) - return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'TZOFFSETFROM' ) : FALSE; - $attributes = $this->_createParams( $this->tzoffsetfrom['params'] ); - return $this->_createElement( 'TZOFFSETFROM', $attributes, $this->tzoffsetfrom['value'] ); - } -/** - * set calendar component property tzoffsetfrom - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.4.8 - 2008-11-04 - * @param string $value - * @param string $params optional - * @return bool - */ - function setTzoffsetfrom( $value, $params=FALSE ) { - if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE; - $this->tzoffsetfrom = array( 'value' => $value, 'params' => iCalUtilityFunctions::_setParams( $params )); - return TRUE; - } -/*********************************************************************************/ -/** - * Property Name: TZOFFSETTO - */ -/** - * creates formatted output for calendar component property tzoffsetto - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.4.8 - 2008-10-21 - * @return string - */ - function createTzoffsetto() { - if( empty( $this->tzoffsetto )) return FALSE; - if( empty( $this->tzoffsetto['value'] )) - return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'TZOFFSETTO' ) : FALSE; - $attributes = $this->_createParams( $this->tzoffsetto['params'] ); - return $this->_createElement( 'TZOFFSETTO', $attributes, $this->tzoffsetto['value'] ); - } -/** - * set calendar component property tzoffsetto - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.4.8 - 2008-11-04 - * @param string $value - * @param string $params optional - * @return bool - */ - function setTzoffsetto( $value, $params=FALSE ) { - if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE; - $this->tzoffsetto = array( 'value' => $value, 'params' => iCalUtilityFunctions::_setParams( $params )); - return TRUE; - } -/*********************************************************************************/ -/** - * Property Name: TZURL - */ -/** - * creates formatted output for calendar component property tzurl - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.4.8 - 2008-10-21 - * @return string - */ - function createTzurl() { - if( empty( $this->tzurl )) return FALSE; - if( empty( $this->tzurl['value'] )) - return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'TZURL' ) : FALSE; - $attributes = $this->_createParams( $this->tzurl['params'] ); - return $this->_createElement( 'TZURL', $attributes, $this->tzurl['value'] ); - } -/** - * set calendar component property tzurl - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.4.8 - 2008-11-04 - * @param string $value - * @param string $params optional - * @return boll - */ - function setTzurl( $value, $params=FALSE ) { - if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE; - $this->tzurl = array( 'value' => $value, 'params' => iCalUtilityFunctions::_setParams( $params )); - return TRUE; - } -/*********************************************************************************/ -/** - * Property Name: UID - */ -/** - * creates formatted output for calendar component property uid - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 0.9.7 - 2006-11-20 - * @return string - */ - function createUid() { - if( 0 >= count( $this->uid )) - $this->_makeuid(); - $attributes = $this->_createParams( $this->uid['params'] ); - return $this->_createElement( 'UID', $attributes, $this->uid['value'] ); - } -/** - * create an unique id for this calendar component object instance - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.2.7 - 2007-09-04 - * @return void - */ - function _makeUid() { - $date = date('Ymd\THisT'); - $unique = substr(microtime(), 2, 4); - $base = 'aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPrRsStTuUvVxXuUvVwWzZ1234567890'; - $start = 0; - $end = strlen( $base ) - 1; - $length = 6; - $str = null; - for( $p = 0; $p < $length; $p++ ) - $unique .= $base{mt_rand( $start, $end )}; - $this->uid = array( 'params' => null ); - $this->uid['value'] = $date.'-'.$unique.'@'.$this->getConfig( 'unique_id' ); - } -/** - * set calendar component property uid - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.4.8 - 2008-11-04 - * @param string $value - * @param string $params optional - * @return bool - */ - function setUid( $value, $params=FALSE ) { - if( empty( $value )) return FALSE; // no allowEmpty check here !!!! - $this->uid = array( 'value' => $value, 'params' => iCalUtilityFunctions::_setParams( $params )); - return TRUE; - } -/*********************************************************************************/ -/** - * Property Name: URL - */ -/** - * creates formatted output for calendar component property url - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.4.8 - 2008-10-21 - * @return string - */ - function createUrl() { - if( empty( $this->url )) return FALSE; - if( empty( $this->url['value'] )) - return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'URL' ) : FALSE; - $attributes = $this->_createParams( $this->url['params'] ); - return $this->_createElement( 'URL', $attributes, $this->url['value'] ); - } -/** - * set calendar component property url - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.16.7 - 2013-01-11 - * @param string $value - * @param string $params optional - * @return bool - */ - function setUrl( $value, $params=FALSE ) { - if( !empty( $value )) { - if( !filter_var( $value, FILTER_VALIDATE_URL ) && ( 'urn' != strtolower( substr( $value, 0, 3 )))) - return FALSE; - } - elseif( $this->getConfig( 'allowEmpty' )) - $value = null; - else - return FALSE; - $this->url = array( 'value' => $value, 'params' => iCalUtilityFunctions::_setParams( $params )); - return TRUE; - } -/*********************************************************************************/ -/** - * Property Name: x-prop - */ -/** - * creates formatted output for calendar component property x-prop - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.16.2 - 2012-12-18 - * @return string - */ - function createXprop() { - if( empty( $this->xprop )) return FALSE; - $output = null; - foreach( $this->xprop as $label => $xpropPart ) { - if( !isset($xpropPart['value']) || ( empty( $xpropPart['value'] ) && !is_numeric( $xpropPart['value'] ))) { - if( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( $label ); - continue; - } - $attributes = $this->_createParams( $xpropPart['params'], array( 'LANGUAGE' )); - if( is_array( $xpropPart['value'] )) { - foreach( $xpropPart['value'] as $pix => $theXpart ) - $xpropPart['value'][$pix] = iCalUtilityFunctions::_strrep( $theXpart, $this->format, $this->format ); - $xpropPart['value'] = implode( ',', $xpropPart['value'] ); - } - else - $xpropPart['value'] = iCalUtilityFunctions::_strrep( $xpropPart['value'], $this->format, $this->nl ); - $output .= $this->_createElement( $label, $attributes, $xpropPart['value'] ); - } - return $output; - } -/** - * set calendar component property x-prop - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.11.9 - 2012-01-16 - * @param string $label - * @param mixed $value - * @param array $params optional - * @return bool - */ - function setXprop( $label, $value, $params=FALSE ) { - if( empty( $label )) - return FALSE; - if( 'X-' != strtoupper( substr( $label, 0, 2 ))) - return FALSE; - if( empty( $value ) && !is_numeric( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE; - $xprop = array( 'value' => $value ); - $xprop['params'] = iCalUtilityFunctions::_setParams( $params ); - if( !is_array( $this->xprop )) $this->xprop = array(); - $this->xprop[strtoupper( $label )] = $xprop; - return TRUE; - } -/*********************************************************************************/ -/*********************************************************************************/ -/** - * create element format parts - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.0.6 - 2006-06-20 - * @return string - */ - function _createFormat() { - $objectname = null; - switch( $this->format ) { - case 'xcal': - $objectname = ( isset( $this->timezonetype )) ? - strtolower( $this->timezonetype ) : strtolower( $this->objName ); - $this->componentStart1 = $this->elementStart1 = '<'; - $this->componentStart2 = $this->elementStart2 = '>'; - $this->componentEnd1 = $this->elementEnd1 = 'componentEnd2 = $this->elementEnd2 = '>'.$this->nl; - $this->intAttrDelimiter = ''; - $this->attributeDelimiter = $this->nl; - $this->valueInit = null; - break; - default: - $objectname = ( isset( $this->timezonetype )) ? - strtoupper( $this->timezonetype ) : strtoupper( $this->objName ); - $this->componentStart1 = 'BEGIN:'; - $this->componentStart2 = null; - $this->componentEnd1 = 'END:'; - $this->componentEnd2 = $this->nl; - $this->elementStart1 = null; - $this->elementStart2 = null; - $this->elementEnd1 = null; - $this->elementEnd2 = $this->nl; - $this->intAttrDelimiter = ''; - $this->attributeDelimiter = ';'; - $this->valueInit = ':'; - break; - } - return $objectname; - } -/** - * creates formatted output for calendar component property - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.16.2 - 2012-12-18 - * @param string $label property name - * @param string $attributes property attributes - * @param string $content property content (optional) - * @return string - */ - function _createElement( $label, $attributes=null, $content=FALSE ) { - switch( $this->format ) { - case 'xcal': - $label = strtolower( $label ); - break; - default: - $label = strtoupper( $label ); - break; - } - $output = $this->elementStart1.$label; - $categoriesAttrLang = null; - $attachInlineBinary = FALSE; - $attachfmttype = null; - if (( 'xcal' == $this->format) && ( 'x-' == substr( $label, 0, 2 ))) { - $this->xcaldecl[] = array( 'xmldecl' => 'ELEMENT' - , 'ref' => $label - , 'type2' => '(#PCDATA)' ); - } - if( !empty( $attributes )) { - $attributes = trim( $attributes ); - if ( 'xcal' == $this->format ) { - $attributes2 = explode( $this->intAttrDelimiter, $attributes ); - $attributes = null; - foreach( $attributes2 as $aix => $attribute ) { - $attrKVarr = explode( '=', $attribute ); - if( empty( $attrKVarr[0] )) - continue; - if( !isset( $attrKVarr[1] )) { - $attrValue = $attrKVarr[0]; - $attrKey = $aix; - } - elseif( 2 == count( $attrKVarr)) { - $attrKey = strtolower( $attrKVarr[0] ); - $attrValue = $attrKVarr[1]; - } - else { - $attrKey = strtolower( $attrKVarr[0] ); - unset( $attrKVarr[0] ); - $attrValue = implode( '=', $attrKVarr ); - } - if(( 'attach' == $label ) && ( in_array( $attrKey, array( 'fmttype', 'encoding', 'value' )))) { - $attachInlineBinary = TRUE; - if( 'fmttype' == $attrKey ) - $attachfmttype = $attrKey.'='.$attrValue; - continue; - } - elseif(( 'categories' == $label ) && ( 'language' == $attrKey )) - $categoriesAttrLang = $attrKey.'='.$attrValue; - else { - $attributes .= ( empty( $attributes )) ? ' ' : $this->attributeDelimiter.' '; - $attributes .= ( !empty( $attrKey )) ? $attrKey.'=' : null; - if(( '"' == substr( $attrValue, 0, 1 )) && ( '"' == substr( $attrValue, -1 ))) { - $attrValue = substr( $attrValue, 1, ( strlen( $attrValue ) - 2 )); - $attrValue = str_replace( '"', '', $attrValue ); - } - $attributes .= '"'.htmlspecialchars( $attrValue ).'"'; - } - } - } - else { - $attributes = str_replace( $this->intAttrDelimiter, $this->attributeDelimiter, $attributes ); - } - } - if(( 'xcal' == $this->format) && - ((( 'attach' == $label ) && !$attachInlineBinary ) || ( in_array( $label, array( 'tzurl', 'url' ))))) { - $pos = strrpos($content, "/"); - $docname = ( $pos !== false) ? substr( $content, (1 - strlen( $content ) + $pos )) : $content; - $this->xcaldecl[] = array( 'xmldecl' => 'ENTITY' - , 'uri' => $docname - , 'ref' => 'SYSTEM' - , 'external' => $content - , 'type' => 'NDATA' - , 'type2' => 'BINERY' ); - $attributes .= ( empty( $attributes )) ? ' ' : $this->attributeDelimiter.' '; - $attributes .= 'uri="'.$docname.'"'; - $content = null; - if( 'attach' == $label ) { - $attributes = str_replace( $this->attributeDelimiter, $this->intAttrDelimiter, $attributes ); - $content = $this->nl.$this->_createElement( 'extref', $attributes, null ); - $attributes = null; - } - } - elseif(( 'xcal' == $this->format) && ( 'attach' == $label ) && $attachInlineBinary ) { - $content = $this->nl.$this->_createElement( 'b64bin', $attachfmttype, $content ); // max one attribute - } - $output .= $attributes; - if( !$content && ( '0' != $content )) { - switch( $this->format ) { - case 'xcal': - $output .= ' /'; - $output .= $this->elementStart2.$this->nl; - return $output; - break; - default: - $output .= $this->elementStart2.$this->valueInit; - return iCalUtilityFunctions::_size75( $output, $this->nl ); - break; - } - } - $output .= $this->elementStart2; - $output .= $this->valueInit.$content; - switch( $this->format ) { - case 'xcal': - return $output.$this->elementEnd1.$label.$this->elementEnd2; - break; - default: - return iCalUtilityFunctions::_size75( $output, $this->nl ); - break; - } - } -/** - * creates formatted output for calendar component property parameters - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.10.27 - 2012-01-16 - * @param array $params optional - * @param array $ctrKeys optional - * @return string - */ - function _createParams( $params=array(), $ctrKeys=array() ) { - if( !is_array( $params ) || empty( $params )) - $params = array(); - $attrLANG = $attr1 = $attr2 = $lang = null; - $CNattrKey = ( in_array( 'CN', $ctrKeys )) ? TRUE : FALSE ; - $LANGattrKey = ( in_array( 'LANGUAGE', $ctrKeys )) ? TRUE : FALSE ; - $CNattrExist = $LANGattrExist = FALSE; - $xparams = array(); - foreach( $params as $paramKey => $paramValue ) { - if(( FALSE !== strpos( $paramValue, ':' )) || - ( FALSE !== strpos( $paramValue, ';' )) || - ( FALSE !== strpos( $paramValue, ',' ))) - $paramValue = '"'.$paramValue.'"'; - if( ctype_digit( (string) $paramKey )) { - $xparams[] = $paramValue; - continue; - } - $paramKey = strtoupper( $paramKey ); - if( !in_array( $paramKey, array( 'ALTREP', 'CN', 'DIR', 'ENCODING', 'FMTTYPE', 'LANGUAGE', 'RANGE', 'RELTYPE', 'SENT-BY', 'TZID', 'VALUE' ))) - $xparams[$paramKey] = $paramValue; - else - $params[$paramKey] = $paramValue; - } - ksort( $xparams, SORT_STRING ); - foreach( $xparams as $paramKey => $paramValue ) { - if( ctype_digit( (string) $paramKey )) - $attr2 .= $this->intAttrDelimiter.$paramValue; - else - $attr2 .= $this->intAttrDelimiter."$paramKey=$paramValue"; - } - if( isset( $params['FMTTYPE'] ) && !in_array( 'FMTTYPE', $ctrKeys )) { - $attr1 .= $this->intAttrDelimiter.'FMTTYPE='.$params['FMTTYPE'].$attr2; - $attr2 = null; - } - if( isset( $params['ENCODING'] ) && !in_array( 'ENCODING', $ctrKeys )) { - if( !empty( $attr2 )) { - $attr1 .= $attr2; - $attr2 = null; - } - $attr1 .= $this->intAttrDelimiter.'ENCODING='.$params['ENCODING']; - } - if( isset( $params['VALUE'] ) && !in_array( 'VALUE', $ctrKeys )) - $attr1 .= $this->intAttrDelimiter.'VALUE='.$params['VALUE']; - if( isset( $params['TZID'] ) && !in_array( 'TZID', $ctrKeys )) { - $attr1 .= $this->intAttrDelimiter.'TZID='.$params['TZID']; - } - if( isset( $params['RANGE'] ) && !in_array( 'RANGE', $ctrKeys )) - $attr1 .= $this->intAttrDelimiter.'RANGE='.$params['RANGE']; - if( isset( $params['RELTYPE'] ) && !in_array( 'RELTYPE', $ctrKeys )) - $attr1 .= $this->intAttrDelimiter.'RELTYPE='.$params['RELTYPE']; - if( isset( $params['CN'] ) && $CNattrKey ) { - $attr1 = $this->intAttrDelimiter.'CN='.$params['CN']; - $CNattrExist = TRUE; - } - if( isset( $params['DIR'] ) && in_array( 'DIR', $ctrKeys )) { - $delim = ( FALSE !== strpos( $params['DIR'], '"' )) ? '' : '"'; - $attr1 .= $this->intAttrDelimiter.'DIR='.$delim.$params['DIR'].$delim; - } - if( isset( $params['SENT-BY'] ) && in_array( 'SENT-BY', $ctrKeys )) - $attr1 .= $this->intAttrDelimiter.'SENT-BY='.$params['SENT-BY']; - if( isset( $params['ALTREP'] ) && in_array( 'ALTREP', $ctrKeys )) { - $delim = ( FALSE !== strpos( $params['ALTREP'], '"' )) ? '' : '"'; - $attr1 .= $this->intAttrDelimiter.'ALTREP='.$delim.$params['ALTREP'].$delim; - } - if( isset( $params['LANGUAGE'] ) && $LANGattrKey ) { - $attrLANG .= $this->intAttrDelimiter.'LANGUAGE='.$params['LANGUAGE']; - $LANGattrExist = TRUE; - } - if( !$LANGattrExist ) { - $lang = $this->getConfig( 'language' ); - if(( $CNattrExist || $LANGattrKey ) && $lang ) - $attrLANG .= $this->intAttrDelimiter.'LANGUAGE='.$lang; - } - return $attr1.$attrLANG.$attr2; - } -/** - * creates formatted output for calendar component property data value type recur - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.14.1 - 2012-10-06 - * @param array $recurlabel - * @param array $recurdata - * @return string - */ - function _format_recur( $recurlabel, $recurdata ) { - $output = null; - foreach( $recurdata as $therule ) { - if( empty( $therule['value'] )) { - if( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( $recurlabel ); - continue; - } - $attributes = ( isset( $therule['params'] )) ? $this->_createParams( $therule['params'] ) : null; - $content1 = $content2 = null; - foreach( $therule['value'] as $rulelabel => $rulevalue ) { - switch( $rulelabel ) { - case 'FREQ': { - $content1 .= "FREQ=$rulevalue"; - break; - } - case 'UNTIL': { - $parno = ( isset( $rulevalue['hour'] )) ? 7 : 3; - $content2 .= ';UNTIL='.iCalUtilityFunctions::_date2strdate( $rulevalue, $parno ); - break; - } - case 'COUNT': - case 'INTERVAL': - case 'WKST': { - $content2 .= ";$rulelabel=$rulevalue"; - break; - } - case 'BYSECOND': - case 'BYMINUTE': - case 'BYHOUR': - case 'BYMONTHDAY': - case 'BYYEARDAY': - case 'BYWEEKNO': - case 'BYMONTH': - case 'BYSETPOS': { - $content2 .= ";$rulelabel="; - if( is_array( $rulevalue )) { - foreach( $rulevalue as $vix => $valuePart ) { - $content2 .= ( $vix ) ? ',' : null; - $content2 .= $valuePart; - } - } - else - $content2 .= $rulevalue; - break; - } - case 'BYDAY': { - $content2 .= ";$rulelabel="; - $bydaycnt = 0; - foreach( $rulevalue as $vix => $valuePart ) { - $content21 = $content22 = null; - if( is_array( $valuePart )) { - $content2 .= ( $bydaycnt ) ? ',' : null; - foreach( $valuePart as $vix2 => $valuePart2 ) { - if( 'DAY' != strtoupper( $vix2 )) - $content21 .= $valuePart2; - else - $content22 .= $valuePart2; - } - $content2 .= $content21.$content22; - $bydaycnt++; - } - else { - $content2 .= ( $bydaycnt ) ? ',' : null; - if( 'DAY' != strtoupper( $vix )) - $content21 .= $valuePart; - else { - $content22 .= $valuePart; - $bydaycnt++; - } - $content2 .= $content21.$content22; - } - } - break; - } - default: { - $content2 .= ";$rulelabel=$rulevalue"; - break; - } - } - } - $output .= $this->_createElement( $recurlabel, $attributes, $content1.$content2 ); - } - return $output; - } -/** - * check if property not exists within component - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.5.1 - 2008-10-15 - * @param string $propName - * @return bool - */ - function _notExistProp( $propName ) { - if( empty( $propName )) return FALSE; // when deleting x-prop, an empty propName may be used=allowed - $propName = strtolower( $propName ); - if( 'last-modified' == $propName ) { if( !isset( $this->lastmodified )) return TRUE; } - elseif( 'percent-complete' == $propName ) { if( !isset( $this->percentcomplete )) return TRUE; } - elseif( 'recurrence-id' == $propName ) { if( !isset( $this->recurrenceid )) return TRUE; } - elseif( 'related-to' == $propName ) { if( !isset( $this->relatedto )) return TRUE; } - elseif( 'request-status' == $propName ) { if( !isset( $this->requeststatus )) return TRUE; } - elseif(( 'x-' != substr($propName,0,2)) && !isset( $this->$propName )) return TRUE; - return FALSE; - } -/*********************************************************************************/ -/*********************************************************************************/ -/** - * get general component config variables or info about subcomponents - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.9.6 - 2011-05-14 - * @param mixed $config - * @return value - */ - function getConfig( $config = FALSE) { - if( !$config ) { - $return = array(); - $return['ALLOWEMPTY'] = $this->getConfig( 'ALLOWEMPTY' ); - $return['FORMAT'] = $this->getConfig( 'FORMAT' ); - if( FALSE !== ( $lang = $this->getConfig( 'LANGUAGE' ))) - $return['LANGUAGE'] = $lang; - $return['NEWLINECHAR'] = $this->getConfig( 'NEWLINECHAR' ); - $return['TZTD'] = $this->getConfig( 'TZID' ); - $return['UNIQUE_ID'] = $this->getConfig( 'UNIQUE_ID' ); - return $return; - } - switch( strtoupper( $config )) { - case 'ALLOWEMPTY': - return $this->allowEmpty; - break; - case 'COMPSINFO': - unset( $this->compix ); - $info = array(); - if( isset( $this->components )) { - foreach( $this->components as $cix => $component ) { - if( empty( $component )) continue; - $info[$cix]['ordno'] = $cix + 1; - $info[$cix]['type'] = $component->objName; - $info[$cix]['uid'] = $component->getProperty( 'uid' ); - $info[$cix]['props'] = $component->getConfig( 'propinfo' ); - $info[$cix]['sub'] = $component->getConfig( 'compsinfo' ); - } - } - return $info; - break; - case 'FORMAT': - return $this->format; - break; - case 'LANGUAGE': - // get language for calendar component as defined in [RFC 1766] - return $this->language; - break; - case 'NL': - case 'NEWLINECHAR': - return $this->nl; - break; - case 'PROPINFO': - $output = array(); - if( !in_array( $this->objName, array( 'valarm', 'vtimezone', 'standard', 'daylight' ))) { - if( empty( $this->uid['value'] )) $this->_makeuid(); - $output['UID'] = 1; - if( empty( $this->dtstamp )) $this->_makeDtstamp(); - $output['DTSTAMP'] = 1; - } - if( !empty( $this->summary )) $output['SUMMARY'] = 1; - if( !empty( $this->description )) $output['DESCRIPTION'] = count( $this->description ); - if( !empty( $this->dtstart )) $output['DTSTART'] = 1; - if( !empty( $this->dtend )) $output['DTEND'] = 1; - if( !empty( $this->due )) $output['DUE'] = 1; - if( !empty( $this->duration )) $output['DURATION'] = 1; - if( !empty( $this->rrule )) $output['RRULE'] = count( $this->rrule ); - if( !empty( $this->rdate )) $output['RDATE'] = count( $this->rdate ); - if( !empty( $this->exdate )) $output['EXDATE'] = count( $this->exdate ); - if( !empty( $this->exrule )) $output['EXRULE'] = count( $this->exrule ); - if( !empty( $this->action )) $output['ACTION'] = 1; - if( !empty( $this->attach )) $output['ATTACH'] = count( $this->attach ); - if( !empty( $this->attendee )) $output['ATTENDEE'] = count( $this->attendee ); - if( !empty( $this->categories )) $output['CATEGORIES'] = count( $this->categories ); - if( !empty( $this->class )) $output['CLASS'] = 1; - if( !empty( $this->comment )) $output['COMMENT'] = count( $this->comment ); - if( !empty( $this->completed )) $output['COMPLETED'] = 1; - if( !empty( $this->contact )) $output['CONTACT'] = count( $this->contact ); - if( !empty( $this->created )) $output['CREATED'] = 1; - if( !empty( $this->freebusy )) $output['FREEBUSY'] = count( $this->freebusy ); - if( !empty( $this->geo )) $output['GEO'] = 1; - if( !empty( $this->lastmodified )) $output['LAST-MODIFIED'] = 1; - if( !empty( $this->location )) $output['LOCATION'] = 1; - if( !empty( $this->organizer )) $output['ORGANIZER'] = 1; - if( !empty( $this->percentcomplete )) $output['PERCENT-COMPLETE'] = 1; - if( !empty( $this->priority )) $output['PRIORITY'] = 1; - if( !empty( $this->recurrenceid )) $output['RECURRENCE-ID'] = 1; - if( !empty( $this->relatedto )) $output['RELATED-TO'] = count( $this->relatedto ); - if( !empty( $this->repeat )) $output['REPEAT'] = 1; - if( !empty( $this->requeststatus )) $output['REQUEST-STATUS'] = count( $this->requeststatus ); - if( !empty( $this->resources )) $output['RESOURCES'] = count( $this->resources ); - if( !empty( $this->sequence )) $output['SEQUENCE'] = 1; - if( !empty( $this->sequence )) $output['SEQUENCE'] = 1; - if( !empty( $this->status )) $output['STATUS'] = 1; - if( !empty( $this->transp )) $output['TRANSP'] = 1; - if( !empty( $this->trigger )) $output['TRIGGER'] = 1; - if( !empty( $this->tzid )) $output['TZID'] = 1; - if( !empty( $this->tzname )) $output['TZNAME'] = count( $this->tzname ); - if( !empty( $this->tzoffsetfrom )) $output['TZOFFSETFROM'] = 1; - if( !empty( $this->tzoffsetto )) $output['TZOFFSETTO'] = 1; - if( !empty( $this->tzurl )) $output['TZURL'] = 1; - if( !empty( $this->url )) $output['URL'] = 1; - if( !empty( $this->xprop )) $output['X-PROP'] = count( $this->xprop ); - return $output; - break; - case 'SETPROPERTYNAMES': - return array_keys( $this->getConfig( 'propinfo' )); - break; - case 'TZID': - return $this->dtzid; - break; - case 'UNIQUE_ID': - if( empty( $this->unique_id )) - $this->unique_id = ( isset( $_SERVER['SERVER_NAME'] )) ? gethostbyname( $_SERVER['SERVER_NAME'] ) : 'localhost'; - return $this->unique_id; - break; - } - } -/** - * general component config setting - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.10.18 - 2011-10-28 - * @param mixed $config - * @param string $value - * @param bool $softUpdate - * @return void - */ - function setConfig( $config, $value = FALSE, $softUpdate = FALSE ) { - if( is_array( $config )) { - $ak = array_keys( $config ); - foreach( $ak as $k ) { - if( 'NEWLINECHAR' == strtoupper( $k )) { - if( FALSE === $this->setConfig( 'NEWLINECHAR', $config[$k] )) - return FALSE; - unset( $config[$k] ); - break; - } - } - foreach( $config as $cKey => $cValue ) { - if( FALSE === $this->setConfig( $cKey, $cValue, $softUpdate )) - return FALSE; - } - return TRUE; - } - $res = FALSE; - switch( strtoupper( $config )) { - case 'ALLOWEMPTY': - $this->allowEmpty = $value; - $subcfg = array( 'ALLOWEMPTY' => $value ); - $res = TRUE; - break; - case 'FORMAT': - $value = trim( strtolower( $value )); - $this->format = $value; - $this->_createFormat(); - $subcfg = array( 'FORMAT' => $value ); - $res = TRUE; - break; - case 'LANGUAGE': - // set language for calendar component as defined in [RFC 1766] - $value = trim( $value ); - if( empty( $this->language ) || !$softUpdate ) - $this->language = $value; - $subcfg = array( 'LANGUAGE' => $value ); - $res = TRUE; - break; - case 'NL': - case 'NEWLINECHAR': - $this->nl = $value; - $this->_createFormat(); - $subcfg = array( 'NL' => $value ); - $res = TRUE; - break; - case 'TZID': - $this->dtzid = $value; - $subcfg = array( 'TZID' => $value ); - $res = TRUE; - break; - case 'UNIQUE_ID': - $value = trim( $value ); - $this->unique_id = $value; - $subcfg = array( 'UNIQUE_ID' => $value ); - $res = TRUE; - break; - default: // any unvalid config key.. . - return TRUE; - } - if( !$res ) return FALSE; - if( isset( $subcfg ) && !empty( $this->components )) { - foreach( $subcfg as $cfgkey => $cfgvalue ) { - foreach( $this->components as $cix => $component ) { - $res = $component->setConfig( $cfgkey, $cfgvalue, $softUpdate ); - if( !$res ) - break 2; - $this->components[$cix] = $component->copy(); // PHP4 compliant - } - } - } - return $res; - } -/*********************************************************************************/ -/** - * delete component property value - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.8.8 - 2011-03-15 - * @param mixed $propName, bool FALSE => X-property - * @param int $propix, optional, if specific property is wanted in case of multiply occurences - * @return bool, if successfull delete TRUE - */ - function deleteProperty( $propName=FALSE, $propix=FALSE ) { - if( $this->_notExistProp( $propName )) return FALSE; - $propName = strtoupper( $propName ); - if( in_array( $propName, array( 'ATTACH', 'ATTENDEE', 'CATEGORIES', 'COMMENT', 'CONTACT', 'DESCRIPTION', 'EXDATE', 'EXRULE', - 'FREEBUSY', 'RDATE', 'RELATED-TO', 'RESOURCES', 'RRULE', 'REQUEST-STATUS', 'TZNAME', 'X-PROP' ))) { - if( !$propix ) - $propix = ( isset( $this->propdelix[$propName] ) && ( 'X-PROP' != $propName )) ? $this->propdelix[$propName] + 2 : 1; - $this->propdelix[$propName] = --$propix; - } - $return = FALSE; - switch( $propName ) { - case 'ACTION': - if( !empty( $this->action )) { - $this->action = ''; - $return = TRUE; - } - break; - case 'ATTACH': - return $this->deletePropertyM( $this->attach, $this->propdelix[$propName] ); - break; - case 'ATTENDEE': - return $this->deletePropertyM( $this->attendee, $this->propdelix[$propName] ); - break; - case 'CATEGORIES': - return $this->deletePropertyM( $this->categories, $this->propdelix[$propName] ); - break; - case 'CLASS': - if( !empty( $this->class )) { - $this->class = ''; - $return = TRUE; - } - break; - case 'COMMENT': - return $this->deletePropertyM( $this->comment, $this->propdelix[$propName] ); - break; - case 'COMPLETED': - if( !empty( $this->completed )) { - $this->completed = ''; - $return = TRUE; - } - break; - case 'CONTACT': - return $this->deletePropertyM( $this->contact, $this->propdelix[$propName] ); - break; - case 'CREATED': - if( !empty( $this->created )) { - $this->created = ''; - $return = TRUE; - } - break; - case 'DESCRIPTION': - return $this->deletePropertyM( $this->description, $this->propdelix[$propName] ); - break; - case 'DTEND': - if( !empty( $this->dtend )) { - $this->dtend = ''; - $return = TRUE; - } - break; - case 'DTSTAMP': - if( in_array( $this->objName, array( 'valarm', 'vtimezone', 'standard', 'daylight' ))) - return FALSE; - if( !empty( $this->dtstamp )) { - $this->dtstamp = ''; - $return = TRUE; - } - break; - case 'DTSTART': - if( !empty( $this->dtstart )) { - $this->dtstart = ''; - $return = TRUE; - } - break; - case 'DUE': - if( !empty( $this->due )) { - $this->due = ''; - $return = TRUE; - } - break; - case 'DURATION': - if( !empty( $this->duration )) { - $this->duration = ''; - $return = TRUE; - } - break; - case 'EXDATE': - return $this->deletePropertyM( $this->exdate, $this->propdelix[$propName] ); - break; - case 'EXRULE': - return $this->deletePropertyM( $this->exrule, $this->propdelix[$propName] ); - break; - case 'FREEBUSY': - return $this->deletePropertyM( $this->freebusy, $this->propdelix[$propName] ); - break; - case 'GEO': - if( !empty( $this->geo )) { - $this->geo = ''; - $return = TRUE; - } - break; - case 'LAST-MODIFIED': - if( !empty( $this->lastmodified )) { - $this->lastmodified = ''; - $return = TRUE; - } - break; - case 'LOCATION': - if( !empty( $this->location )) { - $this->location = ''; - $return = TRUE; - } - break; - case 'ORGANIZER': - if( !empty( $this->organizer )) { - $this->organizer = ''; - $return = TRUE; - } - break; - case 'PERCENT-COMPLETE': - if( !empty( $this->percentcomplete )) { - $this->percentcomplete = ''; - $return = TRUE; - } - break; - case 'PRIORITY': - if( !empty( $this->priority )) { - $this->priority = ''; - $return = TRUE; - } - break; - case 'RDATE': - return $this->deletePropertyM( $this->rdate, $this->propdelix[$propName] ); - break; - case 'RECURRENCE-ID': - if( !empty( $this->recurrenceid )) { - $this->recurrenceid = ''; - $return = TRUE; - } - break; - case 'RELATED-TO': - return $this->deletePropertyM( $this->relatedto, $this->propdelix[$propName] ); - break; - case 'REPEAT': - if( !empty( $this->repeat )) { - $this->repeat = ''; - $return = TRUE; - } - break; - case 'REQUEST-STATUS': - return $this->deletePropertyM( $this->requeststatus, $this->propdelix[$propName] ); - break; - case 'RESOURCES': - return $this->deletePropertyM( $this->resources, $this->propdelix[$propName] ); - break; - case 'RRULE': - return $this->deletePropertyM( $this->rrule, $this->propdelix[$propName] ); - break; - case 'SEQUENCE': - if( !empty( $this->sequence )) { - $this->sequence = ''; - $return = TRUE; - } - break; - case 'STATUS': - if( !empty( $this->status )) { - $this->status = ''; - $return = TRUE; - } - break; - case 'SUMMARY': - if( !empty( $this->summary )) { - $this->summary = ''; - $return = TRUE; - } - break; - case 'TRANSP': - if( !empty( $this->transp )) { - $this->transp = ''; - $return = TRUE; - } - break; - case 'TRIGGER': - if( !empty( $this->trigger )) { - $this->trigger = ''; - $return = TRUE; - } - break; - case 'TZID': - if( !empty( $this->tzid )) { - $this->tzid = ''; - $return = TRUE; - } - break; - case 'TZNAME': - return $this->deletePropertyM( $this->tzname, $this->propdelix[$propName] ); - break; - case 'TZOFFSETFROM': - if( !empty( $this->tzoffsetfrom )) { - $this->tzoffsetfrom = ''; - $return = TRUE; - } - break; - case 'TZOFFSETTO': - if( !empty( $this->tzoffsetto )) { - $this->tzoffsetto = ''; - $return = TRUE; - } - break; - case 'TZURL': - if( !empty( $this->tzurl )) { - $this->tzurl = ''; - $return = TRUE; - } - break; - case 'UID': - if( in_array( $this->objName, array( 'valarm', 'vtimezone', 'standard', 'daylight' ))) - return FALSE; - if( !empty( $this->uid )) { - $this->uid = ''; - $return = TRUE; - } - break; - case 'URL': - if( !empty( $this->url )) { - $this->url = ''; - $return = TRUE; - } - break; - default: - $reduced = ''; - if( $propName != 'X-PROP' ) { - if( !isset( $this->xprop[$propName] )) return FALSE; - foreach( $this->xprop as $k => $a ) { - if(( $k != $propName ) && !empty( $a )) - $reduced[$k] = $a; - } - } - else { - if( count( $this->xprop ) <= $propix ) { unset( $this->propdelix[$propName] ); return FALSE; } - $xpropno = 0; - foreach( $this->xprop as $xpropkey => $xpropvalue ) { - if( $propix != $xpropno ) - $reduced[$xpropkey] = $xpropvalue; - $xpropno++; - } - } - $this->xprop = $reduced; - if( empty( $this->xprop )) { - unset( $this->propdelix[$propName] ); - return FALSE; - } - return TRUE; - } - return $return; - } -/*********************************************************************************/ -/** - * delete component property value, fixing components with multiple occurencies - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.8.8 - 2011-03-15 - * @param array $multiprop, reference to a component property - * @param int $propix, reference to removal counter - * @return bool TRUE - */ - function deletePropertyM( & $multiprop, & $propix ) { - if( isset( $multiprop[$propix] )) - unset( $multiprop[$propix] ); - if( empty( $multiprop )) { - $multiprop = ''; - unset( $propix ); - return FALSE; - } - else - return TRUE; - } -/** - * get component property value/params - * - * if property has multiply values, consequtive function calls are needed - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.12.4 - 2012-04-22 - * @param string $propName, optional - * @param int @propix, optional, if specific property is wanted in case of multiply occurences - * @param bool $inclParam=FALSE - * @param bool $specform=FALSE - * @return mixed - */ - function getProperty( $propName=FALSE, $propix=FALSE, $inclParam=FALSE, $specform=FALSE ) { - if( 'GEOLOCATION' == strtoupper( $propName )) { - $content = $this->getProperty( 'LOCATION' ); - $content = ( !empty( $content )) ? $content.' ' : ''; - if(( FALSE === ( $geo = $this->getProperty( 'GEO' ))) || empty( $geo )) - return FALSE; - if( 0.0 < $geo['latitude'] ) - $sign = '+'; - else - $sign = ( 0.0 > $geo['latitude'] ) ? '-' : ''; - $content .= $sign.sprintf( "%09.6f", abs( $geo['latitude'] )); // sprintf && lpad && float && sign !"#¤%&/( - $content = rtrim( rtrim( $content, '0' ), '.' ); - if( 0.0 < $geo['longitude'] ) - $sign = '+'; - else - $sign = ( 0.0 > $geo['longitude'] ) ? '-' : ''; - return $content.$sign.sprintf( '%8.6f', abs( $geo['longitude'] )).'/'; // sprintf && lpad && float && sign !"#¤%&/( - } - if( $this->_notExistProp( $propName )) return FALSE; - $propName = ( $propName ) ? strtoupper( $propName ) : 'X-PROP'; - if( in_array( $propName, array( 'ATTACH', 'ATTENDEE', 'CATEGORIES', 'COMMENT', 'CONTACT', 'DESCRIPTION', 'EXDATE', 'EXRULE', - 'FREEBUSY', 'RDATE', 'RELATED-TO', 'RESOURCES', 'RRULE', 'REQUEST-STATUS', 'TZNAME', 'X-PROP' ))) { - if( !$propix ) - $propix = ( isset( $this->propix[$propName] )) ? $this->propix[$propName] + 2 : 1; - $this->propix[$propName] = --$propix; - } - switch( $propName ) { - case 'ACTION': - if( !empty( $this->action['value'] )) return ( $inclParam ) ? $this->action : $this->action['value']; - break; - case 'ATTACH': - $ak = ( is_array( $this->attach )) ? array_keys( $this->attach ) : array(); - while( is_array( $this->attach ) && !isset( $this->attach[$propix] ) && ( 0 < count( $this->attach )) && ( $propix < end( $ak ))) - $propix++; - $this->propix[$propName] = $propix; - if( !isset( $this->attach[$propix] )) { unset( $this->propix[$propName] ); return FALSE; } - return ( $inclParam ) ? $this->attach[$propix] : $this->attach[$propix]['value']; - break; - case 'ATTENDEE': - $ak = ( is_array( $this->attendee )) ? array_keys( $this->attendee ) : array(); - while( is_array( $this->attendee ) && !isset( $this->attendee[$propix] ) && ( 0 < count( $this->attendee )) && ( $propix < end( $ak ))) - $propix++; - $this->propix[$propName] = $propix; - if( !isset( $this->attendee[$propix] )) { unset( $this->propix[$propName] ); return FALSE; } - return ( $inclParam ) ? $this->attendee[$propix] : $this->attendee[$propix]['value']; - break; - case 'CATEGORIES': - $ak = ( is_array( $this->categories )) ? array_keys( $this->categories ) : array(); - while( is_array( $this->categories ) && !isset( $this->categories[$propix] ) && ( 0 < count( $this->categories )) && ( $propix < end( $ak ))) - $propix++; - $this->propix[$propName] = $propix; - if( !isset( $this->categories[$propix] )) { unset( $this->propix[$propName] ); return FALSE; } - return ( $inclParam ) ? $this->categories[$propix] : $this->categories[$propix]['value']; - break; - case 'CLASS': - if( !empty( $this->class['value'] )) return ( $inclParam ) ? $this->class : $this->class['value']; - break; - case 'COMMENT': - $ak = ( is_array( $this->comment )) ? array_keys( $this->comment ) : array(); - while( is_array( $this->comment ) && !isset( $this->comment[$propix] ) && ( 0 < count( $this->comment )) && ( $propix < end( $ak ))) - $propix++; - $this->propix[$propName] = $propix; - if( !isset( $this->comment[$propix] )) { unset( $this->propix[$propName] ); return FALSE; } - return ( $inclParam ) ? $this->comment[$propix] : $this->comment[$propix]['value']; - break; - case 'COMPLETED': - if( !empty( $this->completed['value'] )) return ( $inclParam ) ? $this->completed : $this->completed['value']; - break; - case 'CONTACT': - $ak = ( is_array( $this->contact )) ? array_keys( $this->contact ) : array(); - while( is_array( $this->contact ) && !isset( $this->contact[$propix] ) && ( 0 < count( $this->contact )) && ( $propix < end( $ak ))) - $propix++; - $this->propix[$propName] = $propix; - if( !isset( $this->contact[$propix] )) { unset( $this->propix[$propName] ); return FALSE; } - return ( $inclParam ) ? $this->contact[$propix] : $this->contact[$propix]['value']; - break; - case 'CREATED': - if( !empty( $this->created['value'] )) return ( $inclParam ) ? $this->created : $this->created['value']; - break; - case 'DESCRIPTION': - $ak = ( is_array( $this->description )) ? array_keys( $this->description ) : array(); - while( is_array( $this->description ) && !isset( $this->description[$propix] ) && ( 0 < count( $this->description )) && ( $propix < end( $ak ))) - $propix++; - $this->propix[$propName] = $propix; - if( !isset( $this->description[$propix] )) { unset( $this->propix[$propName] ); return FALSE; } - return ( $inclParam ) ? $this->description[$propix] : $this->description[$propix]['value']; - break; - case 'DTEND': - if( !empty( $this->dtend['value'] )) return ( $inclParam ) ? $this->dtend : $this->dtend['value']; - break; - case 'DTSTAMP': - if( in_array( $this->objName, array( 'valarm', 'vtimezone', 'standard', 'daylight' ))) - return; - if( !isset( $this->dtstamp['value'] )) - $this->_makeDtstamp(); - return ( $inclParam ) ? $this->dtstamp : $this->dtstamp['value']; - break; - case 'DTSTART': - if( !empty( $this->dtstart['value'] )) return ( $inclParam ) ? $this->dtstart : $this->dtstart['value']; - break; - case 'DUE': - if( !empty( $this->due['value'] )) return ( $inclParam ) ? $this->due : $this->due['value']; - break; - case 'DURATION': - if( !isset( $this->duration['value'] )) return FALSE; - $value = ( $specform && isset( $this->dtstart['value'] ) && isset( $this->duration['value'] )) ? iCalUtilityFunctions::_duration2date( $this->dtstart['value'], $this->duration['value'] ) : $this->duration['value']; - return ( $inclParam ) ? array( 'value' => $value, 'params' => $this->duration['params'] ) : $value; - break; - case 'EXDATE': - $ak = ( is_array( $this->exdate )) ? array_keys( $this->exdate ) : array(); - while( is_array( $this->exdate ) && !isset( $this->exdate[$propix] ) && ( 0 < count( $this->exdate )) && ( $propix < end( $ak ))) - $propix++; - $this->propix[$propName] = $propix; - if( !isset( $this->exdate[$propix] )) { unset( $this->propix[$propName] ); return FALSE; } - return ( $inclParam ) ? $this->exdate[$propix] : $this->exdate[$propix]['value']; - break; - case 'EXRULE': - $ak = ( is_array( $this->exrule )) ? array_keys( $this->exrule ) : array(); - while( is_array( $this->exrule ) && !isset( $this->exrule[$propix] ) && ( 0 < count( $this->exrule )) && ( $propix < end( $ak ))) - $propix++; - $this->propix[$propName] = $propix; - if( !isset( $this->exrule[$propix] )) { unset( $this->propix[$propName] ); return FALSE; } - return ( $inclParam ) ? $this->exrule[$propix] : $this->exrule[$propix]['value']; - break; - case 'FREEBUSY': - $ak = ( is_array( $this->freebusy )) ? array_keys( $this->freebusy ) : array(); - while( is_array( $this->freebusy ) && !isset( $this->freebusy[$propix] ) && ( 0 < count( $this->freebusy )) && ( $propix < end( $ak ))) - $propix++; - $this->propix[$propName] = $propix; - if( !isset( $this->freebusy[$propix] )) { unset( $this->propix[$propName] ); return FALSE; } - return ( $inclParam ) ? $this->freebusy[$propix] : $this->freebusy[$propix]['value']; - break; - case 'GEO': - if( !empty( $this->geo['value'] )) return ( $inclParam ) ? $this->geo : $this->geo['value']; - break; - case 'LAST-MODIFIED': - if( !empty( $this->lastmodified['value'] )) return ( $inclParam ) ? $this->lastmodified : $this->lastmodified['value']; - break; - case 'LOCATION': - if( !empty( $this->location['value'] )) return ( $inclParam ) ? $this->location : $this->location['value']; - break; - case 'ORGANIZER': - if( !empty( $this->organizer['value'] )) return ( $inclParam ) ? $this->organizer : $this->organizer['value']; - break; - case 'PERCENT-COMPLETE': - if( !empty( $this->percentcomplete['value'] ) || ( isset( $this->percentcomplete['value'] ) && ( '0' == $this->percentcomplete['value'] ))) return ( $inclParam ) ? $this->percentcomplete : $this->percentcomplete['value']; - break; - case 'PRIORITY': - if( !empty( $this->priority['value'] ) || ( isset( $this->priority['value'] ) && ('0' == $this->priority['value'] ))) return ( $inclParam ) ? $this->priority : $this->priority['value']; - break; - case 'RDATE': - $ak = ( is_array( $this->rdate )) ? array_keys( $this->rdate ) : array(); - while( is_array( $this->rdate ) && !isset( $this->rdate[$propix] ) && ( 0 < count( $this->rdate )) && ( $propix < end( $ak ))) - $propix++; - $this->propix[$propName] = $propix; - if( !isset( $this->rdate[$propix] )) { unset( $this->propix[$propName] ); return FALSE; } - return ( $inclParam ) ? $this->rdate[$propix] : $this->rdate[$propix]['value']; - break; - case 'RECURRENCE-ID': - if( !empty( $this->recurrenceid['value'] )) return ( $inclParam ) ? $this->recurrenceid : $this->recurrenceid['value']; - break; - case 'RELATED-TO': - $ak = ( is_array( $this->relatedto )) ? array_keys( $this->relatedto ) : array(); - while( is_array( $this->relatedto ) && !isset( $this->relatedto[$propix] ) && ( 0 < count( $this->relatedto )) && ( $propix < end( $ak ))) - $propix++; - $this->propix[$propName] = $propix; - if( !isset( $this->relatedto[$propix] )) { unset( $this->propix[$propName] ); return FALSE; } - return ( $inclParam ) ? $this->relatedto[$propix] : $this->relatedto[$propix]['value']; - break; - case 'REPEAT': - if( !empty( $this->repeat['value'] ) || ( isset( $this->repeat['value'] ) && ( '0' == $this->repeat['value'] ))) return ( $inclParam ) ? $this->repeat : $this->repeat['value']; - break; - case 'REQUEST-STATUS': - $ak = ( is_array( $this->requeststatus )) ? array_keys( $this->requeststatus ) : array(); - while( is_array( $this->requeststatus ) && !isset( $this->requeststatus[$propix] ) && ( 0 < count( $this->requeststatus )) && ( $propix < end( $ak ))) - $propix++; - $this->propix[$propName] = $propix; - if( !isset( $this->requeststatus[$propix] )) { unset( $this->propix[$propName] ); return FALSE; } - return ( $inclParam ) ? $this->requeststatus[$propix] : $this->requeststatus[$propix]['value']; - break; - case 'RESOURCES': - $ak = ( is_array( $this->resources )) ? array_keys( $this->resources ) : array(); - while( is_array( $this->resources ) && !isset( $this->resources[$propix] ) && ( 0 < count( $this->resources )) && ( $propix < end( $ak ))) - $propix++; - $this->propix[$propName] = $propix; - if( !isset( $this->resources[$propix] )) { unset( $this->propix[$propName] ); return FALSE; } - return ( $inclParam ) ? $this->resources[$propix] : $this->resources[$propix]['value']; - break; - case 'RRULE': - $ak = ( is_array( $this->rrule )) ? array_keys( $this->rrule ) : array(); - while( is_array( $this->rrule ) && !isset( $this->rrule[$propix] ) && ( 0 < count( $this->rrule )) && ( $propix < end( $ak ))) - $propix++; - $this->propix[$propName] = $propix; - if( !isset( $this->rrule[$propix] )) { unset( $this->propix[$propName] ); return FALSE; } - return ( $inclParam ) ? $this->rrule[$propix] : $this->rrule[$propix]['value']; - break; - case 'SEQUENCE': - if( isset( $this->sequence['value'] ) && ( isset( $this->sequence['value'] ) && ( '0' <= $this->sequence['value'] ))) return ( $inclParam ) ? $this->sequence : $this->sequence['value']; - break; - case 'STATUS': - if( !empty( $this->status['value'] )) return ( $inclParam ) ? $this->status : $this->status['value']; - break; - case 'SUMMARY': - if( !empty( $this->summary['value'] )) return ( $inclParam ) ? $this->summary : $this->summary['value']; - break; - case 'TRANSP': - if( !empty( $this->transp['value'] )) return ( $inclParam ) ? $this->transp : $this->transp['value']; - break; - case 'TRIGGER': - if( !empty( $this->trigger['value'] )) return ( $inclParam ) ? $this->trigger : $this->trigger['value']; - break; - case 'TZID': - if( !empty( $this->tzid['value'] )) return ( $inclParam ) ? $this->tzid : $this->tzid['value']; - break; - case 'TZNAME': - $ak = ( is_array( $this->tzname )) ? array_keys( $this->tzname ) : array(); - while( is_array( $this->tzname ) && !isset( $this->tzname[$propix] ) && ( 0 < count( $this->tzname )) && ( $propix < end( $ak ))) - $propix++; - $this->propix[$propName] = $propix; - if( !isset( $this->tzname[$propix] )) { unset( $this->propix[$propName] ); return FALSE; } - return ( $inclParam ) ? $this->tzname[$propix] : $this->tzname[$propix]['value']; - break; - case 'TZOFFSETFROM': - if( !empty( $this->tzoffsetfrom['value'] )) return ( $inclParam ) ? $this->tzoffsetfrom : $this->tzoffsetfrom['value']; - break; - case 'TZOFFSETTO': - if( !empty( $this->tzoffsetto['value'] )) return ( $inclParam ) ? $this->tzoffsetto : $this->tzoffsetto['value']; - break; - case 'TZURL': - if( !empty( $this->tzurl['value'] )) return ( $inclParam ) ? $this->tzurl : $this->tzurl['value']; - break; - case 'UID': - if( in_array( $this->objName, array( 'valarm', 'vtimezone', 'standard', 'daylight' ))) - return FALSE; - if( empty( $this->uid['value'] )) - $this->_makeuid(); - return ( $inclParam ) ? $this->uid : $this->uid['value']; - break; - case 'URL': - if( !empty( $this->url['value'] )) return ( $inclParam ) ? $this->url : $this->url['value']; - break; - default: - if( $propName != 'X-PROP' ) { - if( !isset( $this->xprop[$propName] )) return FALSE; - return ( $inclParam ) ? array( $propName, $this->xprop[$propName] ) - : array( $propName, $this->xprop[$propName]['value'] ); - } - else { - if( empty( $this->xprop )) return FALSE; - $xpropno = 0; - foreach( $this->xprop as $xpropkey => $xpropvalue ) { - if( $propix == $xpropno ) - return ( $inclParam ) ? array( $xpropkey, $this->xprop[$xpropkey] ) - : array( $xpropkey, $this->xprop[$xpropkey]['value'] ); - else - $xpropno++; - } - return FALSE; // not found ?? - } - } - return FALSE; - } -/** - * returns calendar property unique values for 'ATTENDEE', 'CATEGORIES', 'CONTACT', 'RELATED-TO' or 'RESOURCES' and for each, number of occurrence - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.13.4 - 2012-08-07 - * @param string $propName - * @param array $output, incremented result array - */ - function _getProperties( $propName, & $output ) { - if( empty( $output )) - $output = array(); - if( !in_array( strtoupper( $propName ), array( 'ATTENDEE', 'CATEGORIES', 'CONTACT', 'RELATED-TO', 'RESOURCES' ))) - return $output; - while( FALSE !== ( $content = $this->getProperty( $propName ))) { - if( empty( $content )) - continue; - if( is_array( $content )) { - foreach( $content as $part ) { - if( FALSE !== strpos( $part, ',' )) { - $part = explode( ',', $part ); - foreach( $part as $thePart ) { - $thePart = trim( $thePart ); - if( !empty( $thePart )) { - if( !isset( $output[$thePart] )) - $output[$thePart] = 1; - else - $output[$thePart] += 1; - } - } - } - else { - $part = trim( $part ); - if( !isset( $output[$part] )) - $output[$part] = 1; - else - $output[$part] += 1; - } - } - } // end if( is_array( $content )) - elseif( FALSE !== strpos( $content, ',' )) { - $content = explode( ',', $content ); - foreach( $content as $thePart ) { - $thePart = trim( $thePart ); - if( !empty( $thePart )) { - if( !isset( $output[$thePart] )) - $output[$thePart] = 1; - else - $output[$thePart] += 1; - } - } - } // end elseif( FALSE !== strpos( $content, ',' )) - else { - $content = trim( $content ); - if( !empty( $content )) { - if( !isset( $output[$content] )) - $output[$content] = 1; - else - $output[$content] += 1; - } - } - } - ksort( $output ); - } -/** - * general component property setting - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.5.1 - 2008-11-05 - * @param mixed $args variable number of function arguments, - * first argument is ALWAYS component name, - * second ALWAYS component value! - * @return void - */ - function setProperty() { - $numargs = func_num_args(); - if( 1 > $numargs ) return FALSE; - $arglist = func_get_args(); - if( $this->_notExistProp( $arglist[0] )) return FALSE; - if( !$this->getConfig( 'allowEmpty' ) && ( !isset( $arglist[1] ) || empty( $arglist[1] ))) - return FALSE; - $arglist[0] = strtoupper( $arglist[0] ); - for( $argix=$numargs; $argix < 12; $argix++ ) { - if( !isset( $arglist[$argix] )) - $arglist[$argix] = null; - } - switch( $arglist[0] ) { - case 'ACTION': - return $this->setAction( $arglist[1], $arglist[2] ); - case 'ATTACH': - return $this->setAttach( $arglist[1], $arglist[2], $arglist[3] ); - case 'ATTENDEE': - return $this->setAttendee( $arglist[1], $arglist[2], $arglist[3] ); - case 'CATEGORIES': - return $this->setCategories( $arglist[1], $arglist[2], $arglist[3] ); - case 'CLASS': - return $this->setClass( $arglist[1], $arglist[2] ); - case 'COMMENT': - return $this->setComment( $arglist[1], $arglist[2], $arglist[3] ); - case 'COMPLETED': - return $this->setCompleted( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7] ); - case 'CONTACT': - return $this->setContact( $arglist[1], $arglist[2], $arglist[3] ); - case 'CREATED': - return $this->setCreated( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7] ); - case 'DESCRIPTION': - return $this->setDescription( $arglist[1], $arglist[2], $arglist[3] ); - case 'DTEND': - return $this->setDtend( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7], $arglist[8] ); - case 'DTSTAMP': - return $this->setDtstamp( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7] ); - case 'DTSTART': - return $this->setDtstart( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7], $arglist[8] ); - case 'DUE': - return $this->setDue( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7], $arglist[8] ); - case 'DURATION': - return $this->setDuration( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6] ); - case 'EXDATE': - return $this->setExdate( $arglist[1], $arglist[2], $arglist[3] ); - case 'EXRULE': - return $this->setExrule( $arglist[1], $arglist[2], $arglist[3] ); - case 'FREEBUSY': - return $this->setFreebusy( $arglist[1], $arglist[2], $arglist[3], $arglist[4] ); - case 'GEO': - return $this->setGeo( $arglist[1], $arglist[2], $arglist[3] ); - case 'LAST-MODIFIED': - return $this->setLastModified( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7] ); - case 'LOCATION': - return $this->setLocation( $arglist[1], $arglist[2] ); - case 'ORGANIZER': - return $this->setOrganizer( $arglist[1], $arglist[2] ); - case 'PERCENT-COMPLETE': - return $this->setPercentComplete( $arglist[1], $arglist[2] ); - case 'PRIORITY': - return $this->setPriority( $arglist[1], $arglist[2] ); - case 'RDATE': - return $this->setRdate( $arglist[1], $arglist[2], $arglist[3] ); - case 'RECURRENCE-ID': - return $this->setRecurrenceid( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7], $arglist[8] ); - case 'RELATED-TO': - return $this->setRelatedTo( $arglist[1], $arglist[2], $arglist[3] ); - case 'REPEAT': - return $this->setRepeat( $arglist[1], $arglist[2] ); - case 'REQUEST-STATUS': - return $this->setRequestStatus( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5] ); - case 'RESOURCES': - return $this->setResources( $arglist[1], $arglist[2], $arglist[3] ); - case 'RRULE': - return $this->setRrule( $arglist[1], $arglist[2], $arglist[3] ); - case 'SEQUENCE': - return $this->setSequence( $arglist[1], $arglist[2] ); - case 'STATUS': - return $this->setStatus( $arglist[1], $arglist[2] ); - case 'SUMMARY': - return $this->setSummary( $arglist[1], $arglist[2] ); - case 'TRANSP': - return $this->setTransp( $arglist[1], $arglist[2] ); - case 'TRIGGER': - return $this->setTrigger( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7], $arglist[8], $arglist[9], $arglist[10], $arglist[11] ); - case 'TZID': - return $this->setTzid( $arglist[1], $arglist[2] ); - case 'TZNAME': - return $this->setTzname( $arglist[1], $arglist[2], $arglist[3] ); - case 'TZOFFSETFROM': - return $this->setTzoffsetfrom( $arglist[1], $arglist[2] ); - case 'TZOFFSETTO': - return $this->setTzoffsetto( $arglist[1], $arglist[2] ); - case 'TZURL': - return $this->setTzurl( $arglist[1], $arglist[2] ); - case 'UID': - return $this->setUid( $arglist[1], $arglist[2] ); - case 'URL': - return $this->setUrl( $arglist[1], $arglist[2] ); - default: - return $this->setXprop( $arglist[0], $arglist[1], $arglist[2] ); - } - return FALSE; - } -/*********************************************************************************/ -/** - * parse component unparsed data into properties - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.16.2 - 2012-12-18 - * @param mixed $unparsedtext, optional, strict rfc2445 formatted, single property string or array of strings - * @return bool FALSE if error occurs during parsing - * - */ - function parse( $unparsedtext=null ) { - $nl = $this->getConfig( 'nl' ); - if( !empty( $unparsedtext )) { - if( is_array( $unparsedtext )) - $unparsedtext = implode( '\n'.$nl, $unparsedtext ); - $unparsedtext = explode( $nl, iCalUtilityFunctions::convEolChar( $unparsedtext, $nl )); - } - elseif( !isset( $this->unparsed )) - $unparsedtext = array(); - else - $unparsedtext = $this->unparsed; - /* skip leading (empty/invalid) lines */ - foreach( $unparsedtext as $lix => $line ) { - $tst = trim( $line ); - if(( '\n' == $tst ) || empty( $tst )) - unset( $unparsedtext[$lix] ); - else - break; - } - $this->unparsed = array(); - $comp = & $this; - $config = $this->getConfig(); - $compsync = $subsync = 0; - foreach ( $unparsedtext as $lix => $line ) { - if( 'END:VALARM' == strtoupper( substr( $line, 0, 10 ))) { - if( 1 != $subsync ) return FALSE; - $this->components[] = $comp->copy(); - $subsync--; - } - elseif( 'END:DAYLIGHT' == strtoupper( substr( $line, 0, 12 ))) { - if( 1 != $subsync ) return FALSE; - $this->components[] = $comp->copy(); - $subsync--; - } - elseif( 'END:STANDARD' == strtoupper( substr( $line, 0, 12 ))) { - if( 1 != $subsync ) return FALSE; - array_unshift( $this->components, $comp->copy()); - $subsync--; - } - elseif( 'END:' == strtoupper( substr( $line, 0, 4 ))) { // end: - if( 1 != $compsync ) return FALSE; - if( 0 < $subsync ) - $this->components[] = $comp->copy(); - $compsync--; - break; /* skip trailing empty lines */ - } - elseif( 'BEGIN:VALARM' == strtoupper( substr( $line, 0, 12 ))) { - $comp = new valarm( $config); - $subsync++; - } - elseif( 'BEGIN:STANDARD' == strtoupper( substr( $line, 0, 14 ))) { - $comp = new vtimezone( 'standard', $config ); - $subsync++; - } - elseif( 'BEGIN:DAYLIGHT' == strtoupper( substr( $line, 0, 14 ))) { - $comp = new vtimezone( 'daylight', $config ); - $subsync++; - } - elseif( 'BEGIN:' == strtoupper( substr( $line, 0, 6 ))) // begin: - $compsync++; - else - $comp->unparsed[] = $line; - } - if( 0 < $subsync ) - $this->components[] = $comp->copy(); - unset( $config ); - /* concatenate property values spread over several lines */ - $lastix = -1; - $propnames = array( 'action', 'attach', 'attendee', 'categories', 'comment', 'completed' - , 'contact', 'class', 'created', 'description', 'dtend', 'dtstart' - , 'dtstamp', 'due', 'duration', 'exdate', 'exrule', 'freebusy', 'geo' - , 'last-modified', 'location', 'organizer', 'percent-complete' - , 'priority', 'rdate', 'recurrence-id', 'related-to', 'repeat' - , 'request-status', 'resources', 'rrule', 'sequence', 'status' - , 'summary', 'transp', 'trigger', 'tzid', 'tzname', 'tzoffsetfrom' - , 'tzoffsetto', 'tzurl', 'uid', 'url', 'x-' ); - $proprows = array(); - for( $i = 0; $i < count( $this->unparsed ); $i++ ) { // concatenate lines - $line = rtrim( $this->unparsed[$i], $nl ); - while( isset( $this->unparsed[$i+1] ) && !empty( $this->unparsed[$i+1] ) && ( ' ' == $this->unparsed[$i+1]{0} )) - $line .= rtrim( substr( $this->unparsed[++$i], 1 ), $nl ); - $proprows[] = $line; - } - /* parse each property 'line' */ - $paramMStz = array( 'utc-', 'utc+', 'gmt-', 'gmt+' ); - $paramProto3 = array( 'fax:', 'cid:', 'sms:', 'tel:', 'urn:' ); - $paramProto4 = array( 'crid:', 'news:', 'pres:' ); - foreach( $proprows as $line ) { - if( '\n' == substr( $line, -2 )) - $line = substr( $line, 0, -2 ); - /* get propname */ - $propname = null; - $cix = 0; - while( isset( $line[$cix] )) { - if( in_array( $line[$cix], array( ':', ';' ))) - break; - else - $propname .= $line[$cix]; - $cix++; - } - if(( 'x-' == substr( $propname, 0, 2 )) || ( 'X-' == substr( $propname, 0, 2 ))) { - $propname2 = $propname; - $propname = 'X-'; - } - if( !in_array( strtolower( $propname ), $propnames )) // skip non standard property names - continue; - /* rest of the line is opt.params and value */ - $line = substr( $line, $cix ); - /* separate attributes from value */ - $attr = array(); - $attrix = -1; - $clen = strlen( $line ); - $WithinQuotes = FALSE; - $cix = 0; - while( FALSE !== substr( $line, $cix, 1 )) { - if( ( ':' == $line[$cix] ) && - ( substr( $line,$cix, 3 ) != '://' ) && - ( !in_array( strtolower( substr( $line,$cix - 6, 4 )), $paramMStz )) && - ( !in_array( strtolower( substr( $line,$cix - 3, 4 )), $paramProto3 )) && - ( !in_array( strtolower( substr( $line,$cix - 4, 5 )), $paramProto4 )) && - ( strtolower( substr( $line,$cix - 6, 7 )) != 'mailto:' ) && - !$WithinQuotes ) { - $attrEnd = TRUE; - if(( $cix < ( $clen - 4 )) && - ctype_digit( substr( $line, $cix+1, 4 ))) { // an URI with a (4pos) portnr?? - for( $c2ix = $cix; 3 < $c2ix; $c2ix-- ) { - if( '://' == substr( $line, $c2ix - 2, 3 )) { - $attrEnd = FALSE; - break; // an URI with a portnr!! - } - } - } - if( $attrEnd) { - $line = substr( $line, ( $cix + 1 )); - break; - } - $cix++; - } - if( '"' == $line[$cix] ) - $WithinQuotes = ( FALSE === $WithinQuotes ) ? TRUE : FALSE; - if( ';' == $line[$cix] ) - $attr[++$attrix] = null; - else - $attr[$attrix] .= $line[$cix]; - $cix++; - } - /* make attributes in array format */ - $propattr = array(); - foreach( $attr as $attribute ) { - $attrsplit = explode( '=', $attribute, 2 ); - if( 1 < count( $attrsplit )) - $propattr[$attrsplit[0]] = $attrsplit[1]; - else - $propattr[] = $attribute; - } - /* call setProperty( $propname.. . */ - switch( strtoupper( $propname )) { - case 'ATTENDEE': - foreach( $propattr as $pix => $attr ) { - if( !in_array( strtoupper( $pix ), array( 'MEMBER', 'DELEGATED-TO', 'DELEGATED-FROM' ))) - continue; - $attr2 = explode( ',', $attr ); - if( 1 < count( $attr2 )) - $propattr[$pix] = $attr2; - } - $this->setProperty( $propname, $line, $propattr ); - break; - case 'X-': - $propname = ( isset( $propname2 )) ? $propname2 : $propname; - unset( $propname2 ); - case 'CATEGORIES': - case 'RESOURCES': - if( FALSE !== strpos( $line, ',' )) { - $content = array( 0 => '' ); - $cix = $lix = 0; - while( FALSE !== substr( $line, $lix, 1 )) { - if(( ',' == $line[$lix] ) && ( "\\" != $line[( $lix - 1 )])) { - $cix++; - $content[$cix] = ''; - } - else - $content[$cix] .= $line[$lix]; - $lix++; - } - if( 1 < count( $content )) { - $content = array_values( $content ); - foreach( $content as $cix => $contentPart ) - $content[$cix] = iCalUtilityFunctions::_strunrep( $contentPart ); - $this->setProperty( $propname, $content, $propattr ); - break; - } - else - $line = reset( $content ); - } - case 'COMMENT': - case 'CONTACT': - case 'DESCRIPTION': - case 'LOCATION': - case 'SUMMARY': - if( empty( $line )) - $propattr = null; - $this->setProperty( $propname, iCalUtilityFunctions::_strunrep( $line ), $propattr ); - break; - case 'REQUEST-STATUS': - $values = explode( ';', $line, 3 ); - $values[1] = ( !isset( $values[1] )) ? null : iCalUtilityFunctions::_strunrep( $values[1] ); - $values[2] = ( !isset( $values[2] )) ? null : iCalUtilityFunctions::_strunrep( $values[2] ); - $this->setProperty( $propname - , $values[0] // statcode - , $values[1] // statdesc - , $values[2] // extdata - , $propattr ); - break; - case 'FREEBUSY': - $fbtype = ( isset( $propattr['FBTYPE'] )) ? $propattr['FBTYPE'] : ''; // force setting default, if missing - unset( $propattr['FBTYPE'] ); - $values = explode( ',', $line ); - foreach( $values as $vix => $value ) { - $value2 = explode( '/', $value ); - if( 1 < count( $value2 )) - $values[$vix] = $value2; - } - $this->setProperty( $propname, $fbtype, $values, $propattr ); - break; - case 'GEO': - $value = explode( ';', $line, 2 ); - if( 2 > count( $value )) - $value[1] = null; - $this->setProperty( $propname, $value[0], $value[1], $propattr ); - break; - case 'EXDATE': - $values = ( !empty( $line )) ? explode( ',', $line ) : null; - $this->setProperty( $propname, $values, $propattr ); - break; - case 'RDATE': - if( empty( $line )) { - $this->setProperty( $propname, $line, $propattr ); - break; - } - $values = explode( ',', $line ); - foreach( $values as $vix => $value ) { - $value2 = explode( '/', $value ); - if( 1 < count( $value2 )) - $values[$vix] = $value2; - } - $this->setProperty( $propname, $values, $propattr ); - break; - case 'EXRULE': - case 'RRULE': - $values = explode( ';', $line ); - $recur = array(); - foreach( $values as $value2 ) { - if( empty( $value2 )) - continue; // ;-char in ending position ??? - $value3 = explode( '=', $value2, 2 ); - $rulelabel = strtoupper( $value3[0] ); - switch( $rulelabel ) { - case 'BYDAY': { - $value4 = explode( ',', $value3[1] ); - if( 1 < count( $value4 )) { - foreach( $value4 as $v5ix => $value5 ) { - $value6 = array(); - $dayno = $dayname = null; - $value5 = trim( (string) $value5 ); - if(( ctype_alpha( substr( $value5, -1 ))) && - ( ctype_alpha( substr( $value5, -2, 1 )))) { - $dayname = substr( $value5, -2, 2 ); - if( 2 < strlen( $value5 )) - $dayno = substr( $value5, 0, ( strlen( $value5 ) - 2 )); - } - if( $dayno ) - $value6[] = $dayno; - if( $dayname ) - $value6['DAY'] = $dayname; - $value4[$v5ix] = $value6; - } - } - else { - $value4 = array(); - $dayno = $dayname = null; - $value5 = trim( (string) $value3[1] ); - if(( ctype_alpha( substr( $value5, -1 ))) && - ( ctype_alpha( substr( $value5, -2, 1 )))) { - $dayname = substr( $value5, -2, 2 ); - if( 2 < strlen( $value5 )) - $dayno = substr( $value5, 0, ( strlen( $value5 ) - 2 )); - } - if( $dayno ) - $value4[] = $dayno; - if( $dayname ) - $value4['DAY'] = $dayname; - } - $recur[$rulelabel] = $value4; - break; - } - default: { - $value4 = explode( ',', $value3[1] ); - if( 1 < count( $value4 )) - $value3[1] = $value4; - $recur[$rulelabel] = $value3[1]; - break; - } - } // end - switch $rulelabel - } // end - foreach( $values.. . - $this->setProperty( $propname, $recur, $propattr ); - break; - case 'ACTION': - case 'CLASSIFICATION': - case 'STATUS': - case 'TRANSP': - case 'UID': - case 'TZID': - case 'RELATED-TO': - case 'TZNAME': - $line = iCalUtilityFunctions::_strunrep( $line ); - default: - $this->setProperty( $propname, $line, $propattr ); - break; - } // end switch( $propname.. . - } // end - foreach( $proprows.. . - unset( $unparsedtext, $this->unparsed, $proprows ); - if( isset( $this->components ) && is_array( $this->components ) && ( 0 < count( $this->components ))) { - $ckeys = array_keys( $this->components ); - foreach( $ckeys as $ckey ) { - if( !empty( $this->components[$ckey] ) && !empty( $this->components[$ckey]->unparsed )) { - $this->components[$ckey]->parse(); - } - } - } - return TRUE; - } -/*********************************************************************************/ -/*********************************************************************************/ -/** - * return a copy of this component - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.15.4 - 2012-10-18 - * @return object - */ - function copy() { - return unserialize( serialize( $this )); - } -/*********************************************************************************/ -/*********************************************************************************/ -/** - * delete calendar subcomponent from component container - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.8.8 - 2011-03-15 - * @param mixed $arg1 ordno / component type / component uid - * @param mixed $arg2 optional, ordno if arg1 = component type - * @return void - */ - function deleteComponent( $arg1, $arg2=FALSE ) { - if( !isset( $this->components )) return FALSE; - $argType = $index = null; - if ( ctype_digit( (string) $arg1 )) { - $argType = 'INDEX'; - $index = (int) $arg1 - 1; - } - elseif(( strlen( $arg1 ) <= strlen( 'vfreebusy' )) && ( FALSE === strpos( $arg1, '@' ))) { - $argType = strtolower( $arg1 ); - $index = ( !empty( $arg2 ) && ctype_digit( (string) $arg2 )) ? (( int ) $arg2 - 1 ) : 0; - } - $cix2dC = 0; - foreach ( $this->components as $cix => $component) { - if( empty( $component )) continue; - if(( 'INDEX' == $argType ) && ( $index == $cix )) { - unset( $this->components[$cix] ); - return TRUE; - } - elseif( $argType == $component->objName ) { - if( $index == $cix2dC ) { - unset( $this->components[$cix] ); - return TRUE; - } - $cix2dC++; - } - elseif( !$argType && ($arg1 == $component->getProperty( 'uid' ))) { - unset( $this->components[$cix] ); - return TRUE; - } - } - return FALSE; - } -/** - * get calendar component subcomponent from component container - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.8.8 - 2011-03-15 - * @param mixed $arg1 optional, ordno/component type/ component uid - * @param mixed $arg2 optional, ordno if arg1 = component type - * @return object - */ - function getComponent ( $arg1=FALSE, $arg2=FALSE ) { - if( !isset( $this->components )) return FALSE; - $index = $argType = null; - if ( !$arg1 ) { - $argType = 'INDEX'; - $index = $this->compix['INDEX'] = - ( isset( $this->compix['INDEX'] )) ? $this->compix['INDEX'] + 1 : 1; - } - elseif ( ctype_digit( (string) $arg1 )) { - $argType = 'INDEX'; - $index = (int) $arg1; - unset( $this->compix ); - } - elseif(( strlen( $arg1 ) <= strlen( 'vfreebusy' )) && ( FALSE === strpos( $arg1, '@' ))) { - unset( $this->compix['INDEX'] ); - $argType = strtolower( $arg1 ); - if( !$arg2 ) - $index = $this->compix[$argType] = ( isset( $this->compix[$argType] )) ? $this->compix[$argType] + 1 : 1; - else - $index = (int) $arg2; - } - $index -= 1; - $ckeys = array_keys( $this->components ); - if( !empty( $index) && ( $index > end( $ckeys ))) - return FALSE; - $cix2gC = 0; - foreach( $this->components as $cix => $component ) { - if( empty( $component )) continue; - if(( 'INDEX' == $argType ) && ( $index == $cix )) - return $component->copy(); - elseif( $argType == $component->objName ) { - if( $index == $cix2gC ) - return $component->copy(); - $cix2gC++; - } - elseif( !$argType && ( $arg1 == $component->getProperty( 'uid' ))) - return $component->copy(); - } - /* not found.. . */ - unset( $this->compix ); - return false; - } -/** - * add calendar component as subcomponent to container for subcomponents - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 1.x.x - 2007-04-24 - * @param object $component calendar component - * @return void - */ - function addSubComponent ( $component ) { - $this->setComponent( $component ); - } -/** - * create new calendar component subcomponent, already included within component - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.6.33 - 2011-01-03 - * @param string $compType subcomponent type - * @return object (reference) - */ - function & newComponent( $compType ) { - $config = $this->getConfig(); - $keys = array_keys( $this->components ); - $ix = end( $keys) + 1; - switch( strtoupper( $compType )) { - case 'ALARM': - case 'VALARM': - $this->components[$ix] = new valarm( $config ); - break; - case 'STANDARD': - array_unshift( $this->components, new vtimezone( 'STANDARD', $config )); - $ix = 0; - break; - case 'DAYLIGHT': - $this->components[$ix] = new vtimezone( 'DAYLIGHT', $config ); - break; - default: - return FALSE; - } - return $this->components[$ix]; - } -/** - * add calendar component as subcomponent to container for subcomponents - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.8.8 - 2011-03-15 - * @param object $component calendar component - * @param mixed $arg1 optional, ordno/component type/ component uid - * @param mixed $arg2 optional, ordno if arg1 = component type - * @return bool - */ - function setComponent( $component, $arg1=FALSE, $arg2=FALSE ) { - if( !isset( $this->components )) return FALSE; - $component->setConfig( $this->getConfig(), FALSE, TRUE ); - if( !in_array( $component->objName, array( 'valarm', 'vtimezone', 'standard', 'daylight' ))) { - /* make sure dtstamp and uid is set */ - $dummy = $component->getProperty( 'dtstamp' ); - $dummy = $component->getProperty( 'uid' ); - } - if( !$arg1 ) { // plain insert, last in chain - $this->components[] = $component->copy(); - return TRUE; - } - $argType = $index = null; - if ( ctype_digit( (string) $arg1 )) { // index insert/replace - $argType = 'INDEX'; - $index = (int) $arg1 - 1; - } - elseif( in_array( strtolower( $arg1 ), array( 'vevent', 'vtodo', 'vjournal', 'vfreebusy', 'valarm', 'vtimezone' ))) { - $argType = strtolower( $arg1 ); - $index = ( ctype_digit( (string) $arg2 )) ? ((int) $arg2) - 1 : 0; - } - // else if arg1 is set, arg1 must be an UID - $cix2sC = 0; - foreach ( $this->components as $cix => $component2 ) { - if( empty( $component2 )) continue; - if(( 'INDEX' == $argType ) && ( $index == $cix )) { // index insert/replace - $this->components[$cix] = $component->copy(); - return TRUE; - } - elseif( $argType == $component2->objName ) { // component Type index insert/replace - if( $index == $cix2sC ) { - $this->components[$cix] = $component->copy(); - return TRUE; - } - $cix2sC++; - } - elseif( !$argType && ( $arg1 == $component2->getProperty( 'uid' ))) { // UID insert/replace - $this->components[$cix] = $component->copy(); - return TRUE; - } - } - /* arg1=index and not found.. . insert at index .. .*/ - if( 'INDEX' == $argType ) { - $this->components[$index] = $component->copy(); - ksort( $this->components, SORT_NUMERIC ); - } - else /* not found.. . insert last in chain anyway .. .*/ - $this->components[] = $component->copy(); - return TRUE; - } -/** - * creates formatted output for subcomponents - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.11.20 - 2012-02-06 - * @param array $xcaldecl - * @return string - */ - function createSubComponent() { - $output = null; - if( 'vtimezone' == $this->objName ) { // sort subComponents, first standard, then daylight, in dtstart order - $stdarr = $dlarr = array(); - foreach( $this->components as $component ) { - if( empty( $component )) - continue; - $dt = $component->getProperty( 'dtstart' ); - $key = sprintf( '%04d%02d%02d%02d%02d%02d000', $dt['year'], $dt['month'], $dt['day'], $dt['hour'], $dt['min'], $dt['sec'] ); - if( 'standard' == $component->objName ) { - while( isset( $stdarr[$key] )) - $key += 1; - $stdarr[$key] = $component->copy(); - } - elseif( 'daylight' == $component->objName ) { - while( isset( $dlarr[$key] )) - $key += 1; - $dlarr[$key] = $component->copy(); - } - } // end foreach( $this->components as $component ) - $this->components = array(); - ksort( $stdarr, SORT_NUMERIC ); - foreach( $stdarr as $std ) - $this->components[] = $std->copy(); - unset( $stdarr ); - ksort( $dlarr, SORT_NUMERIC ); - foreach( $dlarr as $dl ) - $this->components[] = $dl->copy(); - unset( $dlarr ); - } // end if( 'vtimezone' == $this->objName ) - foreach( $this->components as $component ) { - $component->setConfig( $this->getConfig(), FALSE, TRUE ); - $output .= $component->createComponent( $this->xcaldecl ); - } - return $output; - } -} -/*********************************************************************************/ -/*********************************************************************************/ -/** - * class for calendar component VEVENT - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.5.1 - 2008-10-12 - */ -class vevent extends calendarComponent { - var $attach; - var $attendee; - var $categories; - var $comment; - var $contact; - var $class; - var $created; - var $description; - var $dtend; - var $dtstart; - var $duration; - var $exdate; - var $exrule; - var $geo; - var $lastmodified; - var $location; - var $organizer; - var $priority; - var $rdate; - var $recurrenceid; - var $relatedto; - var $requeststatus; - var $resources; - var $rrule; - var $sequence; - var $status; - var $summary; - var $transp; - var $url; - var $xprop; - // component subcomponents container - var $components; -/** - * constructor for calendar component VEVENT object - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.8.2 - 2011-05-01 - * @param array $config - * @return void - */ - function vevent( $config = array()) { - $this->calendarComponent(); - - $this->attach = ''; - $this->attendee = ''; - $this->categories = ''; - $this->class = ''; - $this->comment = ''; - $this->contact = ''; - $this->created = ''; - $this->description = ''; - $this->dtstart = ''; - $this->dtend = ''; - $this->duration = ''; - $this->exdate = ''; - $this->exrule = ''; - $this->geo = ''; - $this->lastmodified = ''; - $this->location = ''; - $this->organizer = ''; - $this->priority = ''; - $this->rdate = ''; - $this->recurrenceid = ''; - $this->relatedto = ''; - $this->requeststatus = ''; - $this->resources = ''; - $this->rrule = ''; - $this->sequence = ''; - $this->status = ''; - $this->summary = ''; - $this->transp = ''; - $this->url = ''; - $this->xprop = ''; - - $this->components = array(); - - if( defined( 'ICAL_LANG' ) && !isset( $config['language'] )) - $config['language'] = ICAL_LANG; - if( !isset( $config['allowEmpty'] )) $config['allowEmpty'] = TRUE; - if( !isset( $config['nl'] )) $config['nl'] = "\r\n"; - if( !isset( $config['format'] )) $config['format'] = 'iCal'; - if( !isset( $config['delimiter'] )) $config['delimiter'] = DIRECTORY_SEPARATOR; - $this->setConfig( $config ); - - } -/** - * create formatted output for calendar component VEVENT object instance - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.10.16 - 2011-10-28 - * @param array $xcaldecl - * @return string - */ - function createComponent( &$xcaldecl ) { - $objectname = $this->_createFormat(); - $component = $this->componentStart1.$objectname.$this->componentStart2.$this->nl; - $component .= $this->createUid(); - $component .= $this->createDtstamp(); - $component .= $this->createAttach(); - $component .= $this->createAttendee(); - $component .= $this->createCategories(); - $component .= $this->createComment(); - $component .= $this->createContact(); - $component .= $this->createClass(); - $component .= $this->createCreated(); - $component .= $this->createDescription(); - $component .= $this->createDtstart(); - $component .= $this->createDtend(); - $component .= $this->createDuration(); - $component .= $this->createExdate(); - $component .= $this->createExrule(); - $component .= $this->createGeo(); - $component .= $this->createLastModified(); - $component .= $this->createLocation(); - $component .= $this->createOrganizer(); - $component .= $this->createPriority(); - $component .= $this->createRdate(); - $component .= $this->createRrule(); - $component .= $this->createRelatedTo(); - $component .= $this->createRequestStatus(); - $component .= $this->createRecurrenceid(); - $component .= $this->createResources(); - $component .= $this->createSequence(); - $component .= $this->createStatus(); - $component .= $this->createSummary(); - $component .= $this->createTransp(); - $component .= $this->createUrl(); - $component .= $this->createXprop(); - $component .= $this->createSubComponent(); - $component .= $this->componentEnd1.$objectname.$this->componentEnd2; - if( is_array( $this->xcaldecl ) && ( 0 < count( $this->xcaldecl ))) { - foreach( $this->xcaldecl as $localxcaldecl ) - $xcaldecl[] = $localxcaldecl; - } - return $component; - } -} -/*********************************************************************************/ -/*********************************************************************************/ -/** - * class for calendar component VTODO - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.5.1 - 2008-10-12 - */ -class vtodo extends calendarComponent { - var $attach; - var $attendee; - var $categories; - var $comment; - var $completed; - var $contact; - var $class; - var $created; - var $description; - var $dtstart; - var $due; - var $duration; - var $exdate; - var $exrule; - var $geo; - var $lastmodified; - var $location; - var $organizer; - var $percentcomplete; - var $priority; - var $rdate; - var $recurrenceid; - var $relatedto; - var $requeststatus; - var $resources; - var $rrule; - var $sequence; - var $status; - var $summary; - var $url; - var $xprop; - // component subcomponents container - var $components; -/** - * constructor for calendar component VTODO object - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.8.2 - 2011-05-01 - * @param array $config - * @return void - */ - function vtodo( $config = array()) { - $this->calendarComponent(); - - $this->attach = ''; - $this->attendee = ''; - $this->categories = ''; - $this->class = ''; - $this->comment = ''; - $this->completed = ''; - $this->contact = ''; - $this->created = ''; - $this->description = ''; - $this->dtstart = ''; - $this->due = ''; - $this->duration = ''; - $this->exdate = ''; - $this->exrule = ''; - $this->geo = ''; - $this->lastmodified = ''; - $this->location = ''; - $this->organizer = ''; - $this->percentcomplete = ''; - $this->priority = ''; - $this->rdate = ''; - $this->recurrenceid = ''; - $this->relatedto = ''; - $this->requeststatus = ''; - $this->resources = ''; - $this->rrule = ''; - $this->sequence = ''; - $this->status = ''; - $this->summary = ''; - $this->url = ''; - $this->xprop = ''; - - $this->components = array(); - - if( defined( 'ICAL_LANG' ) && !isset( $config['language'] )) - $config['language'] = ICAL_LANG; - if( !isset( $config['allowEmpty'] )) $config['allowEmpty'] = TRUE; - if( !isset( $config['nl'] )) $config['nl'] = "\r\n"; - if( !isset( $config['format'] )) $config['format'] = 'iCal'; - if( !isset( $config['delimiter'] )) $config['delimiter'] = DIRECTORY_SEPARATOR; - $this->setConfig( $config ); - - } -/** - * create formatted output for calendar component VTODO object instance - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.5.1 - 2008-11-07 - * @param array $xcaldecl - * @return string - */ - function createComponent( &$xcaldecl ) { - $objectname = $this->_createFormat(); - $component = $this->componentStart1.$objectname.$this->componentStart2.$this->nl; - $component .= $this->createUid(); - $component .= $this->createDtstamp(); - $component .= $this->createAttach(); - $component .= $this->createAttendee(); - $component .= $this->createCategories(); - $component .= $this->createClass(); - $component .= $this->createComment(); - $component .= $this->createCompleted(); - $component .= $this->createContact(); - $component .= $this->createCreated(); - $component .= $this->createDescription(); - $component .= $this->createDtstart(); - $component .= $this->createDue(); - $component .= $this->createDuration(); - $component .= $this->createExdate(); - $component .= $this->createExrule(); - $component .= $this->createGeo(); - $component .= $this->createLastModified(); - $component .= $this->createLocation(); - $component .= $this->createOrganizer(); - $component .= $this->createPercentComplete(); - $component .= $this->createPriority(); - $component .= $this->createRdate(); - $component .= $this->createRelatedTo(); - $component .= $this->createRequestStatus(); - $component .= $this->createRecurrenceid(); - $component .= $this->createResources(); - $component .= $this->createRrule(); - $component .= $this->createSequence(); - $component .= $this->createStatus(); - $component .= $this->createSummary(); - $component .= $this->createUrl(); - $component .= $this->createXprop(); - $component .= $this->createSubComponent(); - $component .= $this->componentEnd1.$objectname.$this->componentEnd2; - if( is_array( $this->xcaldecl ) && ( 0 < count( $this->xcaldecl ))) { - foreach( $this->xcaldecl as $localxcaldecl ) - $xcaldecl[] = $localxcaldecl; - } - return $component; - } -} -/*********************************************************************************/ -/*********************************************************************************/ -/** - * class for calendar component VJOURNAL - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.5.1 - 2008-10-12 - */ -class vjournal extends calendarComponent { - var $attach; - var $attendee; - var $categories; - var $comment; - var $contact; - var $class; - var $created; - var $description; - var $dtstart; - var $exdate; - var $exrule; - var $lastmodified; - var $organizer; - var $rdate; - var $recurrenceid; - var $relatedto; - var $requeststatus; - var $rrule; - var $sequence; - var $status; - var $summary; - var $url; - var $xprop; -/** - * constructor for calendar component VJOURNAL object - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.8.2 - 2011-05-01 - * @param array $config - * @return void - */ - function vjournal( $config = array()) { - $this->calendarComponent(); - - $this->attach = ''; - $this->attendee = ''; - $this->categories = ''; - $this->class = ''; - $this->comment = ''; - $this->contact = ''; - $this->created = ''; - $this->description = ''; - $this->dtstart = ''; - $this->exdate = ''; - $this->exrule = ''; - $this->lastmodified = ''; - $this->organizer = ''; - $this->rdate = ''; - $this->recurrenceid = ''; - $this->relatedto = ''; - $this->requeststatus = ''; - $this->rrule = ''; - $this->sequence = ''; - $this->status = ''; - $this->summary = ''; - $this->url = ''; - $this->xprop = ''; - - if( defined( 'ICAL_LANG' ) && !isset( $config['language'] )) - $config['language'] = ICAL_LANG; - if( !isset( $config['allowEmpty'] )) $config['allowEmpty'] = TRUE; - if( !isset( $config['nl'] )) $config['nl'] = "\r\n"; - if( !isset( $config['format'] )) $config['format'] = 'iCal'; - if( !isset( $config['delimiter'] )) $config['delimiter'] = DIRECTORY_SEPARATOR; - $this->setConfig( $config ); - - } -/** - * create formatted output for calendar component VJOURNAL object instance - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.5.1 - 2008-10-12 - * @param array $xcaldecl - * @return string - */ - function createComponent( &$xcaldecl ) { - $objectname = $this->_createFormat(); - $component = $this->componentStart1.$objectname.$this->componentStart2.$this->nl; - $component .= $this->createUid(); - $component .= $this->createDtstamp(); - $component .= $this->createAttach(); - $component .= $this->createAttendee(); - $component .= $this->createCategories(); - $component .= $this->createClass(); - $component .= $this->createComment(); - $component .= $this->createContact(); - $component .= $this->createCreated(); - $component .= $this->createDescription(); - $component .= $this->createDtstart(); - $component .= $this->createExdate(); - $component .= $this->createExrule(); - $component .= $this->createLastModified(); - $component .= $this->createOrganizer(); - $component .= $this->createRdate(); - $component .= $this->createRequestStatus(); - $component .= $this->createRecurrenceid(); - $component .= $this->createRelatedTo(); - $component .= $this->createRrule(); - $component .= $this->createSequence(); - $component .= $this->createStatus(); - $component .= $this->createSummary(); - $component .= $this->createUrl(); - $component .= $this->createXprop(); - $component .= $this->componentEnd1.$objectname.$this->componentEnd2; - if( is_array( $this->xcaldecl ) && ( 0 < count( $this->xcaldecl ))) { - foreach( $this->xcaldecl as $localxcaldecl ) - $xcaldecl[] = $localxcaldecl; - } - return $component; - } -} -/*********************************************************************************/ -/*********************************************************************************/ -/** - * class for calendar component VFREEBUSY - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.5.1 - 2008-10-12 - */ -class vfreebusy extends calendarComponent { - var $attendee; - var $comment; - var $contact; - var $dtend; - var $dtstart; - var $duration; - var $freebusy; - var $organizer; - var $requeststatus; - var $url; - var $xprop; - // component subcomponents container - var $components; -/** - * constructor for calendar component VFREEBUSY object - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.8.2 - 2011-05-01 - * @param array $config - * @return void - */ - function vfreebusy( $config = array()) { - $this->calendarComponent(); - - $this->attendee = ''; - $this->comment = ''; - $this->contact = ''; - $this->dtend = ''; - $this->dtstart = ''; - $this->duration = ''; - $this->freebusy = ''; - $this->organizer = ''; - $this->requeststatus = ''; - $this->url = ''; - $this->xprop = ''; - - if( defined( 'ICAL_LANG' ) && !isset( $config['language'] )) - $config['language'] = ICAL_LANG; - if( !isset( $config['allowEmpty'] )) $config['allowEmpty'] = TRUE; - if( !isset( $config['nl'] )) $config['nl'] = "\r\n"; - if( !isset( $config['format'] )) $config['format'] = 'iCal'; - if( !isset( $config['delimiter'] )) $config['delimiter'] = DIRECTORY_SEPARATOR; - $this->setConfig( $config ); - - } -/** - * create formatted output for calendar component VFREEBUSY object instance - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.3.1 - 2007-11-19 - * @param array $xcaldecl - * @return string - */ - function createComponent( &$xcaldecl ) { - $objectname = $this->_createFormat(); - $component = $this->componentStart1.$objectname.$this->componentStart2.$this->nl; - $component .= $this->createUid(); - $component .= $this->createDtstamp(); - $component .= $this->createAttendee(); - $component .= $this->createComment(); - $component .= $this->createContact(); - $component .= $this->createDtstart(); - $component .= $this->createDtend(); - $component .= $this->createDuration(); - $component .= $this->createFreebusy(); - $component .= $this->createOrganizer(); - $component .= $this->createRequestStatus(); - $component .= $this->createUrl(); - $component .= $this->createXprop(); - $component .= $this->componentEnd1.$objectname.$this->componentEnd2; - if( is_array( $this->xcaldecl ) && ( 0 < count( $this->xcaldecl ))) { - foreach( $this->xcaldecl as $localxcaldecl ) - $xcaldecl[] = $localxcaldecl; - } - return $component; - } -} -/*********************************************************************************/ -/*********************************************************************************/ -/** - * class for calendar component VALARM - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.5.1 - 2008-10-12 - */ -class valarm extends calendarComponent { - var $action; - var $attach; - var $attendee; - var $description; - var $duration; - var $repeat; - var $summary; - var $trigger; - var $xprop; -/** - * constructor for calendar component VALARM object - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.8.2 - 2011-05-01 - * @param array $config - * @return void - */ - function valarm( $config = array()) { - $this->calendarComponent(); - - $this->action = ''; - $this->attach = ''; - $this->attendee = ''; - $this->description = ''; - $this->duration = ''; - $this->repeat = ''; - $this->summary = ''; - $this->trigger = ''; - $this->xprop = ''; - - if( defined( 'ICAL_LANG' ) && !isset( $config['language'] )) - $config['language'] = ICAL_LANG; - if( !isset( $config['allowEmpty'] )) $config['allowEmpty'] = TRUE; - if( !isset( $config['nl'] )) $config['nl'] = "\r\n"; - if( !isset( $config['format'] )) $config['format'] = 'iCal'; - if( !isset( $config['delimiter'] )) $config['delimiter'] = DIRECTORY_SEPARATOR; - $this->setConfig( $config ); - - } -/** - * create formatted output for calendar component VALARM object instance - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.5.1 - 2008-10-22 - * @param array $xcaldecl - * @return string - */ - function createComponent( &$xcaldecl ) { - $objectname = $this->_createFormat(); - $component = $this->componentStart1.$objectname.$this->componentStart2.$this->nl; - $component .= $this->createAction(); - $component .= $this->createAttach(); - $component .= $this->createAttendee(); - $component .= $this->createDescription(); - $component .= $this->createDuration(); - $component .= $this->createRepeat(); - $component .= $this->createSummary(); - $component .= $this->createTrigger(); - $component .= $this->createXprop(); - $component .= $this->componentEnd1.$objectname.$this->componentEnd2; - if( is_array( $this->xcaldecl ) && ( 0 < count( $this->xcaldecl ))) { - foreach( $this->xcaldecl as $localxcaldecl ) - $xcaldecl[] = $localxcaldecl; - } - return $component; - } -} -/********************************************************************************** -/*********************************************************************************/ -/** - * class for calendar component VTIMEZONE - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.5.1 - 2008-10-12 - */ -class vtimezone extends calendarComponent { - var $timezonetype; - - var $comment; - var $dtstart; - var $lastmodified; - var $rdate; - var $rrule; - var $tzid; - var $tzname; - var $tzoffsetfrom; - var $tzoffsetto; - var $tzurl; - var $xprop; - // component subcomponents container - var $components; -/** - * constructor for calendar component VTIMEZONE object - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.8.2 - 2011-05-01 - * @param mixed $timezonetype optional, default FALSE ( STANDARD / DAYLIGHT ) - * @param array $config - * @return void - */ - function vtimezone( $timezonetype=FALSE, $config = array()) { - if( is_array( $timezonetype )) { - $config = $timezonetype; - $timezonetype = FALSE; - } - if( !$timezonetype ) - $this->timezonetype = 'VTIMEZONE'; - else - $this->timezonetype = strtoupper( $timezonetype ); - $this->calendarComponent(); - - $this->comment = ''; - $this->dtstart = ''; - $this->lastmodified = ''; - $this->rdate = ''; - $this->rrule = ''; - $this->tzid = ''; - $this->tzname = ''; - $this->tzoffsetfrom = ''; - $this->tzoffsetto = ''; - $this->tzurl = ''; - $this->xprop = ''; - - $this->components = array(); - - if( defined( 'ICAL_LANG' ) && !isset( $config['language'] )) - $config['language'] = ICAL_LANG; - if( !isset( $config['allowEmpty'] )) $config['allowEmpty'] = TRUE; - if( !isset( $config['nl'] )) $config['nl'] = "\r\n"; - if( !isset( $config['format'] )) $config['format'] = 'iCal'; - if( !isset( $config['delimiter'] )) $config['delimiter'] = DIRECTORY_SEPARATOR; - $this->setConfig( $config ); - - } -/** - * create formatted output for calendar component VTIMEZONE object instance - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.5.1 - 2008-10-25 - * @param array $xcaldecl - * @return string - */ - function createComponent( &$xcaldecl ) { - $objectname = $this->_createFormat(); - $component = $this->componentStart1.$objectname.$this->componentStart2.$this->nl; - $component .= $this->createTzid(); - $component .= $this->createLastModified(); - $component .= $this->createTzurl(); - $component .= $this->createDtstart(); - $component .= $this->createTzoffsetfrom(); - $component .= $this->createTzoffsetto(); - $component .= $this->createComment(); - $component .= $this->createRdate(); - $component .= $this->createRrule(); - $component .= $this->createTzname(); - $component .= $this->createXprop(); - $component .= $this->createSubComponent(); - $component .= $this->componentEnd1.$objectname.$this->componentEnd2; - if( is_array( $this->xcaldecl ) && ( 0 < count( $this->xcaldecl ))) { - foreach( $this->xcaldecl as $localxcaldecl ) - $xcaldecl[] = $localxcaldecl; - } - return $component; - } -} -/*********************************************************************************/ -/*********************************************************************************/ -/** - * moving all utility (static) functions to a utility class - * 20111223 - move iCalUtilityFunctions class to the end of the iCalcreator class file - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.10.1 - 2011-07-16 - * - */ -class iCalUtilityFunctions { - // Store the single instance of iCalUtilityFunctions - private static $m_pInstance; - - // Private constructor to limit object instantiation to within the class - private function __construct() { - $m_pInstance = FALSE; - } - - // Getter method for creating/returning the single instance of this class - public static function getInstance() { - if (!self::$m_pInstance) - self::$m_pInstance = new iCalUtilityFunctions(); - - return self::$m_pInstance; - } -/** - * ensures internal date-time/date format (keyed array) for an input date-time/date array (keyed or unkeyed) - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.14.1 - 2012-09-27 - * @param array $datetime - * @param int $parno optional, default FALSE - * @return array - */ - public static function _date_time_array( $datetime, $parno=FALSE ) { - return iCalUtilityFunctions::_chkDateArr( $datetime, $parno ); - } - public static function _chkDateArr( $datetime, $parno=FALSE ) { - $output = array(); - foreach( $datetime as $dateKey => $datePart ) { - switch ( $dateKey ) { - case '0': case 'year': $output['year'] = $datePart; break; - case '1': case 'month': $output['month'] = $datePart; break; - case '2': case 'day': $output['day'] = $datePart; break; - } - if( 3 != $parno ) { - switch ( $dateKey ) { - case '0': - case '1': - case '2': break; - case '3': case 'hour': $output['hour'] = $datePart; break; - case '4': case 'min' : $output['min'] = $datePart; break; - case '5': case 'sec' : $output['sec'] = $datePart; break; - case '6': case 'tz' : $output['tz'] = $datePart; break; - } - } - } - if( 3 != $parno ) { - if( !isset( $output['hour'] )) $output['hour'] = 0; - if( !isset( $output['min'] )) $output['min'] = 0; - if( !isset( $output['sec'] )) $output['sec'] = 0; - if( isset( $output['tz'] ) && - (( '+0000' == $output['tz'] ) || ( '-0000' == $output['tz'] ) || ( '+000000' == $output['tz'] ) || ( '-000000' == $output['tz'] ))) - $output['tz'] = 'Z'; - } - return $output; - } -/** - * check date(-time) and params arrays for an opt. timezone and if it is a DATE-TIME or DATE (updates $parno and params) - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.10.30 - 2012-01-16 - * @param array $date, date to check - * @param int $parno, no of date parts (i.e. year, month.. .) - * @param array $params, property parameters - * @return void - */ - public static function _chkdatecfg( $theDate, & $parno, & $params ) { - if( isset( $params['TZID'] )) - $parno = 6; - elseif( isset( $params['VALUE'] ) && ( 'DATE' == $params['VALUE'] )) - $parno = 3; - else { - if( isset( $params['VALUE'] ) && ( 'PERIOD' == $params['VALUE'] )) - $parno = 7; - if( is_array( $theDate )) { - if( isset( $theDate['timestamp'] )) - $tzid = ( isset( $theDate['tz'] )) ? $theDate['tz'] : null; - else - $tzid = ( isset( $theDate['tz'] )) ? $theDate['tz'] : ( 7 == count( $theDate )) ? end( $theDate ) : null; - if( !empty( $tzid )) { - $parno = 7; - if( !iCalUtilityFunctions::_isOffset( $tzid )) - $params['TZID'] = $tzid; // save only timezone - } - elseif( !$parno && ( 3 == count( $theDate )) && - ( isset( $params['VALUE'] ) && ( 'DATE' == $params['VALUE'] ))) - $parno = 3; - else - $parno = 6; - } - else { // string - $date = trim( $theDate ); - if( 'Z' == substr( $date, -1 )) - $parno = 7; // UTC DATE-TIME - elseif((( 8 == strlen( $date ) && ctype_digit( $date )) || ( 11 >= strlen( $date ))) && - ( !isset( $params['VALUE'] ) || !in_array( $params['VALUE'], array( 'DATE-TIME', 'PERIOD' )))) - $parno = 3; // DATE - $date = iCalUtilityFunctions::_strdate2date( $date, $parno ); - unset( $date['unparsedtext'] ); - if( !empty( $date['tz'] )) { - $parno = 7; - if( !iCalUtilityFunctions::_isOffset( $date['tz'] )) - $params['TZID'] = $date['tz']; // save only timezone - } - elseif( empty( $parno )) - $parno = 6; - } - if( isset( $params['TZID'] )) - $parno = 6; - } - } -/** - * vcalendar sort callback function - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.16.2 - 2012-12-17 - * @param array $a - * @param array $b - * @return int - */ - public static function _cmpfcn( $a, $b ) { - if( empty( $a )) return -1; - if( empty( $b )) return 1; - if( 'vtimezone' == $a->objName ) { - if( 'vtimezone' != $b->objName ) return -1; - elseif( $a->srtk[0] <= $b->srtk[0] ) return -1; - else return 1; - } - elseif( 'vtimezone' == $b->objName ) return 1; - $sortkeys = array( 'year', 'month', 'day', 'hour', 'min', 'sec' ); - for( $k = 0; $k < 4 ; $k++ ) { - if( empty( $a->srtk[$k] )) return -1; - elseif( empty( $b->srtk[$k] )) return 1; - if( is_array( $a->srtk[$k] )) { - if( is_array( $b->srtk[$k] )) { - foreach( $sortkeys as $key ) { - if ( !isset( $a->srtk[$k][$key] )) return -1; - elseif( !isset( $b->srtk[$k][$key] )) return 1; - if ( empty( $a->srtk[$k][$key] )) return -1; - elseif( empty( $b->srtk[$k][$key] )) return 1; - if ( $a->srtk[$k][$key] == $b->srtk[$k][$key]) - continue; - if (( (int) $a->srtk[$k][$key] ) < ((int) $b->srtk[$k][$key] )) - return -1; - elseif(( (int) $a->srtk[$k][$key] ) > ((int) $b->srtk[$k][$key] )) - return 1; - } - } - else return -1; - } - elseif( is_array( $b->srtk[$k] )) return 1; - elseif( $a->srtk[$k] < $b->srtk[$k] ) return -1; - elseif( $a->srtk[$k] > $b->srtk[$k] ) return 1; - } - return 0; - } -/** - * byte oriented line folding fix - * - * remove any line-endings that may include spaces or tabs - * and convert all line endings (iCal default '\r\n'), - * takes care of '\r\n', '\r' and '\n' and mixed '\r\n'+'\r', '\r\n'+'\n' - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.12.17 - 2012-07-12 - * @param string $text - * @param string $nl - * @return string - */ - public static function convEolChar( & $text, $nl ) { - $outp = ''; - $cix = 0; - while( isset( $text[$cix] )) { - if( isset( $text[$cix + 2] ) && ( "\r" == $text[$cix] ) && ( "\n" == $text[$cix + 1] ) && - (( " " == $text[$cix + 2] ) || ( "\t" == $text[$cix + 2] ))) // 2 pos eolchar + ' ' or '\t' - $cix += 2; // skip 3 - elseif( isset( $text[$cix + 1] ) && ( "\r" == $text[$cix] ) && ( "\n" == $text[$cix + 1] )) { - $outp .= $nl; // 2 pos eolchar - $cix += 1; // replace with $nl - } - elseif( isset( $text[$cix + 1] ) && (( "\r" == $text[$cix] ) || ( "\n" == $text[$cix] )) && - (( " " == $text[$cix + 1] ) || ( "\t" == $text[$cix + 1] ))) // 1 pos eolchar + ' ' or '\t' - $cix += 1; // skip 2 - elseif(( "\r" == $text[$cix] ) || ( "\n" == $text[$cix] )) // 1 pos eolchar - $outp .= $nl; // replace with $nl - else - $outp .= $text[$cix]; // add any other byte - $cix += 1; - } - return $outp; - } -/** - * create a calendar timezone and standard/daylight components - * - * Result when 'Europe/Stockholm' and no from/to arguments is used as timezone: - * - * BEGIN:VTIMEZONE - * TZID:Europe/Stockholm - * BEGIN:STANDARD - * DTSTART:20101031T020000 - * TZOFFSETFROM:+0200 - * TZOFFSETTO:+0100 - * TZNAME:CET - * END:STANDARD - * BEGIN:DAYLIGHT - * DTSTART:20100328T030000 - * TZOFFSETFROM:+0100 - * TZOFFSETTO:+0200 - * TZNAME:CEST - * END:DAYLIGHT - * END:VTIMEZONE - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.16.1 - 2012-11-26 - * Generates components for all transitions in a date range, based on contribution by Yitzchok Lavi - * Additional changes jpirkey - * @param object $calendar, reference to an iCalcreator calendar instance - * @param string $timezone, a PHP5 (DateTimeZone) valid timezone - * @param array $xProp, *[x-propName => x-propValue], optional - * @param int $from a unix timestamp - * @param int $to a unix timestamp - * @return bool - */ - public static function createTimezone( & $calendar, $timezone, $xProp=array(), $from=null, $to=null ) { - if( empty( $timezone )) - return FALSE; - if( !empty( $from ) && !is_int( $from )) - return FALSE; - if( !empty( $to ) && !is_int( $to )) - return FALSE; - try { - $dtz = new DateTimeZone( $timezone ); - $transitions = $dtz->getTransitions(); - $utcTz = new DateTimeZone( 'UTC' ); - } - catch( Exception $e ) { return FALSE; } - if( empty( $to )) { - $dates = array_keys( $calendar->getProperty( 'dtstart' )); - if( empty( $dates )) - $dates = array( date( 'Ymd' )); - } - if( !empty( $from )) - $dateFrom = new DateTime( "@$from" ); // set lowest date (UTC) - else { - $from = reset( $dates ); // set lowest date to the lowest dtstart date - $dateFrom = new DateTime( $from.'T000000', $dtz ); - $dateFrom->modify( '-1 month' ); // set $dateFrom to one month before the lowest date - $dateFrom->setTimezone( $utcTz ); // convert local date to UTC - } - $dateFromYmd = $dateFrom->format('Y-m-d' ); - if( !empty( $to )) - $dateTo = new DateTime( "@$to" ); // set end date (UTC) - else { - $to = end( $dates ); // set highest date to the highest dtstart date - $dateTo = new DateTime( $to.'T235959', $dtz ); - $dateTo->modify( '+1 year' ); // set $dateTo to one year after the highest date - $dateTo->setTimezone( $utcTz ); // convert local date to UTC - } - $dateToYmd = $dateTo->format('Y-m-d' ); - unset( $dtz ); - $transTemp = array(); - $prevOffsetfrom = 0; - $stdIx = $dlghtIx = null; - $prevTrans = FALSE; - foreach( $transitions as $tix => $trans ) { // all transitions in date-time order!! - $date = new DateTime( "@{$trans['ts']}" ); // set transition date (UTC) - $transDateYmd = $date->format('Y-m-d' ); - if ( $transDateYmd < $dateFromYmd ) { - $prevOffsetfrom = $trans['offset']; // previous trans offset will be 'next' trans offsetFrom - $prevTrans = $trans; // save it in case we don't find any that match - $prevTrans['offsetfrom'] = ( 0 < $tix ) ? $transitions[$tix-1]['offset'] : 0; - continue; - } - if( $transDateYmd > $dateToYmd ) - break; // loop always (?) breaks here - if( !empty( $prevOffsetfrom ) || ( 0 == $prevOffsetfrom )) { - $trans['offsetfrom'] = $prevOffsetfrom; // i.e. set previous offsetto as offsetFrom - $date->modify( $trans['offsetfrom'].'seconds' ); // convert utc date to local date - $d = $date->format( 'Y-n-j-G-i-s' ); // set date to array to ease up dtstart and (opt) rdate setting - $d = explode( '-', $d ); - $trans['time'] = array( 'year' => $d[0], 'month' => $d[1], 'day' => $d[2], 'hour' => $d[3], 'min' => $d[4], 'sec' => $d[5] ); - } - $prevOffsetfrom = $trans['offset']; - if( TRUE !== $trans['isdst'] ) { // standard timezone - if( !empty( $stdIx ) && isset( $transTemp[$stdIx]['offsetfrom'] ) && // check for any repeating rdate's (in order) - ( $transTemp[$stdIx]['abbr'] == $trans['abbr'] ) && - ( $transTemp[$stdIx]['offsetfrom'] == $trans['offsetfrom'] ) && - ( $transTemp[$stdIx]['offset'] == $trans['offset'] )) { - $transTemp[$stdIx]['rdate'][] = $trans['time']; - continue; - } - $stdIx = $tix; - } // end standard timezone - else { // daylight timezone - if( !empty( $dlghtIx ) && isset( $transTemp[$dlghtIx]['offsetfrom'] ) && // check for any repeating rdate's (in order) - ( $transTemp[$dlghtIx]['abbr'] == $trans['abbr'] ) && - ( $transTemp[$dlghtIx]['offsetfrom'] == $trans['offsetfrom'] ) && - ( $transTemp[$dlghtIx]['offset'] == $trans['offset'] )) { - $transTemp[$dlghtIx]['rdate'][] = $trans['time']; - continue; - } - $dlghtIx = $tix; - } // end daylight timezone - $transTemp[$tix] = $trans; - } // end foreach( $transitions as $tix => $trans ) - $tz = & $calendar->newComponent( 'vtimezone' ); - $tz->setproperty( 'tzid', $timezone ); - if( !empty( $xProp )) { - foreach( $xProp as $xPropName => $xPropValue ) - if( 'x-' == strtolower( substr( $xPropName, 0, 2 ))) - $tz->setproperty( $xPropName, $xPropValue ); - } - if( empty( $transTemp )) { // if no match found - if( $prevTrans ) { // then we use the last transition (before startdate) for the tz info - $date = new DateTime( "@{$prevTrans['ts']}" ); // set transition date (UTC) - $date->modify( $prevTrans['offsetfrom'].'seconds' ); // convert utc date to local date - $d = $date->format( 'Y-n-j-G-i-s' ); // set date to array to ease up dtstart setting - $d = explode( '-', $d ); - $prevTrans['time'] = array( 'year' => $d[0], 'month' => $d[1], 'day' => $d[2], 'hour' => $d[3], 'min' => $d[4], 'sec' => $d[5] ); - $transTemp[0] = $prevTrans; - } - else { // or we use the timezone identifier to BUILD the standard tz info (?) - $date = new DateTime( 'now', new DateTimeZone( $timezone )); - $transTemp[0] = array( 'time' => $date->format( 'Y-m-d\TH:i:s O' ) - , 'offset' => $date->format( 'Z' ) - , 'offsetfrom' => $date->format( 'Z' ) - , 'isdst' => FALSE ); - } - } - unset( $transitions, $date, $prevTrans ); - foreach( $transTemp as $tix => $trans ) { - $type = ( TRUE !== $trans['isdst'] ) ? 'standard' : 'daylight'; - $scomp = & $tz->newComponent( $type ); - $scomp->setProperty( 'dtstart', $trans['time'] ); -// $scomp->setProperty( 'x-utc-timestamp', $tix.' : '.$trans['ts'] ); // test ### - if( !empty( $trans['abbr'] )) - $scomp->setProperty( 'tzname', $trans['abbr'] ); - if( isset( $trans['offsetfrom'] )) - $scomp->setProperty( 'tzoffsetfrom', iCalUtilityFunctions::offsetSec2His( $trans['offsetfrom'] )); - $scomp->setProperty( 'tzoffsetto', iCalUtilityFunctions::offsetSec2His( $trans['offset'] )); - if( isset( $trans['rdate'] )) - $scomp->setProperty( 'RDATE', $trans['rdate'] ); - } - return TRUE; - } -/** - * creates formatted output for calendar component property data value type date/date-time - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.14.1 - 2012-09-17 - * @param array $datetime - * @param int $parno, optional, default 6 - * @return string - */ - public static function _format_date_time( $datetime, $parno=6 ) { - return iCalUtilityFunctions::_date2strdate( $datetime, $parno ); - } - public static function _date2strdate( $datetime, $parno=6 ) { - if( !isset( $datetime['year'] ) && - !isset( $datetime['month'] ) && - !isset( $datetime['day'] ) && - !isset( $datetime['hour'] ) && - !isset( $datetime['min'] ) && - !isset( $datetime['sec'] )) - return; - $output = null; - foreach( $datetime as $dkey => & $dvalue ) - if( 'tz' != $dkey ) $dvalue = (integer) $dvalue; - $output = sprintf( '%04d%02d%02d', $datetime['year'], $datetime['month'], $datetime['day'] ); - if( 3 == $parno ) - return $output; - if( !isset( $datetime['hour'] )) $datetime['hour'] = 0; - if( !isset( $datetime['min'] )) $datetime['min'] = 0; - if( !isset( $datetime['sec'] )) $datetime['sec'] = 0; - $output .= sprintf( 'T%02d%02d%02d', $datetime['hour'], $datetime['min'], $datetime['sec'] ); - if( isset( $datetime['tz'] ) && ( '' < trim( $datetime['tz'] ))) { - $datetime['tz'] = trim( $datetime['tz'] ); - if( 'Z' == $datetime['tz'] ) - $parno = 7; - elseif( iCalUtilityFunctions::_isOffset( $datetime['tz'] )) { - $parno = 7; - $offset = iCalUtilityFunctions::_tz2offset( $datetime['tz'] ); - try { - $d = new DateTime( $output, new DateTimeZone( 'UTC' )); - if( 0 != $offset ) // adjust för offset - $d->modify( "$offset seconds" ); - $output = $d->format( 'Ymd\THis' ); - } - catch( Exception $e ) { - $output = date( 'Ymd\THis', mktime( $datetime['hour'], $datetime['min'], ($datetime['sec'] - $offset), $datetime['month'], $datetime['day'], $datetime['year'] )); - } - } - if( 7 == $parno ) - $output .= 'Z'; - } - return $output; - } -/** - * convert a date/datetime (array) to timestamp - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.14.1 - 2012-09-29 - * @param array $datetime datetime(/date) - * @param string $wtz timezone - * @return int - */ - public static function _date2timestamp( $datetime, $wtz=null ) { - if( !isset( $datetime['hour'] )) $datetime['hour'] = 0; - if( !isset( $datetime['min'] )) $datetime['min'] = 0; - if( !isset( $datetime['sec'] )) $datetime['sec'] = 0; - if( empty( $wtz ) && ( !isset( $datetime['tz'] ) || empty( $datetime['tz'] ))) - return mktime( $datetime['hour'], $datetime['min'], $datetime['sec'], $datetime['month'], $datetime['day'], $datetime['year'] ); - $output = $offset = 0; - if( empty( $wtz )) { - if( iCalUtilityFunctions::_isOffset( $datetime['tz'] )) { - $offset = iCalUtilityFunctions::_tz2offset( $datetime['tz'] ) * -1; - $wtz = 'UTC'; - } - else - $wtz = $datetime['tz']; - } - if(( 'Z' == $wtz ) || ( 'GMT' == strtoupper( $wtz ))) - $wtz = 'UTC'; - try { - $strdate = sprintf( '%04d-%02d-%02d %02d:%02d:%02d', $datetime['year'], $datetime['month'], $datetime['day'], $datetime['hour'], $datetime['min'], $datetime['sec'] ); - $d = new DateTime( $strdate, new DateTimeZone( $wtz )); - if( 0 != $offset ) // adjust for offset - $d->modify( $offset.' seconds' ); - $output = $d->format( 'U' ); - unset( $d ); - } - catch( Exception $e ) { - $output = mktime( $datetime['hour'], $datetime['min'], $datetime['sec'], $datetime['month'], $datetime['day'], $datetime['year'] ); - } - return $output; - } -/** - * ensures internal duration format for input in array format - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.14.1 - 2012-09-25 - * @param array $duration - * @return array - */ - public static function _duration_array( $duration ) { - return iCalUtilityFunctions::_duration2arr( $duration ); - } - public static function _duration2arr( $duration ) { - $output = array(); - if( is_array( $duration ) && - ( 1 == count( $duration )) && - isset( $duration['sec'] ) && - ( 60 < $duration['sec'] )) { - $durseconds = $duration['sec']; - $output['week'] = (int) floor( $durseconds / ( 60 * 60 * 24 * 7 )); - $durseconds = $durseconds % ( 60 * 60 * 24 * 7 ); - $output['day'] = (int) floor( $durseconds / ( 60 * 60 * 24 )); - $durseconds = $durseconds % ( 60 * 60 * 24 ); - $output['hour'] = (int) floor( $durseconds / ( 60 * 60 )); - $durseconds = $durseconds % ( 60 * 60 ); - $output['min'] = (int) floor( $durseconds / ( 60 )); - $output['sec'] = ( $durseconds % ( 60 )); - } - else { - foreach( $duration as $durKey => $durValue ) { - if( empty( $durValue )) continue; - switch ( $durKey ) { - case '0': case 'week': $output['week'] = $durValue; break; - case '1': case 'day': $output['day'] = $durValue; break; - case '2': case 'hour': $output['hour'] = $durValue; break; - case '3': case 'min': $output['min'] = $durValue; break; - case '4': case 'sec': $output['sec'] = $durValue; break; - } - } - } - if( isset( $output['week'] ) && ( 0 < $output['week'] )) { - unset( $output['day'], $output['hour'], $output['min'], $output['sec'] ); - return $output; - } - unset( $output['week'] ); - if( empty( $output['day'] )) - unset( $output['day'] ); - if ( isset( $output['hour'] ) || isset( $output['min'] ) || isset( $output['sec'] )) { - if( !isset( $output['hour'] )) $output['hour'] = 0; - if( !isset( $output['min'] )) $output['min'] = 0; - if( !isset( $output['sec'] )) $output['sec'] = 0; - if(( 0 == $output['hour'] ) && ( 0 == $output['min'] ) && ( 0 == $output['sec'] )) - unset( $output['hour'], $output['min'], $output['sec'] ); - } - return $output; - } -/** - * convert startdate+duration to a array format datetime - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.15.12 - 2012-10-31 - * @param array $startdate - * @param array $duration - * @return array, date format - */ - public static function _duration2date( $startdate, $duration ) { - $dateOnly = ( isset( $startdate['hour'] ) || isset( $startdate['min'] ) || isset( $startdate['sec'] )) ? FALSE : TRUE; - $startdate['hour'] = ( isset( $startdate['hour'] )) ? $startdate['hour'] : 0; - $startdate['min'] = ( isset( $startdate['min'] )) ? $startdate['min'] : 0; - $startdate['sec'] = ( isset( $startdate['sec'] )) ? $startdate['sec'] : 0; - $dtend = 0; - if( isset( $duration['week'] )) $dtend += ( $duration['week'] * 7 * 24 * 60 * 60 ); - if( isset( $duration['day'] )) $dtend += ( $duration['day'] * 24 * 60 * 60 ); - if( isset( $duration['hour'] )) $dtend += ( $duration['hour'] * 60 *60 ); - if( isset( $duration['min'] )) $dtend += ( $duration['min'] * 60 ); - if( isset( $duration['sec'] )) $dtend += $duration['sec']; - $date = date( 'Y-m-d-H-i-s', mktime((int) $startdate['hour'], (int) $startdate['min'], (int) ( $startdate['sec'] + $dtend ), (int) $startdate['month'], (int) $startdate['day'], (int) $startdate['year'] )); - $d = explode( '-', $date ); - $dtend2 = array( 'year' => $d[0], 'month' => $d[1], 'day' => $d[2], 'hour' => $d[3], 'min' => $d[4], 'sec' => $d[5] ); - if( isset( $startdate['tz'] )) - $dtend2['tz'] = $startdate['tz']; - if( $dateOnly && (( 0 == $dtend2['hour'] ) && ( 0 == $dtend2['min'] ) && ( 0 == $dtend2['sec'] ))) - unset( $dtend2['hour'], $dtend2['min'], $dtend2['sec'] ); - return $dtend2; - } -/** - * ensures internal duration format for an input string (iCal) formatted duration - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.14.1 - 2012-09-25 - * @param string $duration - * @return array - */ - public static function _duration_string( $duration ) { - return iCalUtilityFunctions::_durationStr2arr( $duration ); - } - public static function _durationStr2arr( $duration ) { - $duration = (string) trim( $duration ); - while( 'P' != strtoupper( substr( $duration, 0, 1 ))) { - if( 0 < strlen( $duration )) - $duration = substr( $duration, 1 ); - else - return false; // no leading P !?!? - } - $duration = substr( $duration, 1 ); // skip P - $duration = str_replace ( 't', 'T', $duration ); - $duration = str_replace ( 'T', '', $duration ); - $output = array(); - $val = null; - for( $ix=0; $ix < strlen( $duration ); $ix++ ) { - switch( strtoupper( substr( $duration, $ix, 1 ))) { - case 'W': - $output['week'] = $val; - $val = null; - break; - case 'D': - $output['day'] = $val; - $val = null; - break; - case 'H': - $output['hour'] = $val; - $val = null; - break; - case 'M': - $output['min'] = $val; - $val = null; - break; - case 'S': - $output['sec'] = $val; - $val = null; - break; - default: - if( !ctype_digit( substr( $duration, $ix, 1 ))) - return false; // unknown duration control character !?!? - else - $val .= substr( $duration, $ix, 1 ); - } - } - return iCalUtilityFunctions::_duration2arr( $output ); - } -/** - * creates formatted output for calendar component property data value type duration - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.15.8 - 2012-10-30 - * @param array $duration, array( week, day, hour, min, sec ) - * @return string - */ - public static function _format_duration( $duration ) { - return iCalUtilityFunctions::_duration2str( $duration ); - } - public static function _duration2str( $duration ) { - if( isset( $duration['week'] ) || - isset( $duration['day'] ) || - isset( $duration['hour'] ) || - isset( $duration['min'] ) || - isset( $duration['sec'] )) - $ok = TRUE; - else - return; - if( isset( $duration['week'] ) && ( 0 < $duration['week'] )) - return 'P'.$duration['week'].'W'; - $output = 'P'; - if( isset($duration['day'] ) && ( 0 < $duration['day'] )) - $output .= $duration['day'].'D'; - if(( isset( $duration['hour']) && ( 0 < $duration['hour'] )) || - ( isset( $duration['min']) && ( 0 < $duration['min'] )) || - ( isset( $duration['sec']) && ( 0 < $duration['sec'] ))) { - $output .= 'T'; - $output .= ( isset( $duration['hour']) && ( 0 < $duration['hour'] )) ? $duration['hour'].'H' : '0H'; - $output .= ( isset( $duration['min']) && ( 0 < $duration['min'] )) ? $duration['min']. 'M' : '0M'; - $output .= ( isset( $duration['sec']) && ( 0 < $duration['sec'] )) ? $duration['sec']. 'S' : '0S'; - } - if( 'P' == $output ) - $output = 'PT0H0M0S'; - return $output; - } -/** - * removes expkey+expvalue from array and returns hitval (if found) else returns elseval - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.4.16 - 2008-11-08 - * @param array $array - * @param string $expkey, expected key - * @param string $expval, expected value - * @param int $hitVal optional, return value if found - * @param int $elseVal optional, return value if not found - * @param int $preSet optional, return value if already preset - * @return int - */ - public static function _existRem( &$array, $expkey, $expval=FALSE, $hitVal=null, $elseVal=null, $preSet=null ) { - if( $preSet ) - return $preSet; - if( !is_array( $array ) || ( 0 == count( $array ))) - return $elseVal; - foreach( $array as $key => $value ) { - if( strtoupper( $expkey ) == strtoupper( $key )) { - if( !$expval || ( strtoupper( $expval ) == strtoupper( $array[$key] ))) { - unset( $array[$key] ); - return $hitVal; - } - } - } - return $elseVal; - } -/** - * checks if input contains a (array formatted) date/time - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.11.8 - 2012-01-20 - * @param array $input - * @return bool - */ - public static function _isArrayDate( $input ) { - if( !is_array( $input )) - return FALSE; - if( isset( $input['week'] ) || ( !in_array( count( $input ), array( 3, 6, 7 )))) - return FALSE; - if( 7 == count( $input )) - return TRUE; - if( isset( $input['year'] ) && isset( $input['month'] ) && isset( $input['day'] )) - return checkdate( (int) $input['month'], (int) $input['day'], (int) $input['year'] ); - if( isset( $input['day'] ) || isset( $input['hour'] ) || isset( $input['min'] ) || isset( $input['sec'] )) - return FALSE; - if( in_array( 0, $input )) - return FALSE; - if(( 1970 > $input[0] ) || ( 12 < $input[1] ) || ( 31 < $input[2] )) - return FALSE; - if(( isset( $input[0] ) && isset( $input[1] ) && isset( $input[2] )) && - checkdate( (int) $input[1], (int) $input[2], (int) $input[0] )) - return TRUE; - $input = iCalUtilityFunctions::_strdate2date( $input[1].'/'.$input[2].'/'.$input[0], 3 ); // m - d - Y - if( isset( $input['year'] ) && isset( $input['month'] ) && isset( $input['day'] )) - return checkdate( (int) $input['month'], (int) $input['day'], (int) $input['year'] ); - return FALSE; - } -/** - * checks if input array contains a timestamp date - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.4.16 - 2008-10-18 - * @param array $input - * @return bool - */ - public static function _isArrayTimestampDate( $input ) { - return ( is_array( $input ) && isset( $input['timestamp'] )) ? TRUE : FALSE ; - } -/** - * controls if input string contains (trailing) UTC/iCal offset - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.14.1 - 2012-09-21 - * @param string $input - * @return bool - */ - public static function _isOffset( $input ) { - $input = trim( (string) $input ); - if( 'Z' == substr( $input, -1 )) - return TRUE; - elseif(( 5 <= strlen( $input )) && - ( in_array( substr( $input, -5, 1 ), array( '+', '-' ))) && - ( '0000' <= substr( $input, -4 )) && ( '9999' >= substr( $input, -4 ))) - return TRUE; - elseif(( 7 <= strlen( $input )) && - ( in_array( substr( $input, -7, 1 ), array( '+', '-' ))) && - ( '000000' <= substr( $input, -6 )) && ( '999999' >= substr( $input, -6 ))) - return TRUE; - return FALSE; - } -/** - * (very simple) conversion of a MS timezone to a PHP5 valid (Date-)timezone - * matching (MS) UCT offset and time zone descriptors - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.14.1 - 2012-09-16 - * @param string $timezone, input/output variable reference - * @return bool - */ - public static function ms2phpTZ( & $timezone ) { - if( empty( $timezone )) - return FALSE; - $search = str_replace( '"', '', $timezone ); - $search = str_replace( array('GMT', 'gmt', 'utc' ), 'UTC', $search ); - if( '(UTC' != substr( $search, 0, 4 )) - return FALSE; - if( FALSE === ( $pos = strpos( $search, ')' ))) - return FALSE; - $pos = strpos( $search, ')' ); - $searchOffset = substr( $search, 4, ( $pos - 4 )); - $searchOffset = iCalUtilityFunctions::_tz2offset( str_replace( ':', '', $searchOffset )); - while( ' ' ==substr( $search, ( $pos + 1 ))) - $pos += 1; - $searchText = trim( str_replace( array( '(', ')', '&', ',', ' ' ), ' ', substr( $search, ( $pos + 1 )) )); - $searchWords = explode( ' ', $searchText ); - $timezone_abbreviations = DateTimeZone::listAbbreviations(); - $hits = array(); - foreach( $timezone_abbreviations as $name => $transitions ) { - foreach( $transitions as $cnt => $transition ) { - if( empty( $transition['offset'] ) || - empty( $transition['timezone_id'] ) || - ( $transition['offset'] != $searchOffset )) - continue; - $cWords = explode( '/', $transition['timezone_id'] ); - $cPrio = $hitCnt = $rank = 0; - foreach( $cWords as $cWord ) { - if( empty( $cWord )) - continue; - $cPrio += 1; - $sPrio = 0; - foreach( $searchWords as $sWord ) { - if( empty( $sWord ) || ( 'time' == strtolower( $sWord ))) - continue; - $sPrio += 1; - if( strtolower( $cWord ) == strtolower( $sWord )) { - $hitCnt += 1; - $rank += ( $cPrio + $sPrio ); - } - else - $rank += 10; - } - } - if( 0 < $hitCnt ) { - $hits[$rank][] = $transition['timezone_id']; - } - } - } - unset( $timezone_abbreviations ); - if( empty( $hits )) - return FALSE; - ksort( $hits ); - foreach( $hits as $rank => $tzs ) { - if( !empty( $tzs )) { - $timezone = reset( $tzs ); - return TRUE; - } - } - return FALSE; - } -/** - * transforms offset in seconds to [-/+]hhmm[ss] - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2011-05-02 - * @param string $seconds - * @return string - */ - public static function offsetSec2His( $seconds ) { - if( '-' == substr( $seconds, 0, 1 )) { - $prefix = '-'; - $seconds = substr( $seconds, 1 ); - } - elseif( '+' == substr( $seconds, 0, 1 )) { - $prefix = '+'; - $seconds = substr( $seconds, 1 ); - } - else - $prefix = '+'; - $output = ''; - $hour = (int) floor( $seconds / 3600 ); - if( 10 > $hour ) - $hour = '0'.$hour; - $seconds = $seconds % 3600; - $min = (int) floor( $seconds / 60 ); - if( 10 > $min ) - $min = '0'.$min; - $output = $hour.$min; - $seconds = $seconds % 60; - if( 0 < $seconds) { - if( 9 < $seconds) - $output .= $seconds; - else - $output .= '0'.$seconds; - } - return $prefix.$output; - } -/** - * updates an array with dates based on a recur pattern - * - * if missing, UNTIL is set 1 year from startdate (emergency break) - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.10.19 - 2011-10-31 - * @param array $result, array to update, array([timestamp] => timestamp) - * @param array $recur, pattern for recurrency (only value part, params ignored) - * @param array $wdate, component start date - * @param array $startdate, start date - * @param array $enddate, optional - * @return void - * @todo BYHOUR, BYMINUTE, BYSECOND, WEEKLY at year end/start - */ - public static function _recur2date( & $result, $recur, $wdate, $startdate, $enddate=FALSE ) { - foreach( $wdate as $k => $v ) if( ctype_digit( $v )) $wdate[$k] = (int) $v; - $wdateStart = $wdate; - $wdatets = iCalUtilityFunctions::_date2timestamp( $wdate ); - $startdatets = iCalUtilityFunctions::_date2timestamp( $startdate ); - if( !$enddate ) { - $enddate = $startdate; - $enddate['year'] += 1; - } -// echo "recur __in_ comp start ".implode('-',$wdate)." period start ".implode('-',$startdate)." period end ".implode('-',$enddate)."
\n";print_r($recur);echo "
\n";//test### - $endDatets = iCalUtilityFunctions::_date2timestamp( $enddate ); // fix break - if( !isset( $recur['COUNT'] ) && !isset( $recur['UNTIL'] )) - $recur['UNTIL'] = $enddate; // create break - if( isset( $recur['UNTIL'] )) { - $tdatets = iCalUtilityFunctions::_date2timestamp( $recur['UNTIL'] ); - if( $endDatets > $tdatets ) { - $endDatets = $tdatets; // emergency break - $enddate = iCalUtilityFunctions::_timestamp2date( $endDatets, 6 ); - } - else - $recur['UNTIL'] = iCalUtilityFunctions::_timestamp2date( $endDatets, 6 ); - } - if( $wdatets > $endDatets ) { -// echo "recur out of date ".date('Y-m-d H:i:s',$wdatets)."
\n";//test - return array(); // nothing to do.. . - } - if( !isset( $recur['FREQ'] )) // "MUST be specified.. ." - $recur['FREQ'] = 'DAILY'; // ?? - $wkst = ( isset( $recur['WKST'] ) && ( 'SU' == $recur['WKST'] )) ? 24*60*60 : 0; // ?? - $weekStart = (int) date( 'W', ( $wdatets + $wkst )); - if( !isset( $recur['INTERVAL'] )) - $recur['INTERVAL'] = 1; - $countcnt = ( !isset( $recur['BYSETPOS'] )) ? 1 : 0; // DTSTART counts as the first occurrence - /* find out how to step up dates and set index for interval count */ - $step = array(); - if( 'YEARLY' == $recur['FREQ'] ) - $step['year'] = 1; - elseif( 'MONTHLY' == $recur['FREQ'] ) - $step['month'] = 1; - elseif( 'WEEKLY' == $recur['FREQ'] ) - $step['day'] = 7; - else - $step['day'] = 1; - if( isset( $step['year'] ) && isset( $recur['BYMONTH'] )) - $step = array( 'month' => 1 ); - if( empty( $step ) && isset( $recur['BYWEEKNO'] )) // ?? - $step = array( 'day' => 7 ); - if( isset( $recur['BYYEARDAY'] ) || isset( $recur['BYMONTHDAY'] ) || isset( $recur['BYDAY'] )) - $step = array( 'day' => 1 ); - $intervalarr = array(); - if( 1 < $recur['INTERVAL'] ) { - $intervalix = iCalUtilityFunctions::_recurIntervalIx( $recur['FREQ'], $wdate, $wkst ); - $intervalarr = array( $intervalix => 0 ); - } - if( isset( $recur['BYSETPOS'] )) { // save start date + weekno - $bysetposymd1 = $bysetposymd2 = $bysetposw1 = $bysetposw2 = array(); -// echo "bysetposXold_start=$bysetposYold $bysetposMold $bysetposDold
\n"; // test ### - if( is_array( $recur['BYSETPOS'] )) { - foreach( $recur['BYSETPOS'] as $bix => $bval ) - $recur['BYSETPOS'][$bix] = (int) $bval; - } - else - $recur['BYSETPOS'] = array( (int) $recur['BYSETPOS'] ); - if( 'YEARLY' == $recur['FREQ'] ) { - $wdate['month'] = $wdate['day'] = 1; // start from beginning of year - $wdatets = iCalUtilityFunctions::_date2timestamp( $wdate ); - iCalUtilityFunctions::_stepdate( $enddate, $endDatets, array( 'year' => 1 )); // make sure to count whole last year - } - elseif( 'MONTHLY' == $recur['FREQ'] ) { - $wdate['day'] = 1; // start from beginning of month - $wdatets = iCalUtilityFunctions::_date2timestamp( $wdate ); - iCalUtilityFunctions::_stepdate( $enddate, $endDatets, array( 'month' => 1 )); // make sure to count whole last month - } - else - iCalUtilityFunctions::_stepdate( $enddate, $endDatets, $step); // make sure to count whole last period -// echo "BYSETPOS endDat++ =".implode('-',$enddate).' step='.var_export($step,TRUE)."
\n";//test### - $bysetposWold = (int) date( 'W', ( $wdatets + $wkst )); - $bysetposYold = $wdate['year']; - $bysetposMold = $wdate['month']; - $bysetposDold = $wdate['day']; - } - else - iCalUtilityFunctions::_stepdate( $wdate, $wdatets, $step); - $year_old = null; - $daynames = array( 'SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA' ); - /* MAIN LOOP */ -// echo "recur start ".implode('-',$wdate)." end ".implode('-',$enddate)."
\n";//test - while( TRUE ) { - if( isset( $endDatets ) && ( $wdatets > $endDatets )) - break; - if( isset( $recur['COUNT'] ) && ( $countcnt >= $recur['COUNT'] )) - break; - if( $year_old != $wdate['year'] ) { - $year_old = $wdate['year']; - $daycnts = array(); - $yeardays = $weekno = 0; - $yeardaycnt = array(); - foreach( $daynames as $dn ) - $yeardaycnt[$dn] = 0; - for( $m = 1; $m <= 12; $m++ ) { // count up and update up-counters - $daycnts[$m] = array(); - $weekdaycnt = array(); - foreach( $daynames as $dn ) - $weekdaycnt[$dn] = 0; - $mcnt = date( 't', mktime( 0, 0, 0, $m, 1, $wdate['year'] )); - for( $d = 1; $d <= $mcnt; $d++ ) { - $daycnts[$m][$d] = array(); - if( isset( $recur['BYYEARDAY'] )) { - $yeardays++; - $daycnts[$m][$d]['yearcnt_up'] = $yeardays; - } - if( isset( $recur['BYDAY'] )) { - $day = date( 'w', mktime( 0, 0, 0, $m, $d, $wdate['year'] )); - $day = $daynames[$day]; - $daycnts[$m][$d]['DAY'] = $day; - $weekdaycnt[$day]++; - $daycnts[$m][$d]['monthdayno_up'] = $weekdaycnt[$day]; - $yeardaycnt[$day]++; - $daycnts[$m][$d]['yeardayno_up'] = $yeardaycnt[$day]; - } - if( isset( $recur['BYWEEKNO'] ) || ( $recur['FREQ'] == 'WEEKLY' )) - $daycnts[$m][$d]['weekno_up'] =(int)date('W',mktime(0,0,$wkst,$m,$d,$wdate['year'])); - } - } - $daycnt = 0; - $yeardaycnt = array(); - if( isset( $recur['BYWEEKNO'] ) || ( $recur['FREQ'] == 'WEEKLY' )) { - $weekno = null; - for( $d=31; $d > 25; $d-- ) { // get last weekno for year - if( !$weekno ) - $weekno = $daycnts[12][$d]['weekno_up']; - elseif( $weekno < $daycnts[12][$d]['weekno_up'] ) { - $weekno = $daycnts[12][$d]['weekno_up']; - break; - } - } - } - for( $m = 12; $m > 0; $m-- ) { // count down and update down-counters - $weekdaycnt = array(); - foreach( $daynames as $dn ) - $yeardaycnt[$dn] = $weekdaycnt[$dn] = 0; - $monthcnt = 0; - $mcnt = date( 't', mktime( 0, 0, 0, $m, 1, $wdate['year'] )); - for( $d = $mcnt; $d > 0; $d-- ) { - if( isset( $recur['BYYEARDAY'] )) { - $daycnt -= 1; - $daycnts[$m][$d]['yearcnt_down'] = $daycnt; - } - if( isset( $recur['BYMONTHDAY'] )) { - $monthcnt -= 1; - $daycnts[$m][$d]['monthcnt_down'] = $monthcnt; - } - if( isset( $recur['BYDAY'] )) { - $day = $daycnts[$m][$d]['DAY']; - $weekdaycnt[$day] -= 1; - $daycnts[$m][$d]['monthdayno_down'] = $weekdaycnt[$day]; - $yeardaycnt[$day] -= 1; - $daycnts[$m][$d]['yeardayno_down'] = $yeardaycnt[$day]; - } - if( isset( $recur['BYWEEKNO'] ) || ( $recur['FREQ'] == 'WEEKLY' )) - $daycnts[$m][$d]['weekno_down'] = ($daycnts[$m][$d]['weekno_up'] - $weekno - 1); - } - } - } - /* check interval */ - if( 1 < $recur['INTERVAL'] ) { - /* create interval index */ - $intervalix = iCalUtilityFunctions::_recurIntervalIx( $recur['FREQ'], $wdate, $wkst ); - /* check interval */ - $currentKey = array_keys( $intervalarr ); - $currentKey = end( $currentKey ); // get last index - if( $currentKey != $intervalix ) - $intervalarr = array( $intervalix => ( $intervalarr[$currentKey] + 1 )); - if(( $recur['INTERVAL'] != $intervalarr[$intervalix] ) && - ( 0 != $intervalarr[$intervalix] )) { - /* step up date */ -// echo "skip: ".implode('-',$wdate)." ix=$intervalix old=$currentKey interval=".$intervalarr[$intervalix]."
\n";//test - iCalUtilityFunctions::_stepdate( $wdate, $wdatets, $step); - continue; - } - else // continue within the selected interval - $intervalarr[$intervalix] = 0; -// echo "cont: ".implode('-',$wdate)." ix=$intervalix old=$currentKey interval=".$intervalarr[$intervalix]."
\n";//test - } - $updateOK = TRUE; - if( $updateOK && isset( $recur['BYMONTH'] )) - $updateOK = iCalUtilityFunctions::_recurBYcntcheck( $recur['BYMONTH'] - , $wdate['month'] - ,($wdate['month'] - 13)); - if( $updateOK && isset( $recur['BYWEEKNO'] )) - $updateOK = iCalUtilityFunctions::_recurBYcntcheck( $recur['BYWEEKNO'] - , $daycnts[$wdate['month']][$wdate['day']]['weekno_up'] - , $daycnts[$wdate['month']][$wdate['day']]['weekno_down'] ); - if( $updateOK && isset( $recur['BYYEARDAY'] )) - $updateOK = iCalUtilityFunctions::_recurBYcntcheck( $recur['BYYEARDAY'] - , $daycnts[$wdate['month']][$wdate['day']]['yearcnt_up'] - , $daycnts[$wdate['month']][$wdate['day']]['yearcnt_down'] ); - if( $updateOK && isset( $recur['BYMONTHDAY'] )) - $updateOK = iCalUtilityFunctions::_recurBYcntcheck( $recur['BYMONTHDAY'] - , $wdate['day'] - , $daycnts[$wdate['month']][$wdate['day']]['monthcnt_down'] ); -// echo "efter BYMONTHDAY: ".implode('-',$wdate).' status: '; echo ($updateOK) ? 'TRUE' : 'FALSE'; echo "
\n";//test### - if( $updateOK && isset( $recur['BYDAY'] )) { - $updateOK = FALSE; - $m = $wdate['month']; - $d = $wdate['day']; - if( isset( $recur['BYDAY']['DAY'] )) { // single day, opt with year/month day order no - $daynoexists = $daynosw = $daynamesw = FALSE; - if( $recur['BYDAY']['DAY'] == $daycnts[$m][$d]['DAY'] ) - $daynamesw = TRUE; - if( isset( $recur['BYDAY'][0] )) { - $daynoexists = TRUE; - if(( isset( $recur['FREQ'] ) && ( $recur['FREQ'] == 'MONTHLY' )) || isset( $recur['BYMONTH'] )) - $daynosw = iCalUtilityFunctions::_recurBYcntcheck( $recur['BYDAY'][0] - , $daycnts[$m][$d]['monthdayno_up'] - , $daycnts[$m][$d]['monthdayno_down'] ); - elseif( isset( $recur['FREQ'] ) && ( $recur['FREQ'] == 'YEARLY' )) - $daynosw = iCalUtilityFunctions::_recurBYcntcheck( $recur['BYDAY'][0] - , $daycnts[$m][$d]['yeardayno_up'] - , $daycnts[$m][$d]['yeardayno_down'] ); - } - if(( $daynoexists && $daynosw && $daynamesw ) || - ( !$daynoexists && !$daynosw && $daynamesw )) { - $updateOK = TRUE; -// echo "m=$m d=$d day=".$daycnts[$m][$d]['DAY']." yeardayno_up=".$daycnts[$m][$d]['yeardayno_up']." daynoexists:$daynoexists daynosw:$daynosw daynamesw:$daynamesw updateOK:$updateOK
\n"; // test ### - } -// echo "m=$m d=$d day=".$daycnts[$m][$d]['DAY']." yeardayno_up=".$daycnts[$m][$d]['yeardayno_up']." daynoexists:$daynoexists daynosw:$daynosw daynamesw:$daynamesw updateOK:$updateOK
\n"; // test ### - } - else { - foreach( $recur['BYDAY'] as $bydayvalue ) { - $daynoexists = $daynosw = $daynamesw = FALSE; - if( isset( $bydayvalue['DAY'] ) && - ( $bydayvalue['DAY'] == $daycnts[$m][$d]['DAY'] )) - $daynamesw = TRUE; - if( isset( $bydayvalue[0] )) { - $daynoexists = TRUE; - if(( isset( $recur['FREQ'] ) && ( $recur['FREQ'] == 'MONTHLY' )) || - isset( $recur['BYMONTH'] )) - $daynosw = iCalUtilityFunctions::_recurBYcntcheck( $bydayvalue['0'] - , $daycnts[$m][$d]['monthdayno_up'] - , $daycnts[$m][$d]['monthdayno_down'] ); - elseif( isset( $recur['FREQ'] ) && ( $recur['FREQ'] == 'YEARLY' )) - $daynosw = iCalUtilityFunctions::_recurBYcntcheck( $bydayvalue['0'] - , $daycnts[$m][$d]['yeardayno_up'] - , $daycnts[$m][$d]['yeardayno_down'] ); - } -// echo "daynoexists:$daynoexists daynosw:$daynosw daynamesw:$daynamesw
\n"; // test ### - if(( $daynoexists && $daynosw && $daynamesw ) || - ( !$daynoexists && !$daynosw && $daynamesw )) { - $updateOK = TRUE; - break; - } - } - } - } -// echo "efter BYDAY: ".implode('-',$wdate).' status: '; echo ($updateOK) ? 'TRUE' : 'FALSE'; echo "
\n"; // test ### - /* check BYSETPOS */ - if( $updateOK ) { - if( isset( $recur['BYSETPOS'] ) && - ( in_array( $recur['FREQ'], array( 'YEARLY', 'MONTHLY', 'WEEKLY', 'DAILY' )))) { - if( isset( $recur['WEEKLY'] )) { - if( $bysetposWold == $daycnts[$wdate['month']][$wdate['day']]['weekno_up'] ) - $bysetposw1[] = $wdatets; - else - $bysetposw2[] = $wdatets; - } - else { - if(( isset( $recur['FREQ'] ) && ( 'YEARLY' == $recur['FREQ'] ) && - ( $bysetposYold == $wdate['year'] )) || - ( isset( $recur['FREQ'] ) && ( 'MONTHLY' == $recur['FREQ'] ) && - (( $bysetposYold == $wdate['year'] ) && - ( $bysetposMold == $wdate['month'] ))) || - ( isset( $recur['FREQ'] ) && ( 'DAILY' == $recur['FREQ'] ) && - (( $bysetposYold == $wdate['year'] ) && - ( $bysetposMold == $wdate['month']) && - ( $bysetposDold == $wdate['day'] )))) { -// echo "bysetposymd1[]=".date('Y-m-d H:i:s',$wdatets)."
\n";//test - $bysetposymd1[] = $wdatets; - } - else { -// echo "bysetposymd2[]=".date('Y-m-d H:i:s',$wdatets)."
\n";//test - $bysetposymd2[] = $wdatets; - } - } - } - else { - /* update result array if BYSETPOS is set */ - $countcnt++; - if( $startdatets <= $wdatets ) { // only output within period - $result[$wdatets] = TRUE; -// echo "recur ".date('Y-m-d H:i:s',$wdatets)."
\n";//test - } -// echo "recur undate ".date('Y-m-d H:i:s',$wdatets)." okdatstart ".date('Y-m-d H:i:s',$startdatets)."
\n";//test - $updateOK = FALSE; - } - } - /* step up date */ - iCalUtilityFunctions::_stepdate( $wdate, $wdatets, $step); - /* check if BYSETPOS is set for updating result array */ - if( $updateOK && isset( $recur['BYSETPOS'] )) { - $bysetpos = FALSE; - if( isset( $recur['FREQ'] ) && ( 'YEARLY' == $recur['FREQ'] ) && - ( $bysetposYold != $wdate['year'] )) { - $bysetpos = TRUE; - $bysetposYold = $wdate['year']; - } - elseif( isset( $recur['FREQ'] ) && ( 'MONTHLY' == $recur['FREQ'] && - (( $bysetposYold != $wdate['year'] ) || ( $bysetposMold != $wdate['month'] )))) { - $bysetpos = TRUE; - $bysetposYold = $wdate['year']; - $bysetposMold = $wdate['month']; - } - elseif( isset( $recur['FREQ'] ) && ( 'WEEKLY' == $recur['FREQ'] )) { - $weekno = (int) date( 'W', mktime( 0, 0, $wkst, $wdate['month'], $wdate['day'], $wdate['year'])); - if( $bysetposWold != $weekno ) { - $bysetposWold = $weekno; - $bysetpos = TRUE; - } - } - elseif( isset( $recur['FREQ'] ) && ( 'DAILY' == $recur['FREQ'] ) && - (( $bysetposYold != $wdate['year'] ) || - ( $bysetposMold != $wdate['month'] ) || - ( $bysetposDold != $wdate['day'] ))) { - $bysetpos = TRUE; - $bysetposYold = $wdate['year']; - $bysetposMold = $wdate['month']; - $bysetposDold = $wdate['day']; - } - if( $bysetpos ) { - if( isset( $recur['BYWEEKNO'] )) { - $bysetposarr1 = & $bysetposw1; - $bysetposarr2 = & $bysetposw2; - } - else { - $bysetposarr1 = & $bysetposymd1; - $bysetposarr2 = & $bysetposymd2; - } -// echo 'test före out startYMD (weekno)='.$wdateStart['year'].':'.$wdateStart['month'].':'.$wdateStart['day']." ($weekStart) "; // test ### - foreach( $recur['BYSETPOS'] as $ix ) { - if( 0 > $ix ) // both positive and negative BYSETPOS allowed - $ix = ( count( $bysetposarr1 ) + $ix + 1); - $ix--; - if( isset( $bysetposarr1[$ix] )) { - if( $startdatets <= $bysetposarr1[$ix] ) { // only output within period -// $testdate = iCalUtilityFunctions::_timestamp2date( $bysetposarr1[$ix], 6 ); // test ### -// $testweekno = (int) date( 'W', mktime( 0, 0, $wkst, $testdate['month'], $testdate['day'], $testdate['year'] )); // test ### -// echo " testYMD (weekno)=".$testdate['year'].':'.$testdate['month'].':'.$testdate['day']." ($testweekno)"; // test ### - $result[$bysetposarr1[$ix]] = TRUE; -// echo " recur ".date('Y-m-d H:i:s',$bysetposarr1[$ix]); // test ### - } - $countcnt++; - } - if( isset( $recur['COUNT'] ) && ( $countcnt >= $recur['COUNT'] )) - break; - } -// echo "
\n"; // test ### - $bysetposarr1 = $bysetposarr2; - $bysetposarr2 = array(); - } - } - } - } - public static function _recurBYcntcheck( $BYvalue, $upValue, $downValue ) { - if( is_array( $BYvalue ) && - ( in_array( $upValue, $BYvalue ) || in_array( $downValue, $BYvalue ))) - return TRUE; - elseif(( $BYvalue == $upValue ) || ( $BYvalue == $downValue )) - return TRUE; - else - return FALSE; - } - public static function _recurIntervalIx( $freq, $date, $wkst ) { - /* create interval index */ - switch( $freq ) { - case 'YEARLY': - $intervalix = $date['year']; - break; - case 'MONTHLY': - $intervalix = $date['year'].'-'.$date['month']; - break; - case 'WEEKLY': - $wdatets = iCalUtilityFunctions::_date2timestamp( $date ); - $intervalix = (int) date( 'W', ( $wdatets + $wkst )); - break; - case 'DAILY': - default: - $intervalix = $date['year'].'-'.$date['month'].'-'.$date['day']; - break; - } - return $intervalix; - } -/** - * convert input format for exrule and rrule to internal format - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.14.1 - 2012-09-24 - * @param array $rexrule - * @return array - */ - public static function _setRexrule( $rexrule ) { - $input = array(); - if( empty( $rexrule )) - return $input; - foreach( $rexrule as $rexrulelabel => $rexrulevalue ) { - $rexrulelabel = strtoupper( $rexrulelabel ); - if( 'UNTIL' != $rexrulelabel ) - $input[$rexrulelabel] = $rexrulevalue; - else { - iCalUtilityFunctions::_strDate2arr( $rexrulevalue ); - if( iCalUtilityFunctions::_isArrayTimestampDate( $rexrulevalue )) // timestamp, always date-time UTC - $input[$rexrulelabel] = iCalUtilityFunctions::_timestamp2date( $rexrulevalue, 7, 'UTC' ); - elseif( iCalUtilityFunctions::_isArrayDate( $rexrulevalue )) { // date or UTC date-time - $parno = ( isset( $rexrulevalue['hour'] ) || isset( $rexrulevalue[4] )) ? 7 : 3; - $d = iCalUtilityFunctions::_chkDateArr( $rexrulevalue, $parno ); - if(( 3 < $parno ) && isset( $d['tz'] ) && ( 'Z' != $d['tz'] ) && iCalUtilityFunctions::_isOffset( $d['tz'] )) { - $strdate = sprintf( '%04d-%02d-%02d %02d:%02d:%02d %s', $d['year'], $d['month'], $d['day'], $d['hour'], $d['min'], $d['sec'], $d['tz'] ); - $input[$rexrulelabel] = iCalUtilityFunctions::_strdate2date( $strdate, 7 ); - unset( $input[$rexrulelabel]['unparsedtext'] ); - } - else - $input[$rexrulelabel] = $d; - } - elseif( 8 <= strlen( trim( $rexrulevalue ))) { // ex. textual date-time 2006-08-03 10:12:18 => UTC - $input[$rexrulelabel] = iCalUtilityFunctions::_strdate2date( $rexrulevalue ); - unset( $input['$rexrulelabel']['unparsedtext'] ); - } - if(( 3 < count( $input[$rexrulelabel] )) && !isset( $input[$rexrulelabel]['tz'] )) - $input[$rexrulelabel]['tz'] = 'Z'; - } - } - /* set recurrence rule specification in rfc2445 order */ - $input2 = array(); - if( isset( $input['FREQ'] )) - $input2['FREQ'] = $input['FREQ']; - if( isset( $input['UNTIL'] )) - $input2['UNTIL'] = $input['UNTIL']; - elseif( isset( $input['COUNT'] )) - $input2['COUNT'] = $input['COUNT']; - if( isset( $input['INTERVAL'] )) - $input2['INTERVAL'] = $input['INTERVAL']; - if( isset( $input['BYSECOND'] )) - $input2['BYSECOND'] = $input['BYSECOND']; - if( isset( $input['BYMINUTE'] )) - $input2['BYMINUTE'] = $input['BYMINUTE']; - if( isset( $input['BYHOUR'] )) - $input2['BYHOUR'] = $input['BYHOUR']; - if( isset( $input['BYDAY'] )) { - if( !is_array( $input['BYDAY'] )) // ensure upper case.. . - $input2['BYDAY'] = strtoupper( $input['BYDAY'] ); - else { - foreach( $input['BYDAY'] as $BYDAYx => $BYDAYv ) { - if( 'DAY' == strtoupper( $BYDAYx )) - $input2['BYDAY']['DAY'] = strtoupper( $BYDAYv ); - elseif( !is_array( $BYDAYv )) { - $input2['BYDAY'][$BYDAYx] = $BYDAYv; - } - else { - foreach( $BYDAYv as $BYDAYx2 => $BYDAYv2 ) { - if( 'DAY' == strtoupper( $BYDAYx2 )) - $input2['BYDAY'][$BYDAYx]['DAY'] = strtoupper( $BYDAYv2 ); - else - $input2['BYDAY'][$BYDAYx][$BYDAYx2] = $BYDAYv2; - } - } - } - } - } - if( isset( $input['BYMONTHDAY'] )) - $input2['BYMONTHDAY'] = $input['BYMONTHDAY']; - if( isset( $input['BYYEARDAY'] )) - $input2['BYYEARDAY'] = $input['BYYEARDAY']; - if( isset( $input['BYWEEKNO'] )) - $input2['BYWEEKNO'] = $input['BYWEEKNO']; - if( isset( $input['BYMONTH'] )) - $input2['BYMONTH'] = $input['BYMONTH']; - if( isset( $input['BYSETPOS'] )) - $input2['BYSETPOS'] = $input['BYSETPOS']; - if( isset( $input['WKST'] )) - $input2['WKST'] = $input['WKST']; - return $input2; - } -/** - * convert format for input date to internal date with parameters - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.14.1 - 2012-10-15 - * @param mixed $year - * @param mixed $month optional - * @param int $day optional - * @param int $hour optional - * @param int $min optional - * @param int $sec optional - * @param string $tz optional - * @param array $params optional - * @param string $caller optional - * @param string $objName optional - * @param string $tzid optional - * @return array - */ - public static function _setDate( $year, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $tz=FALSE, $params=FALSE, $caller=null, $objName=null, $tzid=FALSE ) { - $input = $parno = null; - $localtime = (( 'dtstart' == $caller ) && in_array( $objName, array( 'vtimezone', 'standard', 'daylight' ))) ? TRUE : FALSE; - iCalUtilityFunctions::_strDate2arr( $year ); - if( iCalUtilityFunctions::_isArrayDate( $year )) { - $input['value'] = iCalUtilityFunctions::_chkDateArr( $year, $parno ); - if( 100 > $input['value']['year'] ) - $input['value']['year'] += 2000; - if( $localtime ) - unset( $month['VALUE'], $month['TZID'] ); - elseif( !isset( $month['TZID'] ) && isset( $tzid )) - $month['TZID'] = $tzid; - if( isset( $input['value']['tz'] ) && iCalUtilityFunctions::_isOffset( $input['value']['tz'] )) - unset( $month['TZID'] ); - elseif( isset( $month['TZID'] ) && iCalUtilityFunctions::_isOffset( $month['TZID'] )) { - $input['value']['tz'] = $month['TZID']; - unset( $month['TZID'] ); - } - $input['params'] = iCalUtilityFunctions::_setParams( $month, array( 'VALUE' => 'DATE-TIME' )); - $hitval = ( isset( $input['value']['tz'] )) ? 7 : 6; - $parno = iCalUtilityFunctions::_existRem( $input['params'], 'VALUE', 'DATE-TIME', $hitval ); - $parno = iCalUtilityFunctions::_existRem( $input['params'], 'VALUE', 'DATE', 3, count( $input['value'] ), $parno ); - if(( 3 != $parno ) && isset( $input['value']['tz'] ) && ( 'Z' != $input['value']['tz'] ) && iCalUtilityFunctions::_isOffset( $input['value']['tz'] )) { - $d = $input['value']; - $strdate = sprintf( '%04d-%02d-%02d %02d:%02d:%02d %s', $d['year'], $d['month'], $d['day'], $d['hour'], $d['min'], $d['sec'], $d['tz'] ); - $input['value'] = iCalUtilityFunctions::_strdate2date( $strdate, $parno ); - unset( $input['value']['unparsedtext'], $input['params']['TZID'] ); - } - if( isset( $input['value']['tz'] ) && !iCalUtilityFunctions::_isOffset( $input['value']['tz'] )) { - $input['params']['TZID'] = $input['value']['tz']; - unset( $input['value']['tz'] ); - } - } // end if( iCalUtilityFunctions::_isArrayDate( $year )) - elseif( iCalUtilityFunctions::_isArrayTimestampDate( $year )) { - if( $localtime ) unset ( $month['VALUE'], $month['TZID'] ); - $input['params'] = iCalUtilityFunctions::_setParams( $month, array( 'VALUE' => 'DATE-TIME' )); - $parno = iCalUtilityFunctions::_existRem( $input['params'], 'VALUE', 'DATE', 3 ); - $hitval = 7; - $parno = iCalUtilityFunctions::_existRem( $input['params'], 'VALUE', 'DATE-TIME', $hitval, $parno ); - if( !isset( $input['params']['TZID'] ) && !empty( $tzid )) - $input['params']['TZID'] = $tzid; - if( isset( $year['tz'] )) { - $parno = 6; - if( !iCalUtilityFunctions::_isOffset( $year['tz'] )) - $input['params']['TZID'] = $year['tz']; - } - elseif( isset( $input['params']['TZID'] )) { - $year['tz'] = $input['params']['TZID']; - $parno = 6; - if( iCalUtilityFunctions::_isOffset( $input['params']['TZID'] )) { - unset( $input['params']['TZID'] ); - $parno = 7; - } - } - $input['value'] = iCalUtilityFunctions::_timestamp2date( $year, $parno ); - } // end elseif( iCalUtilityFunctions::_isArrayTimestampDate( $year )) - elseif( 8 <= strlen( trim( $year ))) { // ex. 2006-08-03 10:12:18 [[[+/-]1234[56]] / timezone] - if( $localtime ) - unset( $month['VALUE'], $month['TZID'] ); - elseif( !isset( $month['TZID'] ) && !empty( $tzid )) - $month['TZID'] = $tzid; - $input['params'] = iCalUtilityFunctions::_setParams( $month, array( 'VALUE' => 'DATE-TIME' )); - $parno = iCalUtilityFunctions::_existRem( $input['params'], 'VALUE', 'DATE-TIME', 7, $parno ); - $parno = iCalUtilityFunctions::_existRem( $input['params'], 'VALUE', 'DATE', 3, $parno, $parno ); - $input['value'] = iCalUtilityFunctions::_strdate2date( $year, $parno ); - unset( $input['value']['unparsedtext'] ); - if( isset( $input['value']['tz'] )) { - if( iCalUtilityFunctions::_isOffset( $input['value']['tz'] )) { - $d = $input['value']; - $strdate = sprintf( '%04d-%02d-%02d %02d:%02d:%02d %s', $d['year'], $d['month'], $d['day'], $d['hour'], $d['min'], $d['sec'], $d['tz'] ); - $input['value'] = iCalUtilityFunctions::_strdate2date( $strdate, 7 ); - unset( $input['value']['unparsedtext'], $input['params']['TZID'] ); - } - else { - $input['params']['TZID'] = $input['value']['tz']; - unset( $input['value']['tz'] ); - } - } - elseif( isset( $input['params']['TZID'] ) && iCalUtilityFunctions::_isOffset( $input['params']['TZID'] )) { - $d = $input['value']; - $strdate = sprintf( '%04d-%02d-%02d %02d:%02d:%02d %s', $d['year'], $d['month'], $d['day'], $d['hour'], $d['min'], $d['sec'], $input['params']['TZID'] ); - $input['value'] = iCalUtilityFunctions::_strdate2date( $strdate, 7 ); - unset( $input['value']['unparsedtext'], $input['params']['TZID'] ); - } - } // end elseif( 8 <= strlen( trim( $year ))) - else { - if( is_array( $params )) - $input['params'] = iCalUtilityFunctions::_setParams( $params, array( 'VALUE' => 'DATE-TIME' )); - elseif( is_array( $tz )) { - $input['params'] = iCalUtilityFunctions::_setParams( $tz, array( 'VALUE' => 'DATE-TIME' )); - $tz = FALSE; - } - elseif( is_array( $hour )) { - $input['params'] = iCalUtilityFunctions::_setParams( $hour, array( 'VALUE' => 'DATE-TIME' )); - $hour = $min = $sec = $tz = FALSE; - } - if( $localtime ) - unset ( $input['params']['VALUE'], $input['params']['TZID'] ); - elseif( !isset( $tz ) && !isset( $input['params']['TZID'] ) && !empty( $tzid )) - $input['params']['TZID'] = $tzid; - elseif( isset( $tz ) && iCalUtilityFunctions::_isOffset( $tz )) - unset( $input['params']['TZID'] ); - elseif( isset( $input['params']['TZID'] ) && iCalUtilityFunctions::_isOffset( $input['params']['TZID'] )) { - $tz = $input['params']['TZID']; - unset( $input['params']['TZID'] ); - } - $parno = iCalUtilityFunctions::_existRem( $input['params'], 'VALUE', 'DATE', 3 ); - $hitval = ( iCalUtilityFunctions::_isOffset( $tz )) ? 7 : 6; - $parno = iCalUtilityFunctions::_existRem( $input['params'], 'VALUE', 'DATE-TIME', $hitval, $parno, $parno ); - $input['value'] = array( 'year' => $year, 'month' => $month, 'day' => $day ); - if( 3 != $parno ) { - $input['value']['hour'] = ( $hour ) ? $hour : '0'; - $input['value']['min'] = ( $min ) ? $min : '0'; - $input['value']['sec'] = ( $sec ) ? $sec : '0'; - if( !empty( $tz )) - $input['value']['tz'] = $tz; - $strdate = iCalUtilityFunctions::_date2strdate( $input['value'], $parno ); - if( !empty( $tz ) && !iCalUtilityFunctions::_isOffset( $tz )) - $strdate .= ( 'Z' == $tz ) ? $tz : ' '.$tz; - $input['value'] = iCalUtilityFunctions::_strdate2date( $strdate, $parno ); - unset( $input['value']['unparsedtext'] ); - if( isset( $input['value']['tz'] )) { - if( iCalUtilityFunctions::_isOffset( $input['value']['tz'] )) { - $d = $input['value']; - $strdate = sprintf( '%04d-%02d-%02d %02d:%02d:%02d %s', $d['year'], $d['month'], $d['day'], $d['hour'], $d['min'], $d['sec'], $d['tz'] ); - $input['value'] = iCalUtilityFunctions::_strdate2date( $strdate, 7 ); - unset( $input['value']['unparsedtext'], $input['params']['TZID'] ); - } - else { - $input['params']['TZID'] = $input['value']['tz']; - unset( $input['value']['tz'] ); - } - } - elseif( isset( $input['params']['TZID'] ) && iCalUtilityFunctions::_isOffset( $input['params']['TZID'] )) { - $d = $input['value']; - $strdate = sprintf( '%04d-%02d-%02d %02d:%02d:%02d %s', $d['year'], $d['month'], $d['day'], $d['hour'], $d['min'], $d['sec'], $input['params']['TZID'] ); - $input['value'] = iCalUtilityFunctions::_strdate2date( $strdate, 7 ); - unset( $input['value']['unparsedtext'], $input['params']['TZID'] ); - } - } - } // end else (i.e. using all arguments) - if(( 3 == $parno ) || ( isset( $input['params']['VALUE'] ) && ( 'DATE' == $input['params']['VALUE'] ))) { - $input['params']['VALUE'] = 'DATE'; - unset( $input['value']['hour'], $input['value']['min'], $input['value']['sec'], $input['value']['tz'], $input['params']['TZID'] ); - } - elseif( isset( $input['params']['TZID'] )) { - if(( 'UTC' == strtoupper( $input['params']['TZID'] )) || ( 'GMT' == strtoupper( $input['params']['TZID'] ))) { - $input['value']['tz'] = 'Z'; - unset( $input['params']['TZID'] ); - } - else - unset( $input['value']['tz'] ); - } - elseif( isset( $input['value']['tz'] )) { - if(( 'UTC' == strtoupper( $input['value']['tz'] )) || ( 'GMT' == strtoupper( $input['value']['tz'] ))) - $input['value']['tz'] = 'Z'; - if( 'Z' != $input['value']['tz'] ) { - $input['params']['TZID'] = $input['value']['tz']; - unset( $input['value']['tz'] ); - } - else - unset( $input['params']['TZID'] ); - } - if( $localtime ) - unset( $input['value']['tz'], $input['params']['TZID'] ); - return $input; - } -/** - * convert format for input date (UTC) to internal date with parameters - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.14.4 - 2012-10-06 - * @param mixed $year - * @param mixed $month optional - * @param int $day optional - * @param int $hour optional - * @param int $min optional - * @param int $sec optional - * @param array $params optional - * @return array - */ - public static function _setDate2( $year, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $params=FALSE ) { - $input = null; - iCalUtilityFunctions::_strDate2arr( $year ); - if( iCalUtilityFunctions::_isArrayDate( $year )) { - $input['value'] = iCalUtilityFunctions::_chkDateArr( $year, 7 ); - if( isset( $input['value']['year'] ) && ( 100 > $input['value']['year'] )) - $input['value']['year'] += 2000; - $input['params'] = iCalUtilityFunctions::_setParams( $month, array( 'VALUE' => 'DATE-TIME' )); - if( isset( $input['value']['tz'] ) && ( 'Z' != $input['value']['tz'] ) && iCalUtilityFunctions::_isOffset( $input['value']['tz'] )) { - $d = $input['value']; - $strdate = sprintf( '%04d-%02d-%02d %02d:%02d:%02d %s', $d['year'], $d['month'], $d['day'], $d['hour'], $d['min'], $d['sec'], $d['tz'] ); - $input['value'] = iCalUtilityFunctions::_strdate2date( $strdate, 7 ); - unset( $input['value']['unparsedtext'] ); - } - } - elseif( iCalUtilityFunctions::_isArrayTimestampDate( $year )) { - $year['tz'] = 'UTC'; - $input['value'] = iCalUtilityFunctions::_timestamp2date( $year, 7 ); - $input['params'] = iCalUtilityFunctions::_setParams( $month, array( 'VALUE' => 'DATE-TIME' )); - } - elseif( 8 <= strlen( trim( $year ))) { // ex. 2006-08-03 10:12:18 - $input['value'] = iCalUtilityFunctions::_strdate2date( $year, 7 ); - unset( $input['value']['unparsedtext'] ); - $input['params'] = iCalUtilityFunctions::_setParams( $month, array( 'VALUE' => 'DATE-TIME' )); - } - else { - $input['value'] = array( 'year' => $year - , 'month' => $month - , 'day' => $day - , 'hour' => $hour - , 'min' => $min - , 'sec' => $sec ); - if( isset( $tz )) $input['value']['tz'] = $tz; - if(( isset( $tz ) && iCalUtilityFunctions::_isOffset( $tz )) || - ( isset( $input['params']['TZID'] ) && iCalUtilityFunctions::_isOffset( $input['params']['TZID'] ))) { - if( !isset( $tz ) && isset( $input['params']['TZID'] ) && iCalUtilityFunctions::_isOffset( $input['params']['TZID'] )) - $input['value']['tz'] = $input['params']['TZID']; - unset( $input['params']['TZID'] ); - $strdate = iCalUtilityFunctions::_date2strdate( $input['value'], 7 ); - $input['value'] = iCalUtilityFunctions::_strdate2date( $strdate, 7 ); - unset( $input['value']['unparsedtext'] ); - } - $input['params'] = iCalUtilityFunctions::_setParams( $params, array( 'VALUE' => 'DATE-TIME' )); - } - $parno = iCalUtilityFunctions::_existRem( $input['params'], 'VALUE', 'DATE-TIME', 7 ); // remove default - if( !isset( $input['value']['hour'] )) $input['value']['hour'] = 0; - if( !isset( $input['value']['min'] )) $input['value']['min'] = 0; - if( !isset( $input['value']['sec'] )) $input['value']['sec'] = 0; - $input['value']['tz'] = 'Z'; - return $input; - } -/** - * check index and set (an indexed) content in multiple value array - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.6.12 - 2011-01-03 - * @param array $valArr - * @param mixed $value - * @param array $params - * @param array $defaults - * @param int $index - * @return void - */ - public static function _setMval( & $valArr, $value, $params=FALSE, $defaults=FALSE, $index=FALSE ) { - if( !is_array( $valArr )) $valArr = array(); - if( $index ) - $index = $index - 1; - elseif( 0 < count( $valArr )) { - $keys = array_keys( $valArr ); - $index = end( $keys ) + 1; - } - else - $index = 0; - $valArr[$index] = array( 'value' => $value, 'params' => iCalUtilityFunctions::_setParams( $params, $defaults )); - ksort( $valArr ); - } -/** - * set input (formatted) parameters- component property attributes - * - * default parameters can be set, if missing - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 1.x.x - 2007-05-01 - * @param array $params - * @param array $defaults - * @return array - */ - public static function _setParams( $params, $defaults=FALSE ) { - if( !is_array( $params)) - $params = array(); - $input = array(); - foreach( $params as $paramKey => $paramValue ) { - if( is_array( $paramValue )) { - foreach( $paramValue as $pkey => $pValue ) { - if(( '"' == substr( $pValue, 0, 1 )) && ( '"' == substr( $pValue, -1 ))) - $paramValue[$pkey] = substr( $pValue, 1, ( strlen( $pValue ) - 2 )); - } - } - elseif(( '"' == substr( $paramValue, 0, 1 )) && ( '"' == substr( $paramValue, -1 ))) - $paramValue = substr( $paramValue, 1, ( strlen( $paramValue ) - 2 )); - if( 'VALUE' == strtoupper( $paramKey )) - $input['VALUE'] = strtoupper( $paramValue ); - else - $input[strtoupper( $paramKey )] = $paramValue; - } - if( is_array( $defaults )) { - foreach( $defaults as $paramKey => $paramValue ) { - if( !isset( $input[$paramKey] )) - $input[$paramKey] = $paramValue; - } - } - return (0 < count( $input )) ? $input : null; - } -/** - * break lines at pos 75 - * - * Lines of text SHOULD NOT be longer than 75 octets, excluding the line - * break. Long content lines SHOULD be split into a multiple line - * representations using a line "folding" technique. That is, a long - * line can be split between any two characters by inserting a CRLF - * immediately followed by a single linear white space character (i.e., - * SPACE, US-ASCII decimal 32 or HTAB, US-ASCII decimal 9). Any sequence - * of CRLF followed immediately by a single linear white space character - * is ignored (i.e., removed) when processing the content type. - * - * Edited 2007-08-26 by Anders Litzell, anders@litzell.se to fix bug where - * the reserved expression "\n" in the arg $string could be broken up by the - * folding of lines, causing ambiguity in the return string. - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.16.2 - 2012-12-18 - * @param string $value - * @return string - */ - public static function _size75( $string, $nl ) { - $tmp = $string; - $string = ''; - $cCnt = $x = 0; - while( TRUE ) { - if( !isset( $tmp[$x] )) { - $string .= $nl; // loop breakes here - break; - } - elseif(( 74 <= $cCnt ) && ( '\\' == $tmp[$x] ) && ( 'n' == $tmp[$x+1] )) { - $string .= $nl.' \n'; // don't break lines inside '\n' - $x += 2; - if( !isset( $tmp[$x] )) { - $string .= $nl; - break; - } - $cCnt = 3; - } - elseif( 75 <= $cCnt ) { - $string .= $nl.' '; - $cCnt = 1; - } - $byte = ord( $tmp[$x] ); - $string .= $tmp[$x]; - switch( TRUE ) { // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 - case(( $byte >= 0x20 ) && ( $byte <= 0x7F )): // characters U-00000000 - U-0000007F (same as ASCII) - $cCnt += 1; - break; // add a one byte character - case(( $byte & 0xE0) == 0xC0 ): // characters U-00000080 - U-000007FF, mask 110XXXXX - if( isset( $tmp[$x+1] )) { - $cCnt += 1; - $string .= $tmp[$x+1]; - $x += 1; // add a two bytes character - } - break; - case(( $byte & 0xF0 ) == 0xE0 ): // characters U-00000800 - U-0000FFFF, mask 1110XXXX - if( isset( $tmp[$x+2] )) { - $cCnt += 1; - $string .= $tmp[$x+1].$tmp[$x+2]; - $x += 2; // add a three bytes character - } - break; - case(( $byte & 0xF8 ) == 0xF0 ): // characters U-00010000 - U-001FFFFF, mask 11110XXX - if( isset( $tmp[$x+3] )) { - $cCnt += 1; - $string .= $tmp[$x+1].$tmp[$x+2].$tmp[$x+3]; - $x += 3; // add a four bytes character - } - break; - case(( $byte & 0xFC ) == 0xF8 ): // characters U-00200000 - U-03FFFFFF, mask 111110XX - if( isset( $tmp[$x+4] )) { - $cCnt += 1; - $string .= $tmp[$x+1].$tmp[$x+2].$tmp[$x+3].$tmp[$x+4]; - $x += 4; // add a five bytes character - } - break; - case(( $byte & 0xFE ) == 0xFC ): // characters U-04000000 - U-7FFFFFFF, mask 1111110X - if( isset( $tmp[$x+5] )) { - $cCnt += 1; - $string .= $tmp[$x+1].$tmp[$x+2].$tmp[$x+3].$tmp[$x+4].$tmp[$x+5]; - $x += 5; // add a six bytes character - } - default: // add any other byte without counting up $cCnt - break; - } // end switch( TRUE ) - $x += 1; // next 'byte' to test - } // end while( TRUE ) { - return $string; - } -/** - * sort callback functions for exdate - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.16.11 - 2013-01-12 - * @param array $a - * @param array $b - * @return int - */ - public static function _sortExdate1( $a, $b ) { - $as = sprintf( '%04d%02d%02d', $a['year'], $a['month'], $a['day'] ); - $as .= ( isset( $a['hour'] )) ? sprintf( '%02d%02d%02d', $a['hour'], $a['min'], $a['sec'] ) : ''; - $bs = sprintf( '%04d%02d%02d', $b['year'], $b['month'], $b['day'] ); - $bs .= ( isset( $b['hour'] )) ? sprintf( '%02d%02d%02d', $b['hour'], $b['min'], $b['sec'] ) : ''; - return strcmp( $as, $bs ); - } - public static function _sortExdate2( $a, $b ) { - $val = reset( $a['value'] ); - $as = sprintf( '%04d%02d%02d', $val['year'], $val['month'], $val['day'] ); - $as .= ( isset( $val['hour'] )) ? sprintf( '%02d%02d%02d', $val['hour'], $val['min'], $val['sec'] ) : ''; - $val = reset( $b['value'] ); - $bs = sprintf( '%04d%02d%02d', $val['year'], $val['month'], $val['day'] ); - $bs .= ( isset( $val['hour'] )) ? sprintf( '%02d%02d%02d', $val['hour'], $val['min'], $val['sec'] ) : ''; - return strcmp( $as, $bs ); - } -/** - * sort callback functions for rdate - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.16.9 - 2013-01-12 - * @param array $a - * @param array $b - * @return int - */ - public static function _sortRdate1( $a, $b ) { - $val = isset( $a['year'] ) ? $a : $a[0]; - $as = sprintf( '%04d%02d%02d', $val['year'], $val['month'], $val['day'] ); - $as .= ( isset( $val['hour'] )) ? sprintf( '%02d%02d%02d', $val['hour'], $val['min'], $val['sec'] ) : ''; - $val = isset( $b['year'] ) ? $b : $b[0]; - $bs = sprintf( '%04d%02d%02d', $val['year'], $val['month'], $val['day'] ); - $bs .= ( isset( $val['hour'] )) ? sprintf( '%02d%02d%02d', $val['hour'], $val['min'], $val['sec'] ) : ''; - return strcmp( $as, $bs ); - } - public static function _sortRdate2( $a, $b ) { - $val = isset( $a['value'][0]['year'] ) ? $a['value'][0] : $a['value'][0][0]; - $as = sprintf( '%04d%02d%02d', $val['year'], $val['month'], $val['day'] ); - $as .= ( isset( $val['hour'] )) ? sprintf( '%02d%02d%02d', $val['hour'], $val['min'], $val['sec'] ) : ''; - $val = isset( $b['value'][0]['year'] ) ? $b['value'][0] : $b['value'][0][0]; - $bs = sprintf( '%04d%02d%02d', $val['year'], $val['month'], $val['day'] ); - $bs .= ( isset( $val['hour'] )) ? sprintf( '%02d%02d%02d', $val['hour'], $val['min'], $val['sec'] ) : ''; - return strcmp( $as, $bs ); - } -/** - * step date, return updated date, array and timpstamp - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.14.1 - 2012-09-24 - * @param array $date, date to step - * @param int $timestamp - * @param array $step, default array( 'day' => 1 ) - * @return void - */ - public static function _stepdate( &$date, &$timestamp, $step=array( 'day' => 1 )) { - if( !isset( $date['hour'] )) $date['hour'] = 0; - if( !isset( $date['min'] )) $date['min'] = 0; - if( !isset( $date['sec'] )) $date['sec'] = 0; - foreach( $step as $stepix => $stepvalue ) - $date[$stepix] += $stepvalue; - $timestamp = mktime( $date['hour'], $date['min'], $date['sec'], $date['month'], $date['day'], $date['year'] ); - $d = date( 'Y-m-d-H-i-s', $timestamp); - $d = explode( '-', $d ); - $date = array( 'year' => $d[0], 'month' => $d[1], 'day' => $d[2], 'hour' => $d[3], 'min' => $d[4], 'sec' => $d[5] ); - foreach( $date as $k => $v ) - $date[$k] = (int) $v; - } -/** - * convert a date from specific string to array format - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.11.8 - 2012-01-27 - * @param mixed $input - * @return bool, TRUE on success - */ - public static function _strDate2arr( & $input ) { - if( is_array( $input )) - return FALSE; - if( 5 > strlen( (string) $input )) - return FALSE; - $work = $input; - if( 2 == substr_count( $work, '-' )) - $work = str_replace( '-', '', $work ); - if( 2 == substr_count( $work, '/' )) - $work = str_replace( '/', '', $work ); - if( !ctype_digit( substr( $work, 0, 8 ))) - return FALSE; - $temp = array( 'year' => (int) substr( $work, 0, 4 ) - , 'month' => (int) substr( $work, 4, 2 ) - , 'day' => (int) substr( $work, 6, 2 )); - if( !checkdate( $temp['month'], $temp['day'], $temp['year'] )) - return FALSE; - if( 8 == strlen( $work )) { - $input = $temp; - return TRUE; - } - if(( ' ' == substr( $work, 8, 1 )) || ( 'T' == substr( $work, 8, 1 )) || ( 't' == substr( $work, 8, 1 ))) - $work = substr( $work, 9 ); - elseif( ctype_digit( substr( $work, 8, 1 ))) - $work = substr( $work, 8 ); - else - return FALSE; - if( 2 == substr_count( $work, ':' )) - $work = str_replace( ':', '', $work ); - if( !ctype_digit( substr( $work, 0, 4 ))) - return FALSE; - $temp['hour'] = substr( $work, 0, 2 ); - $temp['min'] = substr( $work, 2, 2 ); - if((( 0 > $temp['hour'] ) || ( $temp['hour'] > 23 )) || - (( 0 > $temp['min'] ) || ( $temp['min'] > 59 ))) - return FALSE; - if( ctype_digit( substr( $work, 4, 2 ))) { - $temp['sec'] = substr( $work, 4, 2 ); - if(( 0 > $temp['sec'] ) || ( $temp['sec'] > 59 )) - return FALSE; - $len = 6; - } - else { - $temp['sec'] = 0; - $len = 4; - } - if( $len < strlen( $work)) - $temp['tz'] = trim( substr( $work, 6 )); - $input = $temp; - return TRUE; - } -/** - * ensures internal date-time/date format for input date-time/date in string fromat - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.14.1 - 2012-10-07 - * Modified to also return original string value by Yitzchok Lavi - * @param array $datetime - * @param int $parno optional, default FALSE - * @param moxed $wtz optional, default null - * @return array - */ - public static function _date_time_string( $datetime, $parno=FALSE ) { - return iCalUtilityFunctions::_strdate2date( $datetime, $parno, null ); - } - public static function _strdate2date( $datetime, $parno=FALSE, $wtz=null ) { - // save original input string to return it later - $unparseddatetime = $datetime; - $datetime = (string) trim( $datetime ); - $tz = null; - $offset = 0; - $tzSts = FALSE; - $len = strlen( $datetime ); - if( 'Z' == substr( $datetime, -1 )) { - $tz = 'Z'; - $datetime = trim( substr( $datetime, 0, ( $len - 1 ))); - $tzSts = TRUE; - $len = 88; - } - if( iCalUtilityFunctions::_isOffset( substr( $datetime, -5, 5 ))) { // [+/-]NNNN offset - $tz = substr( $datetime, -5, 5 ); - $datetime = trim( substr( $datetime, 0, ($len - 5))); - $len = strlen( $datetime ); - } - elseif( iCalUtilityFunctions::_isOffset( substr( $datetime, -7, 7 ))) { // [+/-]NNNNNN offset - $tz = substr( $datetime, -7, 7 ); - $datetime = trim( substr( $datetime, 0, ($len - 7))); - $len = strlen( $datetime ); - } - elseif( empty( $wtz ) && ctype_digit( substr( $datetime, 0, 4 )) && ctype_digit( substr( $datetime, -2, 2 )) && iCalUtilityFunctions::_strDate2arr( $datetime )) { - $output = $datetime; - if( !empty( $tz )) - $output['tz'] = 'Z'; - $output['unparsedtext'] = $unparseddatetime; - return $output; - } - else { - $cx = $tx = 0; // find any trailing timezone or offset - for( $cx = -1; $cx > ( 9 - $len ); $cx-- ) { - $char = substr( $datetime, $cx, 1 ); - if(( ' ' == $char) || ctype_digit( $char )) - break; // if exists, tz ends here.. . ? - else - $tx--; // tz length counter - } - if( 0 > $tx ) { // if any - $tz = substr( $datetime, $tx ); - $datetime = trim( substr( $datetime, 0, $len + $tx )); - $len = strlen( $datetime ); - } - if(( 17 <= $len ) || // long textual datetime - ( ctype_digit( substr( $datetime, 0, 8 )) && ( 'T' == substr( $datetime, 8, 1 )) && ctype_digit( substr( $datetime, -6, 6 ))) || - ( ctype_digit( substr( $datetime, 0, 14 )))) { - $len = 88; - $tzSts = TRUE; - } - else - $tz = null; // no tz for Y-m-d dates - } - if( empty( $tz ) && !empty( $wtz )) - $tz = $wtz; - if( 17 >= $len ) // any Y-m-d textual date - $tz = null; - if( !empty( $tz ) && ( 17 < $len )) { // tz set AND long textual datetime - if(( 'Z' != $tz ) && ( iCalUtilityFunctions::_isOffset( $tz ))) { - $offset = (string) iCalUtilityFunctions::_tz2offset( $tz ) * -1; - $tz = 'UTC'; - $tzSts = TRUE; - } - elseif( !empty( $wtz )) - $tzSts = TRUE; - $tz = trim( $tz ); - if(( 'Z' == $tz ) || ( 'GMT' == strtoupper( $tz ))) - $tz = 'UTC'; - if( 0 < substr_count( $datetime, '-' )) - $datetime = str_replace( '-', '/', $datetime ); - try { - $d = new DateTime( $datetime, new DateTimeZone( $tz )); - if( 0 != $offset ) // adjust for offset - $d->modify( $offset.' seconds' ); - $datestring = $d->format( 'Y-m-d-H-i-s' ); - unset( $d ); - } - catch( Exception $e ) { - $datestring = date( 'Y-m-d-H-i-s', strtotime( $datetime )); - } - } // end if( !empty( $tz ) && ( 17 < $len )) - else - $datestring = date( 'Y-m-d-H-i-s', strtotime( $datetime )); -// echo " _strdate2date input=$datetime, tz=$tz, offset=$offset, wtz=$wtz, len=$len, prepDate=$datestring\n"; - if( 'UTC' == $tz ) - $tz = 'Z'; - $d = explode( '-', $datestring ); - $output = array( 'year' => $d[0], 'month' => $d[1], 'day' => $d[2] ); - if((( FALSE !== $parno ) && ( 3 != $parno )) || // parno is set to 6 or 7 - (( FALSE === $parno ) && ( 'Z' == $tz )) || // parno is not set and UTC - (( FALSE === $parno ) && ( 'Z' != $tz ) && ( 0 != $d[3] + $d[4] + $d[5] ) && ( 17 < $len ))) { // !parno and !UTC and 0 != hour+min+sec and long input text - $output['hour'] = $d[3]; - $output['min'] = $d[4]; - $output['sec'] = $d[5]; - if(( $tzSts || ( 7 == $parno )) && !empty( $tz )) - $output['tz'] = $tz; - } - // return original string in the array in case strtotime failed to make sense of it - $output['unparsedtext'] = $unparseddatetime; - return $output; - } -/********************************************************************************/ -/** - * special characters management output - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.16.2 - 2012-12-18 - * @param string $string - * @param string $format - * @param string $nl - * @return string - */ - public static function _strrep( $string, $format, $nl ) { - switch( $format ) { - case 'xcal': - $string = str_replace( '\n', $nl, $string); - $string = htmlspecialchars( strip_tags( stripslashes( urldecode ( $string )))); - break; - default: - $pos = 0; - $specChars = array( 'n', 'N', 'r', ',', ';' ); - while( isset( $string[$pos] )) { - if( FALSE === ( $pos = strpos( $string, "\\", $pos ))) - break; - if( !in_array( substr( $string, $pos, 1 ), $specChars )) { - $string = substr( $string, 0, $pos )."\\".substr( $string, ( $pos + 1 )); - $pos += 1; - } - $pos += 1; - } - if( FALSE !== strpos( $string, '"' )) - $string = str_replace('"', "'", $string); - if( FALSE !== strpos( $string, ',' )) - $string = str_replace(',', '\,', $string); - if( FALSE !== strpos( $string, ';' )) - $string = str_replace(';', '\;', $string); - if( FALSE !== strpos( $string, "\r\n" )) - $string = str_replace( "\r\n", '\n', $string); - elseif( FALSE !== strpos( $string, "\r" )) - $string = str_replace( "\r", '\n', $string); - elseif( FALSE !== strpos( $string, "\n" )) - $string = str_replace( "\n", '\n', $string); - if( FALSE !== strpos( $string, '\N' )) - $string = str_replace( '\N', '\n', $string); -// if( FALSE !== strpos( $string, $nl )) - $string = str_replace( $nl, '\n', $string); - break; - } - return $string; - } -/** - * special characters management input (from iCal file) - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.16.2 - 2012-12-18 - * @param string $string - * @return string - */ - public static function _strunrep( $string ) { - $string = str_replace( '\\\\', '\\', $string); - $string = str_replace( '\,', ',', $string); - $string = str_replace( '\;', ';', $string); -// $string = str_replace( '\n', $nl, $string); // ?? - return $string; - } -/** - * convert timestamp to date array, default UTC or adjusted for offset/timezone - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.15.1 - 2012-10-17 - * @param mixed $timestamp - * @param int $parno - * @param string $wtz - * @return array - */ - public static function _timestamp2date( $timestamp, $parno=6, $wtz=null ) { - if( is_array( $timestamp )) { - $tz = ( isset( $timestamp['tz'] )) ? $timestamp['tz'] : $wtz; - $timestamp = $timestamp['timestamp']; - } - $tz = ( isset( $tz )) ? $tz : $wtz; - if( empty( $tz ) || ( 'Z' == $tz ) || ( 'GMT' == strtoupper( $tz ))) - $tz = 'UTC'; - elseif( iCalUtilityFunctions::_isOffset( $tz )) { - $offset = iCalUtilityFunctions::_tz2offset( $tz ); - $tz = 'UTC'; - } - try { - $d = new DateTime( "@$timestamp" ); // set UTC date - if( isset( $offset ) && ( 0 != $offset )) // adjust for offset - $d->modify( $offset.' seconds' ); - elseif( 'UTC' != $tz ) - $d->setTimezone( new DateTimeZone( $tz )); // convert to local date - $date = $d->format( 'Y-m-d-H-i-s' ); - unset( $d ); - } - catch( Exception $e ) { - $date = date( 'Y-m-d-H-i-s', $timestamp ); - } - $date = explode( '-', $date ); - $output = array( 'year' => $date[0], 'month' => $date[1], 'day' => $date[2] ); - if( 3 != $parno ) { - $output['hour'] = $date[3]; - $output['min'] = $date[4]; - $output['sec'] = $date[5]; - if( 'UTC' == $tz && ( !isset( $offset ) || ( 0 == $offset ))) - $output['tz'] = 'Z'; - } - return $output; - } -/** - * convert timestamp (seconds) to duration in array format - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.6.23 - 2010-10-23 - * @param int $timestamp - * @return array, duration format - */ - public static function _timestamp2duration( $timestamp ) { - $dur = array(); - $dur['week'] = (int) floor( $timestamp / ( 7 * 24 * 60 * 60 )); - $timestamp = $timestamp % ( 7 * 24 * 60 * 60 ); - $dur['day'] = (int) floor( $timestamp / ( 24 * 60 * 60 )); - $timestamp = $timestamp % ( 24 * 60 * 60 ); - $dur['hour'] = (int) floor( $timestamp / ( 60 * 60 )); - $timestamp = $timestamp % ( 60 * 60 ); - $dur['min'] = (int) floor( $timestamp / ( 60 )); - $dur['sec'] = (int) $timestamp % ( 60 ); - return $dur; - } -/** - * transforms a dateTime from a timezone to another using PHP DateTime and DateTimeZone class (PHP >= PHP 5.2.0) - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.15.1 - 2012-10-17 - * @param mixed $date, date to alter - * @param string $tzFrom, PHP valid 'from' timezone - * @param string $tzTo, PHP valid 'to' timezone, default 'UTC' - * @param string $format, date output format, default 'Ymd\THis' - * @return bool - */ - public static function transformDateTime( & $date, $tzFrom, $tzTo='UTC', $format = 'Ymd\THis' ) { - if( is_array( $date ) && isset( $date['timestamp'] )) { - try { - $d = new DateTime( "@{$date['timestamp']}" ); // set UTC date - $d->setTimezone(new DateTimeZone( $tzFrom )); // convert to 'from' date - } - catch( Exception $e ) { return FALSE; } - } - else { - if( iCalUtilityFunctions::_isArrayDate( $date )) { - if( isset( $date['tz'] )) - unset( $date['tz'] ); - $date = iCalUtilityFunctions::_date2strdate( iCalUtilityFunctions::_chkDateArr( $date )); - } - if( 'Z' == substr( $date, -1 )) - $date = substr( $date, 0, ( strlen( $date ) - 2 )); - try { $d = new DateTime( $date, new DateTimeZone( $tzFrom )); } - catch( Exception $e ) { return FALSE; } - } - try { $d->setTimezone( new DateTimeZone( $tzTo )); } - catch( Exception $e ) { return FALSE; } - $date = $d->format( $format ); - return TRUE; - } -/** - * convert offset, [+/-]HHmm[ss], to seconds, used when correcting UTC to localtime or v.v. - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.11.4 - 2012-01-11 - * @param string $offset - * @return integer - */ - public static function _tz2offset( $tz ) { - $tz = trim( (string) $tz ); - $offset = 0; - if((( 5 != strlen( $tz )) && ( 7 != strlen( $tz ))) || - (( '+' != substr( $tz, 0, 1 )) && ( '-' != substr( $tz, 0, 1 ))) || - (( '0000' >= substr( $tz, 1, 4 )) && ( '9999' < substr( $tz, 1, 4 ))) || - (( 7 == strlen( $tz )) && ( '00' > substr( $tz, 5, 2 )) && ( '99' < substr( $tz, 5, 2 )))) - return $offset; - $hours2sec = (int) substr( $tz, 1, 2 ) * 3600; - $min2sec = (int) substr( $tz, 3, 2 ) * 60; - $sec = ( 7 == strlen( $tz )) ? (int) substr( $tz, -2 ) : '00'; - $offset = $hours2sec + $min2sec + $sec; - $offset = ('-' == substr( $tz, 0, 1 )) ? $offset * -1 : $offset; - return $offset; - } -} -/*********************************************************************************/ -/* iCalcreator vCard helper functions */ -/*********************************************************************************/ -/** - * convert single ATTENDEE, CONTACT or ORGANIZER (in email format) to vCard - * returns vCard/TRUE or if directory (if set) or file write is unvalid, FALSE - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.12.2 - 2012-07-11 - * @param object $email - * $param string $version, vCard version (default 2.1) - * $param string $directory, where to save vCards (default FALSE) - * $param string $ext, vCard file extension (default 'vcf') - * @return mixed - */ -function iCal2vCard( $email, $version='2.1', $directory=FALSE, $ext='vcf' ) { - if( FALSE === ( $pos = strpos( $email, '@' ))) - return FALSE; - if( $directory ) { - if( DIRECTORY_SEPARATOR != substr( $directory, ( 0 - strlen( DIRECTORY_SEPARATOR )))) - $directory .= DIRECTORY_SEPARATOR; - if( !is_dir( $directory ) || !is_writable( $directory )) - return FALSE; - } - /* prepare vCard */ - $email = str_replace( 'MAILTO:', '', $email ); - $name = $person = substr( $email, 0, $pos ); - if( ctype_upper( $name ) || ctype_lower( $name )) - $name = array( $name ); - else { - if( FALSE !== ( $pos = strpos( $name, '.' ))) { - $name = explode( '.', $name ); - foreach( $name as $k => $part ) - $name[$k] = ucfirst( $part ); - } - else { // split camelCase - $chars = $name; - $name = array( $chars[0] ); - $k = 0; - $x = 1; - while( FALSE !== ( $char = substr( $chars, $x, 1 ))) { - if( ctype_upper( $char )) { - $k += 1; - $name[$k] = ''; - } - $name[$k] .= $char; - $x++; - } - } - } - $nl = "\r\n"; - $FN = 'FN:'.implode( ' ', $name ).$nl; - $name = array_reverse( $name ); - $N = 'N:'.array_shift( $name ); - $scCnt = 0; - while( NULL != ( $part = array_shift( $name ))) { - if(( '4.0' != $version ) || ( 4 > $scCnt )) - $scCnt += 1; - $N .= ';'.$part; - } - while(( '4.0' == $version ) && ( 4 > $scCnt )) { - $N .= ';'; - $scCnt += 1; - } - $N .= $nl; - $EMAIL = 'EMAIL:'.$email.$nl; - /* create vCard */ - $vCard = 'BEGIN:VCARD'.$nl; - $vCard .= "VERSION:$version$nl"; - $vCard .= 'PRODID:-//kigkonsult.se '.ICALCREATOR_VERSION."//$nl"; - $vCard .= $N; - $vCard .= $FN; - $vCard .= $EMAIL; - $vCard .= 'REV:'.gmdate( 'Ymd\THis\Z' ).$nl; - $vCard .= 'END:VCARD'.$nl; - /* save each vCard as (unique) single file */ - if( $directory ) { - $fname = $directory.preg_replace( '/[^a-z0-9.]/i', '', $email ); - $cnt = 1; - $dbl = ''; - while( is_file ( $fname.$dbl.'.'.$ext )) { - $cnt += 1; - $dbl = "_$cnt"; - } - if( FALSE === file_put_contents( $fname, $fname.$dbl.'.'.$ext )) - return FALSE; - return TRUE; - } - /* return vCard */ - else - return $vCard; -} -/** - * convert ATTENDEEs, CONTACTs and ORGANIZERs (in email format) to vCards - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.12.2 - 2012-05-07 - * @param object $calendar, iCalcreator vcalendar instance reference - * $param string $version, vCard version (default 2.1) - * $param string $directory, where to save vCards (default FALSE) - * $param string $ext, vCard file extension (default 'vcf') - * @return mixed - */ -function iCal2vCards( & $calendar, $version='2.1', $directory=FALSE, $ext='vcf' ) { - $hits = array(); - $vCardP = array( 'ATTENDEE', 'CONTACT', 'ORGANIZER' ); - foreach( $vCardP as $prop ) { - $hits2 = $calendar->getProperty( $prop ); - foreach( $hits2 as $propValue => $occCnt ) { - if( FALSE === ( $pos = strpos( $propValue, '@' ))) - continue; - $propValue = str_replace( 'MAILTO:', '', $propValue ); - if( isset( $hits[$propValue] )) - $hits[$propValue] += $occCnt; - else - $hits[$propValue] = $occCnt; - } - } - if( empty( $hits )) - return FALSE; - ksort( $hits ); - $output = ''; - foreach( $hits as $email => $skip ) { - $res = iCal2vCard( $email, $version, $directory, $ext ); - if( $directory && !$res ) - return FALSE; - elseif( !$res ) - return $res; - else - $output .= $res; - } - if( $directory ) - return TRUE; - if( !empty( $output )) - return $output; - return FALSE; -} -/*********************************************************************************/ -/* iCalcreator XML (rfc6321) helper functions */ -/*********************************************************************************/ -/** - * format iCal XML output, rfc6321, using PHP SimpleXMLElement - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.15.6 - 2012-10-19 - * @param object $calendar, iCalcreator vcalendar instance reference - * @return string - */ -function iCal2XML( & $calendar ) { - /** fix an SimpleXMLElement instance and create root element */ - $xmlstr = ''; - $xmlstr .= ''; - $xmlstr .= ''; - $xml = new SimpleXMLElement( $xmlstr ); - $vcalendar = $xml->addChild( 'vcalendar' ); - /** fix calendar properties */ - $properties = $vcalendar->addChild( 'properties' ); - $calProps = array( 'prodid', 'version', 'calscale', 'method' ); - foreach( $calProps as $calProp ) { - if( FALSE !== ( $content = $calendar->getProperty( $calProp ))) - _addXMLchild( $properties, $calProp, 'text', $content ); - } - while( FALSE !== ( $content = $calendar->getProperty( FALSE, FALSE, TRUE ))) - _addXMLchild( $properties, $content[0], 'unknown', $content[1]['value'], $content[1]['params'] ); - $langCal = $calendar->getConfig( 'language' ); - /** prepare to fix components with properties */ - $components = $vcalendar->addChild( 'components' ); - $comps = array( 'vtimezone', 'vevent', 'vtodo', 'vjournal', 'vfreebusy' ); - foreach( $comps as $compName ) { - switch( $compName ) { - case 'vevent': - case 'vtodo': - $subComps = array( 'valarm' ); - break; - case 'vjournal': - case 'vfreebusy': - $subComps = array(); - break; - case 'vtimezone': - $subComps = array( 'standard', 'daylight' ); - break; - } // end switch( $compName ) - /** fix component properties */ - while( FALSE !== ( $component = $calendar->getComponent( $compName ))) { - $child = $components->addChild( $compName ); - $properties = $child->addChild( 'properties' ); - $langComp = $component->getConfig( 'language' ); - $props = $component->getConfig( 'setPropertyNames' ); - foreach( $props as $prop ) { - switch( strtolower( $prop )) { - case 'attach': // may occur multiple times, below - while( FALSE !== ( $content = $component->getProperty( $prop, FALSE, TRUE ))) { - $type = ( isset( $content['params']['VALUE'] ) && ( 'BINARY' == $content['params']['VALUE'] )) ? 'binary' : 'uri'; - unset( $content['params']['VALUE'] ); - _addXMLchild( $properties, $prop, $type, $content['value'], $content['params'] ); - } - break; - case 'attendee': - while( FALSE !== ( $content = $component->getProperty( $prop, FALSE, TRUE ))) { - if( isset( $content['params']['CN'] ) && !isset( $content['params']['LANGUAGE'] )) { - if( $langComp ) - $content['params']['LANGUAGE'] = $langComp; - elseif( $langCal ) - $content['params']['LANGUAGE'] = $langCal; - } - _addXMLchild( $properties, $prop, 'cal-address', $content['value'], $content['params'] ); - } - break; - case 'exdate': - while( FALSE !== ( $content = $component->getProperty( $prop, FALSE, TRUE ))) { - $type = ( isset( $content['params']['VALUE'] ) && ( 'DATE' == $content['params']['VALUE'] )) ? 'date' : 'date-time'; - unset( $content['params']['VALUE'] ); - _addXMLchild( $properties, $prop, $type, $content['value'], $content['params'] ); - } - break; - case 'freebusy': - while( FALSE !== ( $content = $component->getProperty( $prop, FALSE, TRUE ))) { - if( is_array( $content ) && isset( $content['value']['fbtype'] )) { - $content['params']['FBTYPE'] = $content['value']['fbtype']; - unset( $content['value']['fbtype'] ); - } - _addXMLchild( $properties, $prop, 'period', $content['value'], $content['params'] ); - } - break; - case 'request-status': - while( FALSE !== ( $content = $component->getProperty( $prop, FALSE, TRUE ))) { - if( !isset( $content['params']['LANGUAGE'] )) { - if( $langComp ) - $content['params']['LANGUAGE'] = $langComp; - elseif( $langCal ) - $content['params']['LANGUAGE'] = $langCal; - } - _addXMLchild( $properties, $prop, 'rstatus', $content['value'], $content['params'] ); - } - break; - case 'rdate': - while( FALSE !== ( $content = $component->getProperty( $prop, FALSE, TRUE ))) { - $type = 'date-time'; - if( isset( $content['params']['VALUE'] )) { - if( 'DATE' == $content['params']['VALUE'] ) - $type = 'date'; - elseif( 'PERIOD' == $content['params']['VALUE'] ) - $type = 'period'; - } - unset( $content['params']['VALUE'] ); - _addXMLchild( $properties, $prop, $type, $content['value'], $content['params'] ); - } - break; - case 'categories': - case 'comment': - case 'contact': - case 'description': - case 'related-to': - case 'resources': - while( FALSE !== ( $content = $component->getProperty( $prop, FALSE, TRUE ))) { - if(( 'related-to' != $prop ) && !isset( $content['params']['LANGUAGE'] )) { - if( $langComp ) - $content['params']['LANGUAGE'] = $langComp; - elseif( $langCal ) - $content['params']['LANGUAGE'] = $langCal; - } - _addXMLchild( $properties, $prop, 'text', $content['value'], $content['params'] ); - } - break; - case 'x-prop': - while( FALSE !== ( $content = $component->getProperty( $prop, FALSE, TRUE ))) - _addXMLchild( $properties, $content[0], 'unknown', $content[1]['value'], $content[1]['params'] ); - break; - case 'created': // single occurence below, if set - case 'completed': - case 'dtstamp': - case 'last-modified': - $utcDate = TRUE; - case 'dtstart': - case 'dtend': - case 'due': - case 'recurrence-id': - if( FALSE !== ( $content = $component->getProperty( $prop, FALSE, TRUE ))) { - $type = ( isset( $content['params']['VALUE'] ) && ( 'DATE' == $content['params']['VALUE'] )) ? 'date' : 'date-time'; - unset( $content['params']['VALUE'] ); - if(( isset( $content['params']['TZID'] ) && empty( $content['params']['TZID'] )) || @is_null( $content['params']['TZID'] )) - unset( $content['params']['TZID'] ); - _addXMLchild( $properties, $prop, $type, $content['value'], $content['params'] ); - } - unset( $utcDate ); - break; - case 'duration': - if( FALSE !== ( $content = $component->getProperty( $prop, FALSE, TRUE ))) { - if( !isset( $content['value']['relatedStart'] ) || ( TRUE !== $content['value']['relatedStart'] )) - $content['params']['RELATED'] = 'END'; - _addXMLchild( $properties, $prop, 'duration', $content['value'], $content['params'] ); - } - break; - case 'rrule': - while( FALSE !== ( $content = $component->getProperty( $prop, FALSE, TRUE ))) - _addXMLchild( $properties, $prop, 'recur', $content['value'], $content['params'] ); - break; - case 'class': - case 'location': - case 'status': - case 'summary': - case 'transp': - case 'tzid': - case 'uid': - if( FALSE !== ( $content = $component->getProperty( $prop, FALSE, TRUE ))) { - if((( 'location' == $prop ) || ( 'summary' == $prop )) && !isset( $content['params']['LANGUAGE'] )) { - if( $langComp ) - $content['params']['LANGUAGE'] = $langComp; - elseif( $langCal ) - $content['params']['LANGUAGE'] = $langCal; - } - _addXMLchild( $properties, $prop, 'text', $content['value'], $content['params'] ); - } - break; - case 'geo': - if( FALSE !== ( $content = $component->getProperty( $prop, FALSE, TRUE ))) - _addXMLchild( $properties, $prop, 'geo', $content['value'], $content['params'] ); - break; - case 'organizer': - if( FALSE !== ( $content = $component->getProperty( $prop, FALSE, TRUE ))) { - if( isset( $content['params']['CN'] ) && !isset( $content['params']['LANGUAGE'] )) { - if( $langComp ) - $content['params']['LANGUAGE'] = $langComp; - elseif( $langCal ) - $content['params']['LANGUAGE'] = $langCal; - } - _addXMLchild( $properties, $prop, 'cal-address', $content['value'], $content['params'] ); - } - break; - case 'percent-complete': - case 'priority': - case 'sequence': - if( FALSE !== ( $content = $component->getProperty( $prop, FALSE, TRUE ))) - _addXMLchild( $properties, $prop, 'integer', $content['value'], $content['params'] ); - break; - case 'tzurl': - case 'url': - if( FALSE !== ( $content = $component->getProperty( $prop, FALSE, TRUE ))) - _addXMLchild( $properties, $prop, 'uri', $content['value'], $content['params'] ); - break; - } // end switch( $prop ) - } // end foreach( $props as $prop ) - /** fix subComponent properties, if any */ - foreach( $subComps as $subCompName ) { - while( FALSE !== ( $subcomp = $component->getComponent( $subCompName ))) { - $child2 = $child->addChild( $subCompName ); - $properties = $child2->addChild( 'properties' ); - $langComp = $subcomp->getConfig( 'language' ); - $subCompProps = $subcomp->getConfig( 'setPropertyNames' ); - foreach( $subCompProps as $prop ) { - switch( strtolower( $prop )) { - case 'attach': // may occur multiple times, below - while( FALSE !== ( $content = $subcomp->getProperty( $prop, FALSE, TRUE ))) { - $type = ( isset( $content['params']['VALUE'] ) && ( 'BINARY' == $content['params']['VALUE'] )) ? 'binary' : 'uri'; - unset( $content['params']['VALUE'] ); - _addXMLchild( $properties, $prop, $type, $content['value'], $content['params'] ); - } - break; - case 'attendee': - while( FALSE !== ( $content = $subcomp->getProperty( $prop, FALSE, TRUE ))) { - if( isset( $content['params']['CN'] ) && !isset( $content['params']['LANGUAGE'] )) { - if( $langComp ) - $content['params']['LANGUAGE'] = $langComp; - elseif( $langCal ) - $content['params']['LANGUAGE'] = $langCal; - } - _addXMLchild( $properties, $prop, 'cal-address', $content['value'], $content['params'] ); - } - break; - case 'comment': - case 'tzname': - while( FALSE !== ( $content = $subcomp->getProperty( $prop, FALSE, TRUE ))) { - if( !isset( $content['params']['LANGUAGE'] )) { - if( $langComp ) - $content['params']['LANGUAGE'] = $langComp; - elseif( $langCal ) - $content['params']['LANGUAGE'] = $langCal; - } - _addXMLchild( $properties, $prop, 'text', $content['value'], $content['params'] ); - } - break; - case 'rdate': - while( FALSE !== ( $content = $subcomp->getProperty( $prop, FALSE, TRUE ))) { - $type = 'date-time'; - if( isset( $content['params']['VALUE'] )) { - if( 'DATE' == $content['params']['VALUE'] ) - $type = 'date'; - elseif( 'PERIOD' == $content['params']['VALUE'] ) - $type = 'period'; - } - unset( $content['params']['VALUE'] ); - _addXMLchild( $properties, $prop, $type, $content['value'], $content['params'] ); - } - break; - case 'x-prop': - while( FALSE !== ( $content = $subcomp->getProperty( $prop, FALSE, TRUE ))) - _addXMLchild( $properties, $content[0], 'unknown', $content[1]['value'], $content[1]['params'] ); - break; - case 'action': // single occurence below, if set - case 'description': - case 'summary': - if( FALSE !== ( $content = $subcomp->getProperty( $prop, FALSE, TRUE ))) { - if(( 'action' != $prop ) && !isset( $content['params']['LANGUAGE'] )) { - if( $langComp ) - $content['params']['LANGUAGE'] = $langComp; - elseif( $langCal ) - $content['params']['LANGUAGE'] = $langCal; - } - _addXMLchild( $properties, $prop, 'text', $content['value'], $content['params'] ); - } - break; - case 'dtstart': - if( FALSE !== ( $content = $subcomp->getProperty( $prop, FALSE, TRUE ))) { - unset( $content['value']['tz'], $content['params']['VALUE'] ); // always local time - _addXMLchild( $properties, $prop, 'date-time', $content['value'], $content['params'] ); - } - break; - case 'duration': - if( FALSE !== ( $content = $subcomp->getProperty( $prop, FALSE, TRUE ))) - _addXMLchild( $properties, $prop, 'duration', $content['value'], $content['params'] ); - break; - case 'repeat': - if( FALSE !== ( $content = $subcomp->getProperty( $prop, FALSE, TRUE ))) - _addXMLchild( $properties, $prop, 'integer', $content['value'], $content['params'] ); - break; - case 'trigger': - if( FALSE !== ( $content = $subcomp->getProperty( $prop, FALSE, TRUE ))) { - if( isset( $content['value']['year'] ) && - isset( $content['value']['month'] ) && - isset( $content['value']['day'] )) - $type = 'date-time'; - else { - $type = 'duration'; - if( !isset( $content['value']['relatedStart'] ) || ( TRUE !== $content['value']['relatedStart'] )) - $content['params']['RELATED'] = 'END'; - } - _addXMLchild( $properties, $prop, $type, $content['value'], $content['params'] ); - } - break; - case 'tzoffsetto': - case 'tzoffsetfrom': - if( FALSE !== ( $content = $subcomp->getProperty( $prop, FALSE, TRUE ))) - _addXMLchild( $properties, $prop, 'utc-offset', $content['value'], $content['params'] ); - break; - case 'rrule': - while( FALSE !== ( $content = $subcomp->getProperty( $prop, FALSE, TRUE ))) - _addXMLchild( $properties, $prop, 'recur', $content['value'], $content['params'] ); - break; - } // switch( $prop ) - } // end foreach( $subCompProps as $prop ) - } // end while( FALSE !== ( $subcomp = $component->getComponent( subCompName ))) - } // end foreach( $subCombs as $subCompName ) - } // end while( FALSE !== ( $component = $calendar->getComponent( $compName ))) - } // end foreach( $comps as $compName) - return $xml->asXML(); -} -/** - * Add children to a SimpleXMLelement - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.15.5 - 2012-10-19 - * @param object $parent, reference to a SimpleXMLelement node - * @param string $name, new element node name - * @param string $type, content type, subelement(-s) name - * @param string $content, new subelement content - * @param array $params, new element 'attributes' - * @return void - */ -function _addXMLchild( & $parent, $name, $type, $content, $params=array()) { - /** create new child node */ - $name = strtolower( $name ); - $child = $parent->addChild( $name ); - if( isset( $params['VALUE'] )) - unset( $params['VALUE'] ); - if( !empty( $params )) { - $parameters = $child->addChild( 'parameters' ); - foreach( $params as $param => $parVal ) { - $param = strtolower( $param ); - if( 'x-' == substr( $param, 0, 2 )) { - $p1 = $parameters->addChild( $param ); - $p2 = $p1->addChild( 'unknown', htmlspecialchars( $parVal )); - } - else { - $p1 = $parameters->addChild( $param ); - switch( $param ) { - case 'altrep': - case 'dir': $ptype = 'uri'; break; - case 'delegated-from': - case 'delegated-to': - case 'member': - case 'sent-by': $ptype = 'cal-address'; break; - case 'rsvp': $ptype = 'boolean'; break ; - default: $ptype = 'text'; break; - } - if( is_array( $parVal )) { - foreach( $parVal as $pV ) - $p2 = $p1->addChild( $ptype, htmlspecialchars( $pV )); - } - else - $p2 = $p1->addChild( $ptype, htmlspecialchars( $parVal )); - } - } - } - if( empty( $content ) && ( '0' != $content )) - return; - /** store content */ - switch( $type ) { - case 'binary': - $v = $child->addChild( $type, $content ); - break; - case 'boolean': - break; - case 'cal-address': - $v = $child->addChild( $type, $content ); - break; - case 'date': - if( array_key_exists( 'year', $content )) - $content = array( $content ); - foreach( $content as $date ) { - $str = sprintf( '%04d-%02d-%02d', $date['year'], $date['month'], $date['day'] ); - $v = $child->addChild( $type, $str ); - } - break; - case 'date-time': - if( array_key_exists( 'year', $content )) - $content = array( $content ); - foreach( $content as $dt ) { - if( !isset( $dt['hour'] )) $dt['hour'] = 0; - if( !isset( $dt['min'] )) $dt['min'] = 0; - if( !isset( $dt['sec'] )) $dt['sec'] = 0; - $str = sprintf( '%04d-%02d-%02dT%02d:%02d:%02d', $dt['year'], $dt['month'], $dt['day'], $dt['hour'], $dt['min'], $dt['sec'] ); - if( isset( $dt['tz'] ) && ( 'Z' == $dt['tz'] )) - $str .= 'Z'; - $v = $child->addChild( $type, $str ); - } - break; - case 'duration': - $output = (( 'trigger' == $name ) && ( FALSE !== $content['before'] )) ? '-' : ''; - $v = $child->addChild( $type, $output.iCalUtilityFunctions::_duration2str( $content ) ); - break; - case 'geo': - $v1 = $child->addChild( 'latitude', number_format( (float) $content['latitude'], 6, '.', '' )); - $v1 = $child->addChild( 'longitude', number_format( (float) $content['longitude'], 6, '.', '' )); - break; - case 'integer': - $v = $child->addChild( $type, $content ); - break; - case 'period': - if( !is_array( $content )) - break; - foreach( $content as $period ) { - $v1 = $child->addChild( $type ); - $str = sprintf( '%04d-%02d-%02dT%02d:%02d:%02d', $period[0]['year'], $period[0]['month'], $period[0]['day'], $period[0]['hour'], $period[0]['min'], $period[0]['sec'] ); - if( isset( $period[0]['tz'] ) && ( 'Z' == $period[0]['tz'] )) - $str .= 'Z'; - $v2 = $v1->addChild( 'start', $str ); - if( array_key_exists( 'year', $period[1] )) { - $str = sprintf( '%04d-%02d-%02dT%02d:%02d:%02d', $period[1]['year'], $period[1]['month'], $period[1]['day'], $period[1]['hour'], $period[1]['min'], $period[1]['sec'] ); - if( isset($period[1]['tz'] ) && ( 'Z' == $period[1]['tz'] )) - $str .= 'Z'; - $v2 = $v1->addChild( 'end', $str ); - } - else - $v2 = $v1->addChild( 'duration', iCalUtilityFunctions::_duration2str( $period[1] )); - } - break; - case 'recur': - foreach( $content as $rulelabel => $rulevalue ) { - $rulelabel = strtolower( $rulelabel ); - switch( $rulelabel ) { - case 'until': - if( isset( $rulevalue['hour'] )) - $str = sprintf( '%04d-%02d-%02dT%02d:%02d:%02dZ', $rulevalue['year'], $rulevalue['month'], $rulevalue['day'], $rulevalue['hour'], $rulevalue['min'], $rulevalue['sec'] ); - else - $str = sprintf( '%04d-%02d-%02d', $rulevalue['year'], $rulevalue['month'], $rulevalue['day'] ); - $v = $child->addChild( $rulelabel, $str ); - break; - case 'bysecond': - case 'byminute': - case 'byhour': - case 'bymonthday': - case 'byyearday': - case 'byweekno': - case 'bymonth': - case 'bysetpos': { - if( is_array( $rulevalue )) { - foreach( $rulevalue as $vix => $valuePart ) - $v = $child->addChild( $rulelabel, $valuePart ); - } - else - $v = $child->addChild( $rulelabel, $rulevalue ); - break; - } - case 'byday': { - if( isset( $rulevalue['DAY'] )) { - $str = ( isset( $rulevalue[0] )) ? $rulevalue[0] : ''; - $str .= $rulevalue['DAY']; - $p = $child->addChild( $rulelabel, $str ); - } - else { - foreach( $rulevalue as $valuePart ) { - if( isset( $valuePart['DAY'] )) { - $str = ( isset( $valuePart[0] )) ? $valuePart[0] : ''; - $str .= $valuePart['DAY']; - $p = $child->addChild( $rulelabel, $str ); - } - else - $p = $child->addChild( $rulelabel, $valuePart ); - } - } - break; - } - case 'freq': - case 'count': - case 'interval': - case 'wkst': - default: - $p = $child->addChild( $rulelabel, $rulevalue ); - break; - } // end switch( $rulelabel ) - } // end foreach( $content as $rulelabel => $rulevalue ) - break; - case 'rstatus': - $v = $child->addChild( 'code', number_format( (float) $content['statcode'], 2, '.', '')); - $v = $child->addChild( 'description', htmlspecialchars( $content['text'] )); - if( isset( $content['extdata'] )) - $v = $child->addChild( 'data', htmlspecialchars( $content['extdata'] )); - break; - case 'text': - if( !is_array( $content )) - $content = array( $content ); - foreach( $content as $part ) - $v = $child->addChild( $type, htmlspecialchars( $part )); - break; - case 'time': - break; - case 'uri': - $v = $child->addChild( $type, $content ); - break; - case 'utc-offset': - if( in_array( substr( $content, 0, 1 ), array( '-', '+' ))) { - $str = substr( $content, 0, 1 ); - $content = substr( $content, 1 ); - } - else - $str = '+'; - $str .= substr( $content, 0, 2 ).':'.substr( $content, 2, 2 ); - if( 4 < strlen( $content )) - $str .= ':'.substr( $content, 4 ); - $v = $child->addChild( $type, $str ); - break; - case 'unknown': - default: - if( is_array( $content )) - $content = implode( '', $content ); - $v = $child->addChild( 'unknown', htmlspecialchars( $content )); - break; - } -} -/** - * parse xml string into iCalcreator instance - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.11.2 - 2012-01-31 - * @param string $xmlstr - * @param array $iCalcfg iCalcreator config array (opt) - * @return mixed iCalcreator instance or FALSE on error - */ -function & XMLstr2iCal( $xmlstr, $iCalcfg=array()) { - libxml_use_internal_errors( TRUE ); - $xml = simplexml_load_string( $xmlstr ); - if( !$xml ) { - $str = ''; - $return = FALSE; - foreach( libxml_get_errors() as $error ) { - switch ( $error->level ) { - case LIBXML_ERR_FATAL: $str .= ' FATAL '; break; - case LIBXML_ERR_ERROR: $str .= ' ERROR '; break; - case LIBXML_ERR_WARNING: - default: $str .= ' WARNING '; break; - } - $str .= PHP_EOL.'Error when loading XML'; - if( !empty( $error->file )) - $str .= ', file:'.$error->file.', '; - $str .= ', line:'.$error->line; - $str .= ', ('.$error->code.') '.$error->message; - } - error_log( $str ); - if( LIBXML_ERR_WARNING != $error->level ) - return $return; - libxml_clear_errors(); - } - return xml2iCal( $xml, $iCalcfg ); -} -/** - * parse xml file into iCalcreator instance - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.11.2 - 2012-01-20 - * @param string $xmlfile - * @param array$iCalcfg iCalcreator config array (opt) - * @return mixediCalcreator instance or FALSE on error - */ -function & XMLfile2iCal( $xmlfile, $iCalcfg=array()) { - libxml_use_internal_errors( TRUE ); - $xml = simplexml_load_file( $xmlfile ); - if( !$xml ) { - $str = ''; - foreach( libxml_get_errors() as $error ) { - switch ( $error->level ) { - case LIBXML_ERR_FATAL: $str .= 'FATAL '; break; - case LIBXML_ERR_ERROR: $str .= 'ERROR '; break; - case LIBXML_ERR_WARNING: - default: $str .= 'WARNING '; break; - } - $str .= 'Failed loading XML'.PHP_EOL; - if( !empty( $error->file )) - $str .= ' file:'.$error->file.', '; - $str .= 'line:'.$error->line.PHP_EOL; - $str .= '('.$error->code.') '.$error->message.PHP_EOL; - } - error_log( $str ); - if( LIBXML_ERR_WARNING != $error->level ) - return FALSE; - libxml_clear_errors(); - } - return xml2iCal( $xml, $iCalcfg ); -} -/** - * parse SimpleXMLElement instance into iCalcreator instance - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.11.2 - 2012-01-27 - * @param object $xmlobj SimpleXMLElement - * @param array $iCalcfg iCalcreator config array (opt) - * @return mixed iCalcreator instance or FALSE on error - */ -function & XML2iCal( $xmlobj, $iCalcfg=array()) { - $iCal = new vcalendar( $iCalcfg ); - foreach( $xmlobj->children() as $icalendar ) { // vcalendar - foreach( $icalendar->children() as $calPart ) { // calendar properties and components - if( 'components' == $calPart->getName()) { - foreach( $calPart->children() as $component ) { // single components - if( 0 < $component->count()) - _getXMLComponents( $iCal, $component ); - } - } - elseif(( 'properties' == $calPart->getName()) && ( 0 < $calPart->count())) { - foreach( $calPart->children() as $calProp ) { // calendar properties - $propName = $calProp->getName(); - if(( 'calscale' != $propName ) && ( 'method' != $propName ) && ( 'x-' != substr( $propName,0,2 ))) - continue; - $params = array(); - foreach( $calProp->children() as $calPropElem ) { // single calendar property - if( 'parameters' == $calPropElem->getName()) - $params = _getXMLParams( $calPropElem ); - else - $iCal->setProperty( $propName, reset( $calPropElem ), $params ); - } // end foreach( $calProp->children() as $calPropElem ) - } // end foreach( $calPart->properties->children() as $calProp ) - } // end if( 0 < $calPart->properties->count()) - } // end foreach( $icalendar->children() as $calPart ) - } // end foreach( $xmlobj->children() as $icalendar ) - return $iCal; -} -/** - * parse SimpleXMLElement instance property parameters and return iCalcreator property parameter array - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.11.2 - 2012-01-15 - * @param object $parameters SimpleXMLElement - * @return array iCalcreator property parameter array - */ -function _getXMLParams( & $parameters ) { - if( 1 > $parameters->count()) - return array(); - $params = array(); - foreach( $parameters->children() as $parameter ) { // single parameter key - $key = strtoupper( $parameter->getName()); - $value = array(); - foreach( $parameter->children() as $paramValue ) // skip parameter value type - $value[] = reset( $paramValue ); - if( 2 > count( $value )) - $params[$key] = html_entity_decode( reset( $value )); - else - $params[$key] = $value; - } - return $params; -} -/** - * parse SimpleXMLElement instance components, create iCalcreator component and update - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.11.2 - 2012-01-15 - * @param array $iCal iCalcreator calendar instance - * @param object $component SimpleXMLElement - * @return void - */ -function _getXMLComponents( & $iCal, & $component ) { - $compName = $component->getName(); - $comp = & $iCal->newComponent( $compName ); - $subComponents = array( 'valarm', 'standard', 'daylight' ); - foreach( $component->children() as $compPart ) { // properties and (opt) subComponents - if( 1 > $compPart->count()) - continue; - if( in_array( $compPart->getName(), $subComponents )) - _getXMLComponents( $comp, $compPart ); - elseif( 'properties' == $compPart->getName()) { - foreach( $compPart->children() as $property ) // properties as single property - _getXMLProperties( $comp, $property ); - } - } // end foreach( $component->children() as $compPart ) -} -/** - * parse SimpleXMLElement instance property, create iCalcreator component property - * - * @author Kjell-Inge Gustafsson, kigkonsult - * @since 2.11.2 - 2012-01-27 - * @param array $iCal iCalcreator calendar instance - * @param object $component SimpleXMLElement - * @return void - */ -function _getXMLProperties( & $iCal, & $property ) { - $propName = $property->getName(); - $value = $params = array(); - $valueType = ''; - foreach( $property->children() as $propPart ) { // calendar property parameters (opt) and value(-s) - $valueType = $propPart->getName(); - if( 'parameters' == $valueType) { - $params = _getXMLParams( $propPart ); - continue; - } - switch( $valueType ) { - case 'binary': - $value = reset( $propPart ); - break; - case 'boolean': - break; - case 'cal-address': - $value = reset( $propPart ); - break; - case 'date': - $params['VALUE'] = 'DATE'; - case 'date-time': - if(( 'exdate' == $propName ) || ( 'rdate' == $propName )) - $value[] = reset( $propPart ); - else - $value = reset( $propPart ); - break; - case 'duration': - $value = reset( $propPart ); - break; -// case 'geo': - case 'latitude': - case 'longitude': - $value[$valueType] = reset( $propPart ); - break; - case 'integer': - $value = reset( $propPart ); - break; - case 'period': - if( 'rdate' == $propName ) - $params['VALUE'] = 'PERIOD'; - $pData = array(); - foreach( $propPart->children() as $periodPart ) - $pData[] = reset( $periodPart ); - if( !empty( $pData )) - $value[] = $pData; - break; -// case 'rrule': - case 'freq': - case 'count': - case 'until': - case 'interval': - case 'wkst': - $value[$valueType] = reset( $propPart ); - break; - case 'bysecond': - case 'byminute': - case 'byhour': - case 'bymonthday': - case 'byyearday': - case 'byweekno': - case 'bymonth': - case 'bysetpos': - $value[$valueType][] = reset( $propPart ); - break; - case 'byday': - $byday = reset( $propPart ); - if( 2 == strlen( $byday )) - $value[$valueType][] = array( 'DAY' => $byday ); - else { - $day = substr( $byday, -2 ); - $key = substr( $byday, 0, ( strlen( $byday ) - 2 )); - $value[$valueType][] = array( $key, 'DAY' => $day ); - } - break; -// case 'rstatus': - case 'code': - $value[0] = reset( $propPart ); - break; - case 'description': - $value[1] = reset( $propPart ); - break; - case 'data': - $value[2] = reset( $propPart ); - break; - case 'text': - $text = str_replace( array( "\r\n", "\n\r", "\r", "\n"), '\n', reset( $propPart )); - $value['text'][] = html_entity_decode( $text ); - break; - case 'time': - break; - case 'uri': - $value = reset( $propPart ); - break; - case 'utc-offset': - $value = str_replace( ':', '', reset( $propPart )); - break; - case 'unknown': - default: - $value = html_entity_decode( reset( $propPart )); - break; - } // end switch( $valueType ) - } // end foreach( $property->children() as $propPart ) - if( 'freebusy' == $propName ) { - $fbtype = $params['FBTYPE']; - unset( $params['FBTYPE'] ); - $iCal->setProperty( $propName, $fbtype, $value, $params ); - } - elseif( 'geo' == $propName ) - $iCal->setProperty( $propName, $value['latitude'], $value['longitude'], $params ); - elseif( 'request-status' == $propName ) { - if( !isset( $value[2] )) - $value[2] = FALSE; - $iCal->setProperty( $propName, $value[0], $value[1], $value[2], $params ); - } - else { - if( isset( $value['text'] ) && is_array( $value['text'] )) { - if(( 'categories' == $propName ) || ( 'resources' == $propName )) - $value = $value['text']; - else - $value = reset( $value['text'] ); - } - $iCal->setProperty( $propName, $value, $params ); - } -} -/*********************************************************************************/ -/* Additional functions to use with vtimezone components */ -/*********************************************************************************/ -/** - * For use with - * iCalcreator (kigkonsult.se/iCalcreator/index.php) - * copyright (c) 2011 Yitzchok Lavi - * icalcreator@onebigsystem.com - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -/** - * Additional functions to use with vtimezone components - * - * Before calling the functions, set time zone 'GMT' ('date_default_timezone_set')! - * - * @author Yitzchok Lavi - * adjusted for iCalcreator Kjell-Inge Gustafsson, kigkonsult - * @version 1.0.2 - 2011-02-24 - * - */ -/** - * Returns array with the offset information from UTC for a (UTC) datetime/timestamp in the - * timezone, according to the VTIMEZONE information in the input array. - * - * $param array $timezonesarray, output from function getTimezonesAsDateArrays (below) - * $param string $tzid, time zone identifier - * $param mixed $timestamp, timestamp or a UTC datetime (in array format) - * @return array, time zone data with keys for 'offsetHis', 'offsetSec' and 'tzname' - * - */ -function getTzOffsetForDate($timezonesarray, $tzid, $timestamp) { - if( is_array( $timestamp )) { -//$disp = sprintf( '%04d%02d%02d %02d%02d%02d', $timestamp['year'], $timestamp['month'], $timestamp['day'], $timestamp['hour'], $timestamp['min'], $timestamp['sec'] ); // test ### - $timestamp = gmmktime( - $timestamp['hour'], - $timestamp['min'], - $timestamp['sec'], - $timestamp['month'], - $timestamp['day'], - $timestamp['year'] - ) ; -// echo ' '."\n".' '.$timestamp.''.$disp.' '."\n".' '; // test ### - } - $tzoffset = array(); - // something to return if all goes wrong (such as if $tzid doesn't find us an array of dates) - $tzoffset['offsetHis'] = '+0000'; - $tzoffset['offsetSec'] = 0; - $tzoffset['tzname'] = '?'; - if( !isset( $timezonesarray[$tzid] )) - return $tzoffset; - $tzdatearray = $timezonesarray[$tzid]; - if ( is_array($tzdatearray) ) { - sort($tzdatearray); // just in case - if ( $timestamp < $tzdatearray[0]['timestamp'] ) { - // our date is before the first change - $tzoffset['offsetHis'] = $tzdatearray[0]['tzbefore']['offsetHis'] ; - $tzoffset['offsetSec'] = $tzdatearray[0]['tzbefore']['offsetSec'] ; - $tzoffset['tzname'] = $tzdatearray[0]['tzbefore']['offsetHis'] ; // we don't know the tzname in this case - } elseif ( $timestamp >= $tzdatearray[count($tzdatearray)-1]['timestamp'] ) { - // our date is after the last change (we do this so our scan can stop at the last record but one) - $tzoffset['offsetHis'] = $tzdatearray[count($tzdatearray)-1]['tzafter']['offsetHis'] ; - $tzoffset['offsetSec'] = $tzdatearray[count($tzdatearray)-1]['tzafter']['offsetSec'] ; - $tzoffset['tzname'] = $tzdatearray[count($tzdatearray)-1]['tzafter']['tzname'] ; - } else { - // our date somewhere in between - // loop through the list of dates and stop at the one where the timestamp is before our date and the next one is after it - // we don't include the last date in our loop as there isn't one after it to check - for ( $i = 0 ; $i <= count($tzdatearray)-2 ; $i++ ) { - if(( $timestamp >= $tzdatearray[$i]['timestamp'] ) && ( $timestamp < $tzdatearray[$i+1]['timestamp'] )) { - $tzoffset['offsetHis'] = $tzdatearray[$i]['tzafter']['offsetHis'] ; - $tzoffset['offsetSec'] = $tzdatearray[$i]['tzafter']['offsetSec'] ; - $tzoffset['tzname'] = $tzdatearray[$i]['tzafter']['tzname'] ; - break; - } - } - } - } - return $tzoffset; -} -/** - * Returns an array containing all the timezone data in the vcalendar object - * - * @param object $vcalendar, iCalcreator calendar instance - * @return array, time zone transition timestamp, array before(offsetHis, offsetSec), array after(offsetHis, offsetSec, tzname) - * based on the timezone data in the vcalendar object - * - */ -function getTimezonesAsDateArrays($vcalendar) { - $timezonedata = array(); - while( $vtz = $vcalendar->getComponent( 'vtimezone' )) { - $tzid = $vtz->getProperty('tzid'); - $alltzdates = array(); - while ( $vtzc = $vtz->getComponent( 'standard' )) { - $newtzdates = expandTimezoneDates($vtzc); - $alltzdates = array_merge($alltzdates, $newtzdates); - } - while ( $vtzc = $vtz->getComponent( 'daylight' )) { - $newtzdates = expandTimezoneDates($vtzc); - $alltzdates = array_merge($alltzdates, $newtzdates); - } - sort($alltzdates); - $timezonedata[$tzid] = $alltzdates; - } - return $timezonedata; -} -/** - * Returns an array containing time zone data from vtimezone standard/daylight instances - * - * @param object $vtzc, an iCalcreator calendar standard/daylight instance - * @return array, time zone data; array before(offsetHis, offsetSec), array after(offsetHis, offsetSec, tzname) - * - */ -function expandTimezoneDates($vtzc) { - $tzdates = array(); - // prepare time zone "description" to attach to each change - $tzbefore = array(); - $tzbefore['offsetHis'] = $vtzc->getProperty('tzoffsetfrom') ; - $tzbefore['offsetSec'] = iCalUtilityFunctions::_tz2offset($tzbefore['offsetHis']); - if(( '-' != substr( (string) $tzbefore['offsetSec'], 0, 1 )) && ( '+' != substr( (string) $tzbefore['offsetSec'], 0, 1 ))) - $tzbefore['offsetSec'] = '+'.$tzbefore['offsetSec']; - $tzafter = array(); - $tzafter['offsetHis'] = $vtzc->getProperty('tzoffsetto') ; - $tzafter['offsetSec'] = iCalUtilityFunctions::_tz2offset($tzafter['offsetHis']); - if(( '-' != substr( (string) $tzafter['offsetSec'], 0, 1 )) && ( '+' != substr( (string) $tzafter['offsetSec'], 0, 1 ))) - $tzafter['offsetSec'] = '+'.$tzafter['offsetSec']; - if( FALSE === ( $tzafter['tzname'] = $vtzc->getProperty('tzname'))) - $tzafter['tzname'] = $tzafter['offsetHis']; - // find out where to start from - $dtstart = $vtzc->getProperty('dtstart'); - $dtstarttimestamp = mktime( - $dtstart['hour'], - $dtstart['min'], - $dtstart['sec'], - $dtstart['month'], - $dtstart['day'], - $dtstart['year'] - ) ; - if( !isset( $dtstart['unparsedtext'] )) // ?? - $dtstart['unparsedtext'] = sprintf( '%04d%02d%02dT%02d%02d%02d', $dtstart['year'], $dtstart['month'], $dtstart['day'], $dtstart['hour'], $dtstart['min'], $dtstart['sec'] ); - if ( $dtstarttimestamp == 0 ) { - // it seems that the dtstart string may not have parsed correctly - // let's set a timestamp starting from 1902, using the time part of the original string - // so that the time will change at the right time of day - // at worst we'll get midnight again - $origdtstartsplit = explode('T',$dtstart['unparsedtext']) ; - $dtstarttimestamp = strtotime("19020101",0); - $dtstarttimestamp = strtotime($origdtstartsplit[1],$dtstarttimestamp); - } - // the date (in dtstart and opt RDATE/RRULE) is ALWAYS LOCAL (not utc!!), adjust from 'utc' to 'local' timestamp - $diff = -1 * $tzbefore['offsetSec']; - $dtstarttimestamp += $diff; - // add this (start) change to the array of changes - $tzdates[] = array( - 'timestamp' => $dtstarttimestamp, - 'tzbefore' => $tzbefore, - 'tzafter' => $tzafter - ); - $datearray = getdate($dtstarttimestamp); - // save original array to use time parts, because strtotime (used below) apparently loses the time - $changetime = $datearray ; - // generate dates according to an RRULE line - $rrule = $vtzc->getProperty('rrule') ; - if ( is_array($rrule) ) { - if ( $rrule['FREQ'] == 'YEARLY' ) { - // calculate transition dates starting from DTSTART - $offsetchangetimestamp = $dtstarttimestamp; - // calculate transition dates until 10 years in the future - $stoptimestamp = strtotime("+10 year",time()); - // if UNTIL is set, calculate until then (however far ahead) - if ( isset( $rrule['UNTIL'] ) && ( $rrule['UNTIL'] != '' )) { - $stoptimestamp = mktime( - $rrule['UNTIL']['hour'], - $rrule['UNTIL']['min'], - $rrule['UNTIL']['sec'], - $rrule['UNTIL']['month'], - $rrule['UNTIL']['day'], - $rrule['UNTIL']['year'] - ) ; - } - $count = 0 ; - $stopcount = isset( $rrule['COUNT'] ) ? $rrule['COUNT'] : 0 ; - $daynames = array( - 'SU' => 'Sunday', - 'MO' => 'Monday', - 'TU' => 'Tuesday', - 'WE' => 'Wednesday', - 'TH' => 'Thursday', - 'FR' => 'Friday', - 'SA' => 'Saturday' - ); - // repeat so long as we're between DTSTART and UNTIL, or we haven't prepared COUNT dates - while ( $offsetchangetimestamp < $stoptimestamp && ( $stopcount == 0 || $count < $stopcount ) ) { - // break up the timestamp into its parts - $datearray = getdate($offsetchangetimestamp); - if ( isset( $rrule['BYMONTH'] ) && ( $rrule['BYMONTH'] != 0 )) { - // set the month - $datearray['mon'] = $rrule['BYMONTH'] ; - } - if ( isset( $rrule['BYMONTHDAY'] ) && ( $rrule['BYMONTHDAY'] != 0 )) { - // set specific day of month - $datearray['mday'] = $rrule['BYMONTHDAY']; - } elseif ( is_array($rrule['BYDAY']) ) { - // find the Xth WKDAY in the month - // the starting point for this process is the first of the month set above - $datearray['mday'] = 1 ; - // turn $datearray as it is now back into a timestamp - $offsetchangetimestamp = mktime( - $datearray['hours'], - $datearray['minutes'], - $datearray['seconds'], - $datearray['mon'], - $datearray['mday'], - $datearray['year'] - ); - if ($rrule['BYDAY'][0] > 0) { - // to find Xth WKDAY in month, we find last WKDAY in month before - // we do that by finding first WKDAY in this month and going back one week - // then we add X weeks (below) - $offsetchangetimestamp = strtotime($daynames[$rrule['BYDAY']['DAY']],$offsetchangetimestamp); - $offsetchangetimestamp = strtotime("-1 week",$offsetchangetimestamp); - } else { - // to find Xth WKDAY before the end of the month, we find the first WKDAY in the following month - // we do that by going forward one month and going to WKDAY there - // then we subtract X weeks (below) - $offsetchangetimestamp = strtotime("+1 month",$offsetchangetimestamp); - $offsetchangetimestamp = strtotime($daynames[$rrule['BYDAY']['DAY']],$offsetchangetimestamp); - } - // now move forward or back the appropriate number of weeks, into the month we want - $offsetchangetimestamp = strtotime($rrule['BYDAY'][0] . " week",$offsetchangetimestamp); - $datearray = getdate($offsetchangetimestamp); - } - // convert the date parts back into a timestamp, setting the time parts according to the - // original time data which we stored - $offsetchangetimestamp = mktime( - $changetime['hours'], - $changetime['minutes'], - $changetime['seconds'] + $diff, - $datearray['mon'], - $datearray['mday'], - $datearray['year'] - ); - // add this change to the array of changes - $tzdates[] = array( - 'timestamp' => $offsetchangetimestamp, - 'tzbefore' => $tzbefore, - 'tzafter' => $tzafter - ); - // update counters (timestamp and count) - $offsetchangetimestamp = strtotime("+" . (( isset( $rrule['INTERVAL'] ) && ( $rrule['INTERVAL'] != 0 )) ? $rrule['INTERVAL'] : 1 ) . " year",$offsetchangetimestamp); - $count += 1 ; - } - } - } - // generate dates according to RDATE lines - while ($rdates = $vtzc->getProperty('rdate')) { - if ( is_array($rdates) ) { - - foreach ( $rdates as $rdate ) { - // convert the explicit change date to a timestamp - $offsetchangetimestamp = mktime( - $rdate['hour'], - $rdate['min'], - $rdate['sec'] + $diff, - $rdate['month'], - $rdate['day'], - $rdate['year'] - ) ; - // add this change to the array of changes - $tzdates[] = array( - 'timestamp' => $offsetchangetimestamp, - 'tzbefore' => $tzbefore, - 'tzafter' => $tzafter - ); - } - } - } - return $tzdates; -} -?> diff --git a/php/ical/class.icalparser.php b/php/ical/class.icalparser.php deleted file mode 100644 index a035847..0000000 --- a/php/ical/class.icalparser.php +++ /dev/null @@ -1,552 +0,0 @@ - - * Copyright (C) 2012-2014 Christoph Haas - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -/** - * This is the iCal-class - * Parse ics file content to array. - * - * @param {string} filename The name of the file which should be parsed - * @constructor - */ -class ICal { - /* How many ToDos are in this ical? */ - public /** @type {int} */ $todo_count = 0; - - /* How many events are in this ical? */ - public /** @type {int} */ $event_count = 0; - - /* Currently editing an alarm? */ - private /** @type {boolean} */ $isalarm = false; - - /* The parsed calendar */ - public /** @type {Array} */ $cal; - - /* Error message store... null default */ - public /** @type {String} */ $errors; - - /* Which keyword has been added to cal at last? */ - private /** @type {string} */ $_lastKeyWord; - - /* The default timezone, used to convert UTC Time */ - private /** @type {string} */ $default_timezone = "Europe/Vienna"; - - /* The default timezone, used to convert UTC Time */ - private /** @type {boolean} */ $timezone_set = false; - - /* Ignore Daylight Saving Time */ - private /** @type {boolean} */ $ignore_dst = false; - - /** - * Creates the iCal-Object - * - * @param {string} $filename The path to the iCal-file - * - * @return Object The iCal-Object - */ - public function __construct($filename, $default_timezone, $timezone = false, $igndst = false) { - if (!$filename) { - $this->errors = "No filename specified"; - return false; - } - - $this->default_timezone = $default_timezone; - - if(isset($timezone) && $timezone != false) { - $this->default_timezone = $timezone; - $this->timezone_set = true; - } - - if(isset($igndst) && $igndst != false) { - $this->ignore_dst = true; - } - - $lines = file($filename, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); - if (stristr($lines[0], 'BEGIN:VCALENDAR') === false) { - $this->errors = "Not a valid ical file"; - return false; - } else { - - foreach ($lines as $line) { - $line = trim($line); - $add = $this->keyValueFromString($line); - if ($add === false) { - $this->addCalendarComponentWithKeyAndValue($type, false, $line); - continue; - } - - list($keyword, $dummy, $prop, $propvalue, $value) = $add; - - switch ($line) { - // http://www.kanzaki.com/docs/ical/vtodo.html - case "BEGIN:VTODO": - $this->todo_count++; - $type = "VTODO"; - break; - - case "BEGIN:VALARM": - //echo "vevent gematcht"; - $this->isalarm=true; - $type = "VEVENT"; - break; - // http://www.kanzaki.com/docs/ical/vevent.html - case "BEGIN:VEVENT": - //echo "vevent gematcht"; - $this->event_count++; - $type = "VEVENT"; - break; - - //all other special strings - case "BEGIN:VCALENDAR": - case "BEGIN:DAYLIGHT": - // http://www.kanzaki.com/docs/ical/vtimezone.html - case "BEGIN:VTIMEZONE": - case "BEGIN:STANDARD": - $type = $value; - break; - case "END:VTODO": // end special text - goto VCALENDAR key - case "END:VEVENT": - case "END:VCALENDAR": - case "END:DAYLIGHT": - case "END:VTIMEZONE": - case "END:STANDARD": - $type = "VCALENDAR"; - break; - case "END:VALARM": - $this->isalarm=false; - $type = "VEVENT"; - break; - default: - $this->addCalendarComponentWithKeyAndValue($type, $keyword, $value, $prop, $propvalue); - break; - } - } - return $this->cal; - } - } - - /** - * Add to $this->ical array one value and key. - * - * @param {string} $component This could be VTODO, VEVENT, VCALENDAR, ... - * @param {string} $keyword The keyword, for example DTSTART - * @param {string} $value The value, for example 20110105T090000Z - * - * @return {None} - */ - public function addCalendarComponentWithKeyAndValue($component, $keyword, $value, $prop = false, $propvalue = false) { - if ($keyword == false) { // multiline value - $keyword = $this->last_keyword; - - switch ($component) { - case 'VEVENT': - if (stristr($keyword, "DTSTART") or stristr($keyword, "DTEND") or stristr($keyword, "TRIGGER")) { - $ts = $this->iCalDateToUnixTimestamp($value, $prop, $propvalue); - $value = $ts * 1000; - } - $value = str_replace("\\n", "\n", $value); - - $value = $this->customFilters($keyword, $value); - - if(!$this->isalarm) { - $value = $this->cal[$component][$this->event_count - 1][$keyword].$value; - } else { - $value = $this->cal[$component][$this->event_count - 1]["VALARM"][$keyword].$value; - } - break; - case 'VTODO' : - $value = $this->cal[$component][$this->todo_count - 1] - [$keyword].$value; - break; - } - } - - /* This should not be neccesary anymore*/ - //always strip additional content.... - //if (stristr($keyword, "DTSTART") or stristr($keyword, "DTEND")) { - //$keyword = explode(";", $keyword); - //$keyword = $keyword[0]; // remove additional content like VALUE=DATE - //} - - if ((stristr($keyword, "TIMEZONE") || stristr($keyword, "TZID")) && !$this->timezone_set) { // check if timezone already set... - $this->default_timezone = $this->trimTimeZone($value); // store the calendertimezone - } - - switch ($component) { - case "VTODO": - $this->cal[$component][$this->todo_count - 1][$keyword] = $value; - //$this->cal[$component][$this->todo_count]['Unix'] = $unixtime; - break; - case "VEVENT": - if (stristr($keyword, "DTSTART") or stristr($keyword, "DTEND") or stristr($keyword, "TRIGGER")) { - $ts = $this->iCalDateToUnixTimestamp($value, $prop, $propvalue); - $value = $ts * 1000; - } - $value = str_replace("\\n", "\n", $value); - - $value = $this->customFilters($keyword, $value); - - if(!$this->isalarm) { - $this->cal[$component][$this->event_count - 1][$keyword] = $value; - } else { - $this->cal[$component][$this->event_count - 1]["VALARM"][$keyword] = $value; - } - break; - default: - $this->cal[$component][$keyword] = $value; - break; - } - $this->last_keyword = $keyword; - } - - /** - * Filter some chars out of the value. - * - * @param {string} $keyword keyword to which the filter is applied - * @param {string} $value to filter - * @return {string} filtered value - */ - private function customFilters($keyword, $value) { - if (stristr($keyword, "SUMMARY")) { - $value = str_replace("\n", " ", $value); // we don't need linebreaks in the summary... - } - - if (stristr($keyword, "SUMMARY")) { - $value = str_replace("\,", ",", $value); // strange escaped comma - } - - return $value; - } - - /** - * Trim a Timezone String - * - * @param {string} $timezone timezone string which should be trimmed - * @return {string} trimmed value - */ - private function trimTimeZone($timezone) { - if(preg_match('~([?<=/]*)([^/]*[/|-][^/]*$)~', $timezone, $matches)) { // detects tzurls in tzids - if ($matches[2] != "") { - return $matches[2]; // 2 = extracted timezone - } else { - return $timezone; - } - } - - return $timezone; - } - - /** - * Get a key-value pair of a string. - * - * @param {string} $text which is like "VCALENDAR:Begin" or "LOCATION:" - * - * @return {array} array("Argument", "Optional Arg/Val", "Optional Arg", "Optional Value", "Value") - */ - public function keyValueFromString($text) { - - preg_match('/(^[^a-z:;]+)([;]+([a-zA-Z]*)[=]*([^:"]*|"[\w\W]*"))?[:]([\w\W]*)/', $text, $matches); - - // this regex has problems with multiple attributes... ATTENDEE;RSVP=TRUE;ROLE=REQ-PARTICIPANT:mailto:jsmith@example.com - // TODO: fix this - - if (count($matches) == 0) { - return false; - } - - $matches = array_splice($matches, 1, 5); // 0 = Arg, 1 = Complete Optional Arg/Val, 2 = Optional Arg, 3 = Optional Val, 4 = Value - return $matches; - } - - /** - * Return UTC Unix timestamp from ical date time format - * - * @param {string} $icalDate A Date in the format YYYYMMDD[T]HHMMSS[Z] or - * YYYYMMDD[T]HHMMSS - * - * @return {int} - */ - private function iCalDateToUTCUnixTimestamp($icalDate, $prop, $propvalue) { - - $timezone = false; - $allday = false; - - if($prop) { - $pos = strpos("TZIDtzid", $prop); - if($pos !== false && $propvalue != false) { - $timezone = str_replace('"', '', $propvalue); - $timezone = str_replace('\'', '', $timezone); - $timezone = $this->trimTimeZone($timezone); - } - } - - /* timestring format */ - $utc = strpos("zZ",substr($icalDate, -1)) === false ? false : true; - - $icalDate = str_replace('T', '', $icalDate); - $icalDate = str_replace('Z', '', $icalDate); - - $pattern = '/([0-9]{4})'; // 1: YYYY - $pattern .= '([0-9]{2})'; // 2: MM - $pattern .= '([0-9]{2})'; // 3: DD - $pattern .= '([0-9]{0,2})'; // 4: HH - $pattern .= '([0-9]{0,2})'; // 5: MM - $pattern .= '([0-9]{0,2})/'; // 6: SS - preg_match($pattern, $icalDate, $date); - - // Unix timestamp can't represent dates before 1970 - if ($date[1] <= 1970) { - return false; - } - - // check if we have a allday event - if((!$date[6] || $date[6] === "") || (!$date[5] || $date[5] === "") || (!$date[4] || $date[4] === "")) { - $date[6] = 0; - $date[5] = 0; - $date[4] = 0; - $allday = true; - - $dtz = date_default_timezone_get(); - date_default_timezone_set('UTC'); - } - - // Unix timestamps after 03:14:07 UTC 2038-01-19 might cause an overflow - // if 32 bit integers are used. - $timestamp = mktime((int)$date[4], - (int)$date[5], - (int)$date[6], - (int)$date[2], - (int)$date[3], - (int)$date[1]); - - if($allday) { - date_default_timezone_set($dtz); - } - - if(!$utc && !$allday) { - $tz = $this->default_timezone; - if($timezone != false) { - $tz = $timezone; - } - - $error = false; - $this_tz = false; - - try { - $this_tz = new DateTimeZone($tz); - } catch(Exception $e) { - error_log($e->getMessage()); - $error = true; - } - - if($error) { - try { // Try using the default calendar timezone - $this_tz = new DateTimeZone($this->default_timezone); - } catch(Exception $e) { - error_log($e->getMessage()); - $timestamp_utc = $timestamp; // if that fails, we cannot do anymore - } - } - - if($this_tz != false) { - $tz_now = new DateTime("now", $this_tz); - $tz_offset = $this_tz->getOffset($tz_now); - $timestamp_utc = $timestamp - $tz_offset; - } - } else { - $timestamp_utc = $timestamp; - } - - return array($timestamp_utc,$allday); - } - - /** - * Return a timezone specific timestamp - * @param {int} $timestamp_utc UTC Timestamp to convert - * @param {string} $timezone Timezone - * @return {int} - */ - private function UTCTimestampToTZTimestamp($timestamp_utc, $timezone, $ignore_dst = false) { - $this_tz = false; - try { // Try using the default calendar timezone - $this_tz = new DateTimeZone($this->default_timezone); - } catch(Exception $e) { - error_log($e->getMessage()); - $timestamp_utc = $timestamp; // if that fails, we cannot do anymore - } - if($this_tz != false) { - $transition = $this_tz->getTransitions($timestamp_utc,$timestamp_utc); - $trans_offset = $transition[0]['offset']; - $isdst = $transition[0]['isdst']; - - $tz_now = new DateTime("now", $this_tz); - $tz_offset = $this_tz->getOffset($tz_now); - - if(!$ignore_dst) { - $tz_offset = $trans_offset; // normaly use dst - } - - return $timestamp_utc + $tz_offset; - } - return $timestamp_utc; // maybe timezone conversion will fail... - } - - /** - * Return Timezone specific Unix timestamp from ical date time format - * - * @param {string} $icalDate A Date in the format YYYYMMDD[T]HHMMSS[Z] or - * YYYYMMDD[T]HHMMSS - * - * @return {int} - */ - public function iCalDateToUnixTimestamp($icalDate, $prop, $propvalue) { - list($timestamp, $allday) = $this->iCalDateToUTCUnixTimestamp($icalDate, $prop, $propvalue); - - if(!$allday) { - $timestamp = $this->UTCTimestampToTZTimestamp($timestamp, $this->default_timezone, $this->ignore_dst, $allday); - } - - return $timestamp; - } - - /** - * Returns an array of arrays with all events. Every event is an associative - * array and each property is an element it. - * - * @return {array} - */ - public function events() { - $array = $this->cal; - return $array['VEVENT']; - } - - /** - * Returns an array of calendar types. - * - * @return {array} - */ - public function calendar() { - $array = $this->cal; - return $array['VCALENDAR']; - } - - /** - * Returns the default or set timezone - * - * @return {string} - */ - public function timezone() { - return $this->default_timezone; - } - - /** - * Returns a boolean value whether thr current calendar has events or not - * - * @return {boolean} - */ - public function hasEvents() { - return ( count($this->events()) > 0 ? true : false ); - } - - /** - * Returns false when the current calendar has no events in range, else the - * events. - * - * Note that this function makes use of a UNIX timestamp. This might be a - * problem on January the 29th, 2038. - * See http://en.wikipedia.org/wiki/Unix_time#Representing_the_number - * - * @param {boolean} $rangeStart Either true or false - * @param {boolean} $rangeEnd Either true or false - * - * @return {mixed} - */ - public function eventsFromRange($rangeStart = false, $rangeEnd = false) { - $events = $this->sortEventsWithOrder($this->events(), SORT_ASC); - - if (!$events) { - return false; - } - - $extendedEvents = array(); - - if ($rangeStart !== false) { - $rangeStart = new DateTime(); - } - - if ($rangeEnd !== false or $rangeEnd <= 0) { - $rangeEnd = new DateTime('2038/01/18'); - } else { - $rangeEnd = new DateTime($rangeEnd); - } - - $rangeStart = $rangeStart->format('U'); - $rangeEnd = $rangeEnd->format('U'); - - - - // loop through all events by adding two new elements - foreach ($events as $anEvent) { - $timestamp = $this->iCalDateToUnixTimestamp($anEvent['DTSTART']); - if ($timestamp >= $rangeStart && $timestamp <= $rangeEnd) { - $extendedEvents[] = $anEvent; - } - } - - return $extendedEvents; - } - - /** - * Returns sorted events - * - * @param {array} $events An array with events. - * @param {array} $sortOrder Either SORT_ASC, SORT_DESC, SORT_REGULAR, - * SORT_NUMERIC, SORT_STRING - * - * @return {array} - */ - public function sortEventsWithOrder($events, $sortOrder = SORT_ASC) { - $extendedEvents = array(); - - // loop through all events by adding two new elements - foreach ($events as $anEvent) { - if (!array_key_exists('UNIX_TIMESTAMP', $anEvent)) { - $anEvent['UNIX_TIMESTAMP'] = $this->iCalDateToUnixTimestamp($anEvent['DTSTART']); - } - - if (!array_key_exists('REAL_DATETIME', $anEvent)) { - $anEvent['REAL_DATETIME'] = date("d.m.Y", $anEvent['UNIX_TIMESTAMP']); - } - - $extendedEvents[] = $anEvent; - } - - foreach ($extendedEvents as $key => $value) { - $timestamp[$key] = $value['UNIX_TIMESTAMP']; - } - array_multisort($timestamp, $sortOrder, $extendedEvents); - - return $extendedEvents; - } -} -?> diff --git a/php/module.calendar.php b/php/module.calendar.php index 84b753e..ea1f07f 100644 --- a/php/module.calendar.php +++ b/php/module.calendar.php @@ -1,4 +1,4 @@ -busystates = array( + "FREE", + "TENTATIVE", + "BUSY", + "OOF" + ); + + $this->labels = array( + "NONE", + "IMPORTANT", + "WORK", + "PERSONAL", + "HOLIDAY", + "REQUIRED", + "TRAVEL REQUIRED", + "PREPARATION REQUIERED", + "BIRTHDAY", + "SPECIAL DATE", + "PHONE INTERVIEW" + ); + + $this->attendeetype = array( + "NON-PARTICIPANT", // needed as zarafa starts counting at 1 + "REQ-PARTICIPANT", + "OPT-PARTICIPANT", + "NON-PARTICIPANT" + ); } /** @@ -43,28 +83,32 @@ class CalendarModule extends Module { * Exception part is used for authentication errors also * @return boolean true on success or false on failure. */ - public function execute() { + public function execute() + { $result = false; - - if(!$this->DEBUG) { + + if (!$this->DEBUG) { /* disable error printing - otherwise json communication might break... */ ini_set('display_errors', '0'); } - - foreach($this->data as $actionType => $actionData) { - if(isset($actionType)) { + + foreach ($this->data as $actionType => $actionData) { + if (isset($actionType)) { try { - if($this->DEBUG) { + if ($this->DEBUG) { error_log("exec: " . $actionType); } - switch($actionType) { + switch ($actionType) { + case "load": + $result = $this->loadCalendar($actionType, $actionData); + break; case "export": $result = $this->exportCalendar($actionType, $actionData); break; case "import": $result = $this->importCalendar($actionType, $actionData); break; - case "attachmentpath": + case "importattachment": $result = $this->getAttachmentPath($actionType, $actionData); break; default: @@ -72,30 +116,31 @@ class CalendarModule extends Module { } } catch (MAPIException $e) { - if($this->DEBUG) { + if ($this->DEBUG) { error_log("mapi exception: " . $e->getMessage()); } } catch (Exception $e) { - if($this->DEBUG) { + if ($this->DEBUG) { error_log("exception: " . $e->getMessage()); } } } } - + return $result; } - + /** * Generates a random string with variable length. * @param $length the lenght of the generated string * @return string a random string */ - private function randomstring($length = 6) { + private function randomstring($length = 6) + { // $chars - all allowed charakters $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"; - srand((double)microtime()*1000000); + srand((double)microtime() * 1000000); $i = 0; $pass = ""; while ($i < $length) { @@ -106,347 +151,331 @@ class CalendarModule extends Module { } return $pass; } - + /** - * Generates the secid file (used to verify the download path) - * @param $secid the secid, a random security token + * Get a property from the array. + * @param $props + * @param $propname + * @return string */ - private function createSecIDFile($secid) { - $lockFile = TMP_PATH . "/secid." . $secid; - $fh = fopen($lockFile, 'w') or die("can't open secid file"); - $stringData = date(DATE_RFC822); - fwrite($fh, $stringData); - fclose($fh); - } - - /** - * Generates the secid file (used to verify the download path) - * @param $time a timestamp - * @param $incl_time true if date should include time - * @ return date object - */ - private function getIcalDate($time, $incl_time = true) { - return $incl_time ? date('Ymd\THis', $time) : date('Ymd', $time); - } - - /** - * adds an event to the exported calendar) - * @param $vevent pointer to the eventstore - * @param $event the event to add - */ - private function addEvent(&$vevent, $event) { - - $busystate = array("FREE", "TENTATIVE", "BUSY", "OOF"); - $zlabel = array("NONE", "IMPORTANT", "WORK", "PERSONAL", "HOLIDAY", "REQUIRED", "TRAVEL REQUIRED", "PREPARATION REQUIERED", "BIRTHDAY", "SPECIAL DATE", "PHONE INTERVIEW"); - - $vevent->setProperty("LOCATION", $event["location"]); // property name - case independent - $vevent->setProperty("SUMMARY", $event["subject"]); - $vevent->setProperty("DESCRIPTION", str_replace("\n", "\\n",$event["description"])); - $vevent->setProperty("COMMENT", "Exported from Zarafa" ); - $vevent->setProperty("ORGANIZER", $event["sent_representing_email_address"]); - $vevent->setProperty("DTSTART", $this->getIcalDate($event["commonstart"]) . "Z"); - $vevent->setProperty("DTEND", $this->getIcalDate($event["commonend"]) . "Z"); - $vevent->setProperty("DTSTAMP", $this->getIcalDate($event["creation_time"]) . "Z"); - $vevent->setProperty("CREATED", $this->getIcalDate($event["creation_time"]) . "Z"); - $vevent->setProperty("LAST-MODIFIED", $this->getIcalDate($event["last_modification_time"]) . "Z"); - $vevent->setProperty("X-MICROSOFT-CDO-BUSYSTATUS", $busystate[$event["busystatus"]]); - $vevent->setProperty("X-ZARAFA-LABEL", $zlabel[$event["label"]]); - $vevent->setProperty("PRIORITY", $event["importance"]); - $vevent->setProperty("CLASS", $event["private"] ? "PRIVATE" : "PUBLIC"); - - // ATTENDEES - if(count($event["attendees"]) > 0) { - foreach($event["attendees"] as $attendee) { - $vevent->setProperty("ATTENDEE", $attendee["props"]["smtp_address"]); - } - } - - // REMINDERS - if($event["reminder"]) { - $valarm = & $vevent->newComponent("valarm"); // create an event alarm - $valarm->setProperty("action", "DISPLAY" ); - $valarm->setProperty("description", $vevent->getProperty("SUMMARY")); // reuse the event summary - $valarm->setProperty("trigger", $this->getIcalDate($event["reminder_time"]) . "Z"); // create alarm trigger (in UTC datetime) + private function getProp($props, $propname) + { + if (isset($props["props"][$propname])) { + return $props["props"][$propname]; } + return ""; } - - /** - * Loads the descriptiontext of an event - * @param $event - * @return array with event description/body - */ - private function loadEventDescription($event) { - $entryid = $this->getActionEntryID($event); - $store = $this->getActionStore($event); - - $basedate = null; - - $properties = $GLOBALS['properties']->getAppointmentProperties(); - $plaintext = true; - - $data = array(); - - if($store && $entryid) { - $message = $GLOBALS['operations']->openMessage($store, $entryid); - - - // add all standard properties from the series/normal message - $data['item'] = $GLOBALS['operations']->getMessageProps($store, $message, $properties, (isset($plaintext) && $plaintext)); - - // if appointment is recurring then only we should get properties of occurence if basedate is supplied - if($data['item']['props']['recurring'] === true) { - if(isset($basedate) && $basedate) { - $recur = new Recurrence($store, $message); - $exceptionatt = $recur->getExceptionAttachment($basedate); + private function getDurationStringFromMintues($minutes, $pos = false) { + $pos = $pos === true ? "+" : "-"; + $str = $pos . "P"; - // Single occurences are never recurring - $data['item']['props']['recurring'] = false; - if($exceptionatt) { - // Existing exception (open existing item, which includes basedate) - $exceptionattProps = mapi_getprops($exceptionatt, array(PR_ATTACH_NUM)); - $exception = mapi_attach_openobj($exceptionatt, 0); - // overwrite properties with the ones from the exception - $exceptionProps = $GLOBALS['operations']->getMessageProps($store, $exception, $properties, (isset($plaintext) && $plaintext)); + // variables for holding values + $mins = intval($minutes); + $hours = 0; + $days = 0; + $weeks = 0; - /** - * If recurring item has set reminder to true then - * all occurrences before the 'flagdueby' value(of recurring item) - * should not show that reminder is set. - */ - if (isset($exceptionProps['props']['reminder']) && $data['item']['props']['reminder'] == true) { - $flagDueByDay = $recur->dayStartOf($data['item']['props']['flagdueby']); - - if ($flagDueByDay > $basedate) { - $exceptionProps['props']['reminder'] = false; - } - } - - // The properties must be merged, if the recipients or attachments are present in the exception - // then that list should be used. Otherwise the list from the series must be applied (this - // corresponds with OL2007). - // @FIXME getMessageProps should not return empty string if exception doesn't contain body - // by this change we can handle a situation where user has set empty string in the body explicitly - if (!empty($exceptionProps['props']['body']) || !empty($exceptionProps['props']['html_body'])) { - if(!empty($exceptionProps['props']['body'])) { - $data['item']['props']['body'] = $exceptionProps['props']['body']; - } - - if(!empty($exceptionProps['props']['html_body'])) { - $data['item']['props']['html_body'] = $exceptionProps['props']['html_body']; - } - - $data['item']['props']['isHTML'] = $exceptionProps['props']['isHTML']; - } - // remove properties from $exceptionProps so array_merge will not overwrite it - unset($exceptionProps['props']['html_body']); - unset($exceptionProps['props']['body']); - unset($exceptionProps['props']['isHTML']); - - $data['item']['props'] = array_merge($data['item']['props'], $exceptionProps['props']); - if (isset($exceptionProps['recipients'])) { - $data['item']['recipients'] = $exceptionProps['recipients']; - } - - if (isset($exceptionProps['attachments'])) { - $data['item']['attachments'] = $exceptionProps['attachments']; - } - - // Make sure we are using the passed basedate and not something wrong in the opened item - $data['item']['props']['basedate'] = $basedate; - } else { - // opening an occurence of a recurring series (same as normal open, but add basedate, startdate and enddate) - $data['item']['props']['basedate'] = $basedate; - $data['item']['props']['startdate'] = $recur->getOccurrenceStart($basedate); - $data['item']['props']['duedate'] = $recur->getOccurrenceEnd($basedate); - $data['item']['props']['commonstart'] = $data['item']['props']['startdate']; - $data['item']['props']['commonend'] = $data['item']['props']['duedate']; - unset($data['item']['props']['reminder_time']); - - /** - * If recurring item has set reminder to true then - * all occurrences before the 'flagdueby' value(of recurring item) - * should not show that reminder is set. - */ - if (isset($exceptionProps['props']['reminder']) && $data['item']['props']['reminder'] == true) { - $flagDueByDay = $recur->dayStartOf($data['item']['props']['flagdueby']); - - if ($flagDueByDay > $basedate) { - $exceptionProps['props']['reminder'] = false; - } - } - } - } else { - // Opening a recurring series, get the recurrence information - $recur = new Recurrence($store, $message); - $recurpattern = $recur->getRecurrence(); - $tz = $recur->tz; // no function to do this at the moment - - // Add the recurrence pattern to the data - if(isset($recurpattern) && is_array($recurpattern)) { - $data['item']['props'] += $recurpattern; - } - - // Add the timezone information to the data - if(isset($tz) && is_array($tz)) { - $data['item']['props'] += $tz; - } - } - } + // calculations + if ( $mins >= 60 ) { + $hours = (int)($mins / 60); + $mins = $mins % 60; + } + if ( $hours >= 24 ) { + $days = (int)($hours / 24); + $hours = $hours % 60; + } + if ( $days >= 7 ) { + $weeks = (int)($days / 7); + $days = $days % 7; } - return $data['item']['props']['body']; - } - - /** - * Loads the attendees of an event - * @param $event - * @return array with event attendees - */ - private function loadAttendees($event) { - $entryid = $this->getActionEntryID($event); - $store = $this->getActionStore($event); - - $basedate = null; - - $properties = $GLOBALS['properties']->getAppointmentProperties(); - $plaintext = true; - - $data = array(); - - if($store && $entryid) { - $message = $GLOBALS['operations']->openMessage($store, $entryid); - - - // add all standard properties from the series/normal message - $data['item'] = $GLOBALS['operations']->getMessageProps($store, $message, $properties, (isset($plaintext) && $plaintext)); - + // format result + if ( $weeks ) { + $str .= "{$weeks}W"; + } + if ( $days ) { + $str .= "{$days}D"; + } + if ( $hours ) { + $str .= "{$hours}H"; + } + if ( $mins ) { + $str .= "{$mins}M"; } - return $data['item']['recipients']['item']; + return $str; } - + /** * The main export function, creates the ics file for download * @param $actionType * @param $actionData */ - private function exportCalendar($actionType, $actionData) { - $secid = $this->randomstring(); - $this->createSecIDFile($secid); - $tmpname = stripslashes($actionData["calendar"] . ".ics." . $this->randomstring(8)); - $filename = TMP_PATH . "/" . $tmpname . "." . $secid; - - if(!is_writable(TMP_PATH . "/")) { - error_log("could not write to export tmp directory!"); + private function exportCalendar($actionType, $actionData) + { + // Get store id + $storeid = false; + if (isset($actionData["storeid"])) { + $storeid = $actionData["storeid"]; } - - $tz = date("e"); // use php timezone (maybe set up in php.ini, date.timezone) - - if($this->DEBUG) { - error_log("PHP Timezone: " . $tz); - } - - $config = array( - "language" => substr($GLOBALS["settings"]->get("zarafa/v1/main/language"),0,2), - "directory" => TMP_PATH . "/", - "filename" => $tmpname . "." . $secid, - "unique_id" => "zarafa-export-plugin", - "TZID" => $tz - ); - - $v = new vcalendar($config); - $v->setProperty("method", "PUBLISH"); // required of some calendar software - $v->setProperty("x-wr-calname", $actionData["calendar"]); // required of some calendar software - $v->setProperty("X-WR-CALDESC", "Exported Zarafa Calendar"); // required of some calendar software - $v->setProperty("X-WR-TIMEZONE", $tz); - $xprops = array("X-LIC-LOCATION" => $tz); // required of some calendar software - iCalUtilityFunctions::createTimezone($v, $tz, $xprops); // create timezone object in calendar - - - foreach($actionData["data"] as $event) { - $event["props"]["description"] = $this->loadEventDescription($event); - $event["props"]["attendees"] = $this->loadAttendees($event); - - $vevent = & $v->newComponent("vevent"); // create a new event object - $this->addEvent($vevent, $event["props"]); + // Get records + $records = array(); + if (isset($actionData["records"])) { + $records = $actionData["records"]; } - - $v->saveCalendar(); - - $response['status'] = true; - $response['fileid'] = $tmpname; // number of entries that will be exported - $response['basedir'] = TMP_PATH; - $response['secid'] = $secid; - $response['realname'] = $actionData["calendar"]; + + // Get folders + $folder = false; + if (isset($actionData["folder"])) { + $folder = $actionData["folder"]; + } + + $response = array(); + $error = false; + $error_msg = ""; + + // write csv + $token = $this->randomstring(16); + $file = PLUGIN_CALENDARIMPORTER_TMP_UPLOAD . "ics_" . $token . ".ics"; + file_put_contents($file, ""); + + $store = $GLOBALS["mapisession"]->openMessageStore(hex2bin($storeid)); + if ($store) { + // load folder first + if ($folder !== false) { + $mapifolder = mapi_msgstore_openentry($store, hex2bin($folder)); + + $table = mapi_folder_getcontentstable($mapifolder); + $list = mapi_table_queryallrows($table, array(PR_ENTRYID)); + + foreach ($list as $item) { + $records[] = bin2hex($item[PR_ENTRYID]); + } + } + + $vcalendar = new VObject\Component\VCalendar(); + + // Add static stuff to vcalendar + $vcalendar->add('METHOD', 'PUBLISH'); + $vcalendar->add('X-WR-CALDESC', 'Exported Zarafa Calendar'); + $vcalendar->add('X-WR-TIMEZONE', date_default_timezone_get()); + + // TODO: add VTIMEZONE object to ical. + + for ($index = 0, $count = count($records); $index < $count; $index++) { + $message = mapi_msgstore_openentry($store, hex2bin($records[$index])); + + // get message properties. + $properties = $GLOBALS['properties']->getAppointmentProperties(); + $plaintext = true; + $messageProps = $GLOBALS['operations']->getMessageProps($store, $message, $properties, $plaintext); + + $vevent = $vcalendar->add('VEVENT', [ + 'SUMMARY' => $this->getProp($messageProps, "subject"), + 'DTSTART' => date_timestamp_set(new DateTime(), $this->getProp($messageProps, "startdate")), + 'DTEND' => date_timestamp_set(new DateTime(), $this->getProp($messageProps, "duedate")), + 'CREATED' => date_timestamp_set(new DateTime(), $this->getProp($messageProps, "creation_time")), + 'LAST-MODIFIED' => date_timestamp_set(new DateTime(), $this->getProp($messageProps, "last_modification_time")), + 'PRIORITY' => $this->getProp($messageProps, "importance"), + 'X-MICROSOFT-CDO-INTENDEDSTATUS' => $this->busystates[intval($this->getProp($messageProps, "busystatus"))], // both seem to be valid... + 'X-MICROSOFT-CDO-BUSYSTATUS' => $this->busystates[intval($this->getProp($messageProps, "busystatus"))], // both seem to be valid... + 'X-ZARAFA-LABEL' => $this->labels[intval($this->getProp($messageProps, "label"))], + 'CLASS' => $this->getProp($messageProps, "private") ? "PRIVATE" : "PUBLIC", + 'COMMENT' => "eid:" . $records[$index] + ]); + + // Add organizer + $vevent->add('ORGANIZER','mailto:' . $this->getProp($messageProps, "sender_email_address")); + $vevent->ORGANIZER['CN'] = $this->getProp($messageProps, "sender_name"); + + // Add Attendees + if(isset($messageProps["recipients"]) && count($messageProps["recipients"]["item"]) > 0) { + foreach($messageProps["recipients"]["item"] as $attendee) { + $att = $vevent->add('ATTENDEE', "mailto:" . $this->getProp($attendee, "email_address")); + $att["CN"] = $this->getProp($attendee, "display_name"); + $att["ROLE"] = $this->attendeetype[intval($this->getProp($attendee, "recipient_type"))]; + } + } + + // Add alarms + if(!empty($this->getProp($messageProps, "reminder")) && $this->getProp($messageProps, "reminder") == 1) { + $valarm = $vevent->add('VALARM', [ + 'ACTION' => 'DISPLAY', + 'DESCRIPTION' => $this->getProp($messageProps, "subject") // reuse the event summary + ]); + + // Add trigger + $durationValue = $this->getDurationStringFromMintues($this->getProp($messageProps, "reminder_minutes"), false); + $valarm->add('TRIGGER', $durationValue); // default trigger type is duration (see 4.8.6.3) + + /* + $valarm->add('TRIGGER', date_timestamp_set(new DateTime(), $this->getProp($messageProps, "reminder_time"))); // trigger type "DATE-TIME" + $valarm->TRIGGER['VALUE'] = 'DATE-TIME'; + */ + } + + // Add location + if(!empty($this->getProp($messageProps, "location"))) { + $vevent->add('LOCATION',$this->getProp($messageProps, "location")); + } + + // Add description + $body = $this->getProp($messageProps, "isHTML") ? $this->getProp($messageProps, "html_body") : $this->getProp($messageProps, "body"); + if(!empty($body)) { + $vevent->add('DESCRIPTION',$body); + } + } + + // write combined ics file + file_put_contents($file, file_get_contents($file) . $vcalendar->serialize()); + } + + if (count($records) > 0) { + $response['status'] = true; + $response['download_token'] = $token; + $response['filename'] = count($records) . "events.ics"; + } else { + $response['status'] = false; + $response['message'] = "No events found. Export skipped!"; + } + $this->addActionData($actionType, $response); $GLOBALS["bus"]->addData($this->getResponseData()); - - if($this->DEBUG) { - error_log("export done, bus data written!"); - } } - + /** * The main import function, parses the uploaded ics file * @param $actionType * @param $actionData */ - private function importCalendar($actionType, $actionData) { - if($this->DEBUG) { - error_log("PHP Timezone: " . $tz); + private function importCalendar($actionType, $actionData) + { + // Get uploaded vcf path + $icsfile = false; + if (isset($actionData["ics_filepath"])) { + $icsfile = $actionData["ics_filepath"]; } - - if(is_readable ($actionData["ics_filepath"])) { - $ical = new ICal($actionData["ics_filepath"], $GLOBALS["settings"]->get("zarafa/v1/plugins/calendarimporter/default_timezone"), $actionData["timezone"], $actionData["ignore_dst"]); // Parse it! - - if(isset($ical->errors)) { - $response['status'] = false; - $response['message']= $ical->errors; - } else if(!$ical->hasEvents()) { - $response['status'] = false; - $response['message']= "No events in ics file"; - } else { - $response['status'] = true; - $response['parsed_file']= $actionData["ics_filepath"]; - $response['parsed'] = array ( - 'timezone' => $ical->timezone(), - 'calendar' => $ical->calendar(), - 'events' => $ical->events() - ); + + // Get store id + $storeid = false; + if (isset($actionData["storeid"])) { + $storeid = $actionData["storeid"]; + } + + // Get folder entryid + $folderid = false; + if (isset($actionData["folderid"])) { + $folderid = $actionData["folderid"]; + } + + // Get uids + $uids = array(); + if (isset($actionData["uids"])) { + $uids = $actionData["uids"]; + } + + $response = array(); + $error = false; + $error_msg = ""; + + // parse the ics file a last time... + $parser = null; + try { + $parser = VObject\Reader::read( + fopen($icsfile,'r') + ); + } catch (Exception $e) { + $error = true; + $error_msg = $e->getMessage(); + } + + $events = array(); + if (count($parser->VEVENT) > 0) { + $events = $this->parseCalendarToArray($parser); + $store = $GLOBALS["mapisession"]->openMessageStore(hex2bin($storeid)); + $folder = mapi_msgstore_openentry($store, hex2bin($folderid)); + + $importall = false; + if (count($uids) == count($events)) { + $importall = true; } + + $propValuesMAPI = array(); + $properties = $GLOBALS['properties']->getAppointmentProperties(); + // extend properties... + $properties["body"] = PR_BODY; + + $count = 0; + + // iterate through all events and import them :) + foreach ($events as $event) { + if (isset($event["startdate"]) && ($importall || in_array($event["internal_fields"]["event_uid"], $uids))) { + + $message = mapi_folder_createmessage($folder); + + // parse the arraykeys + foreach ($event as $key => $value) { + if ($key !== "internal_fields") { + if(isset($properties[$key])) { + $propValuesMAPI[$properties[$key]] = $value; + } + } + } + + $propValuesMAPI[$properties["commonstart"]] = $propValuesMAPI[$properties["startdate"]]; + $propValuesMAPI[$properties["commonend"]] = $propValuesMAPI[$properties["duedate"]]; + $propValuesMAPI[$properties["duration"]] = ($propValuesMAPI[$properties["duedate"]] - $propValuesMAPI[$properties["startdate"]]) / 60; // Minutes needed + $propValuesMAPI[$properties["reminder"]] = false; // needed, overwritten if there is a timer + + $propValuesMAPI[$properties["message_class"]] = "IPM.Appointment"; + $propValuesMAPI[$properties["icon_index"]] = "1024"; + + // TODO: set attendees and alarms + + mapi_setprops($message, $propValuesMAPI); + mapi_savechanges($message); + if ($this->DEBUG) { + error_log("New event added: \"" . $event["subject"] . "\".\n"); + } + $count++; + } + } + + $response['status'] = true; + $response['count'] = $count; + $response['message'] = ""; + } else { - $response['status'] = false; - $response['message']= "File could not be read by server"; + $response['status'] = false; + $response['count'] = 0; + $response['message'] = $error ? $error_msg : "ICS file empty!"; } - + $this->addActionData($actionType, $response); $GLOBALS["bus"]->addData($this->getResponseData()); - - if($this->DEBUG) { - error_log("parsing done, bus data written!"); - } } - + /** * Store the file to a temporary directory, prepare it for oc upload * @param $actionType * @param $actionData * @private */ - private function getAttachmentPath($actionType, $actionData) { + private function getAttachmentPath($actionType, $actionData) + { // Get store id $storeid = false; - if(isset($actionData["store"])) { + if (isset($actionData["store"])) { $storeid = $actionData["store"]; } // Get message entryid $entryid = false; - if(isset($actionData["entryid"])) { + if (isset($actionData["entryid"])) { $entryid = $actionData["entryid"]; } @@ -455,42 +484,41 @@ class CalendarModule extends Module { // Get number of attachment which should be opened. $attachNum = false; - if(isset($actionData["attachNum"])) { + if (isset($actionData["attachNum"])) { $attachNum = $actionData["attachNum"]; } // Check if storeid and entryid isset - if($storeid && $entryid) { + if ($storeid && $entryid) { // Open the store $store = $GLOBALS["mapisession"]->openMessageStore(hex2bin($storeid)); - - if($store) { + + if ($store) { // Open the message $message = mapi_msgstore_openentry($store, hex2bin($entryid)); - - if($message) { + + if ($message) { $attachment = false; // Check if attachNum isset - if($attachNum) { + if ($attachNum) { // Loop through the attachNums, message in message in message ... - for($i = 0; $i < (count($attachNum) - 1); $i++) - { + for ($i = 0; $i < (count($attachNum) - 1); $i++) { // Open the attachment - $tempattach = mapi_message_openattach($message, (int) $attachNum[$i]); - if($tempattach) { + $tempattach = mapi_message_openattach($message, (int)$attachNum[$i]); + if ($tempattach) { // Open the object in the attachment $message = mapi_attach_openobj($tempattach); } } // Open the attachment - $attachment = mapi_message_openattach($message, (int) $attachNum[(count($attachNum) - 1)]); + $attachment = mapi_message_openattach($message, (int)$attachNum[(count($attachNum) - 1)]); } // Check if the attachment is opened - if($attachment) { - + if ($attachment) { + // Get the props of the attachment $props = mapi_attach_getprops($attachment, array(PR_ATTACH_LONG_FILENAME, PR_ATTACH_MIME_TAG, PR_DISPLAY_NAME, PR_ATTACH_METHOD)); // Content Type @@ -499,29 +527,33 @@ class CalendarModule extends Module { $filename = "ERROR"; // Set filename - if(isset($props[PR_ATTACH_LONG_FILENAME])) { + if (isset($props[PR_ATTACH_LONG_FILENAME])) { $filename = $props[PR_ATTACH_LONG_FILENAME]; - } else if(isset($props[PR_ATTACH_FILENAME])) { - $filename = $props[PR_ATTACH_FILENAME]; - } else if(isset($props[PR_DISPLAY_NAME])) { - $filename = $props[PR_DISPLAY_NAME]; - } - + } else { + if (isset($props[PR_ATTACH_FILENAME])) { + $filename = $props[PR_ATTACH_FILENAME]; + } else { + if (isset($props[PR_DISPLAY_NAME])) { + $filename = $props[PR_DISPLAY_NAME]; + } + } + } + // Set content type - if(isset($props[PR_ATTACH_MIME_TAG])) { + if (isset($props[PR_ATTACH_MIME_TAG])) { $contentType = $props[PR_ATTACH_MIME_TAG]; } else { // Parse the extension of the filename to get the content type - if(strrpos($filename, ".") !== false) { + if (strrpos($filename, ".") !== false) { $extension = strtolower(substr($filename, strrpos($filename, "."))); $contentType = "application/octet-stream"; - if (is_readable("mimetypes.dat")){ - $fh = fopen("mimetypes.dat","r"); + if (is_readable("mimetypes.dat")) { + $fh = fopen("mimetypes.dat", "r"); $ext_found = false; - while (!feof($fh) && !$ext_found){ + while (!feof($fh) && !$ext_found) { $line = fgets($fh); preg_match("/(\.[a-z0-9]+)[ \t]+([^ \t\n\r]*)/i", $line, $result); - if ($extension == $result[1]){ + if ($extension == $result[1]) { $ext_found = true; $contentType = $result[2]; } @@ -530,24 +562,24 @@ class CalendarModule extends Module { } } } - - + + $tmpname = tempnam(TMP_PATH, stripslashes($filename)); // Open a stream to get the attachment data $stream = mapi_openpropertytostream($attachment, PR_ATTACH_DATA_BIN); $stat = mapi_stream_stat($stream); // File length = $stat["cb"] - - $fhandle = fopen($tmpname,'w'); + + $fhandle = fopen($tmpname, 'w'); $buffer = null; - for($i = 0; $i < $stat["cb"]; $i += BLOCK_SIZE) { + for ($i = 0; $i < $stat["cb"]; $i += BLOCK_SIZE) { // Write stream $buffer = mapi_stream_read($stream, BLOCK_SIZE); - fwrite($fhandle,$buffer,strlen($buffer)); + fwrite($fhandle, $buffer, strlen($buffer)); } fclose($fhandle); - + $response = array(); $response['tmpname'] = $tmpname; $response['filename'] = $filename; @@ -569,6 +601,129 @@ class CalendarModule extends Module { $GLOBALS["bus"]->addData($this->getResponseData()); } } -}; + + /** + * Function that parses the uploaded ics file and posts it via json + * @param $actionType + * @param $actionData + */ + private function loadCalendar($actionType, $actionData) + { + $error = false; + $error_msg = ""; + + if (is_readable($actionData["ics_filepath"])) { + $parser = null; + + try { + $parser = VObject\Reader::read( + fopen($actionData["ics_filepath"],'r') + ); + //error_log(print_r($parser->VTIMEZONE, true)); + } catch (Exception $e) { + $error = true; + $error_msg = $e->getMessage(); + } + if ($error) { + $response['status'] = false; + $response['message'] = $error_msg; + } else { + if (count($parser->VEVENT) == 0) { + $response['status'] = false; + $response['message'] = "No event in ics file"; + } else { + $response['status'] = true; + $response['parsed_file'] = $actionData["ics_filepath"]; + $response['parsed'] = array( + 'events' => $this->parseCalendarToArray($parser), + 'timezone' => isset($parser->VTIMEZONE->TZID) ? (string)$parser->VTIMEZONE->TZID : (string)$parser->{'X-WR-TIMEZONE'}, + 'calendar' => (string)$parser->PRODID + ); + } + } + } else { + $response['status'] = false; + $response['message'] = "File could not be read by server"; + } + + $this->addActionData($actionType, $response); + $GLOBALS["bus"]->addData($this->getResponseData()); + + if ($this->DEBUG) { + error_log("parsing done, bus data written!"); + } + } + + /** + * Create a array with contacts + * + * @param {VObject} $calendar ics parser object + * @return array parsed events + * @private + */ + private function parseCalendarToArray($calendar) + { + $events = array(); + foreach ($calendar->VEVENT as $Index => $vEvent) { + // Sabre\VObject\Parser\XML\Element\VEvent + $properties = array(); + + //uid - used for front/backend communication + $properties["internal_fields"] = array(); + $properties["internal_fields"]["event_uid"] = base64_encode($Index . $vEvent->UID); + + $properties["startdate"] = (string)$vEvent->DTSTART->getDateTime()->getTimestamp(); + $properties["duedate"] = (string)$vEvent->DTEND->getDateTime()->getTimestamp(); + $properties["location"] = (string)$vEvent->LOCATION; + $properties["subject"] = (string)$vEvent->SUMMARY; + $properties["body"] = (string)$vEvent->DESCRIPTION; + $properties["comment"] = (string)$vEvent->COMMENT; + $properties["timezone"] = (string)$vEvent->DTSTART["TZID"]; + $properties["organizer"] = (string)$vEvent->ORGANIZER; + $properties["busystatus"] = array_search((string)$vEvent->{'X-MICROSOFT-CDO-INTENDEDSTATUS'}, $this->busystates); // X-MICROSOFT-CDO-BUSYSTATUS + $properties["transp"] = (string)$vEvent->TRANSP; + //$properties["trigger"] = (string)$vEvent->COMMENT; + $properties["priority"] = (string)$vEvent->PRIORITY; + $properties["private"] = ((string)$vEvent->CLASS) == "PRIVATE" ? true : false; + if(!empty((string)$vEvent->{'X-ZARAFA-LABEL'})) { + $properties["label"] = array_search((string)$vEvent->{'X-ZARAFA-LABEL'}, $this->labels); + } + $properties["last_modification_time"] = (string)$vEvent->{'LAST-MODIFIED'}->getDateTime()->getTimestamp(); + $properties["creation_time"] = (string)$vEvent->CREATED->getDateTime()->getTimestamp(); + $properties["rrule"] = (string)$vEvent->RRULE; + + // Attendees + $properties["attendees"] = array(); + if(isset($vEvent->ATTENDEE) && count($vEvent->ATTENDEE) > 0) { + foreach($vEvent->ATTENDEE as $attendee) { + $properties["attendees"][] = array( + "name" => (string)$attendee["CN"], + "mail" => (string)$attendee, + "status" => (string)$attendee["PARTSTAT"], + "role" => (string)$attendee["ROLE"] + ); + } + } + + // Alarms + $properties["alarms"] = array(); + if(isset($vEvent->VALARM) && count($vEvent->VALARM) > 0) { + foreach($vEvent->VALARM as $alarm) { + $properties["alarms"][] = array( + "description" => (string)$alarm->DESCRIPTION, + "trigger" => (string)$alarm->TRIGGER, + "type" => (string)$alarm->TRIGGER["VALUE"] + ); + } + } + + array_push($events, $properties); + } + + return $events; + } +} + +; ?> diff --git a/php/plugin.calendarimporter.php b/php/plugin.calendarimporter.php index ba28d83..bd8aec5 100644 --- a/php/plugin.calendarimporter.php +++ b/php/plugin.calendarimporter.php @@ -19,25 +19,31 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * - * + */ +require_once __DIR__ . "/download.php"; + +/** * calendarimporter Plugin * * With this plugin you can import a ics file to your zarafa calendar * */ -class Plugincalendarimporter extends Plugin { +class Plugincalendarimporter extends Plugin +{ /** * Constructor */ - function Plugincalendarimporter() {} + function __construct() {} /** * Function initializes the Plugin and registers all hooks * * @return void */ - function init() { + function init() + { $this->registerHook('server.core.settings.init.before'); + $this->registerHook('server.index.load.custom'); } /** @@ -47,11 +53,17 @@ class Plugincalendarimporter extends Plugin { * @param mixed $data object(s) related to the hook * @return void */ - function execute($eventID, &$data) { - switch($eventID) { + function execute($eventID, &$data) + { + switch ($eventID) { case 'server.core.settings.init.before' : $this->injectPluginSettings($data); break; + case 'server.index.load.custom': + if ($data['name'] == 'download_ics') { + calendarimporter\DownloadHandler::doDownload(); + } + break; } } @@ -60,17 +72,17 @@ class Plugincalendarimporter extends Plugin { * settings. * @param Array $data Reference to the data of the triggered hook */ - function injectPluginSettings(&$data) { + function injectPluginSettings(&$data) + { $data['settingsObj']->addSysAdminDefaults(Array( 'zarafa' => Array( 'v1' => Array( 'plugins' => Array( 'calendarimporter' => Array( - 'enable' => PLUGIN_CALENDARIMPORTER_USER_DEFAULT_ENABLE, - 'enable_export' => PLUGIN_CALENDARIMPORTER_USER_DEFAULT_ENABLE_EXPORT, + 'enable' => PLUGIN_CALENDARIMPORTER_USER_DEFAULT_ENABLE, 'enable_sync' => PLUGIN_CALENDARIMPORTER_USER_DEFAULT_ENABLE_SYNC, - 'default_calendar' => PLUGIN_CALENDARIMPORTER_DEFAULT, - 'default_timezone' => PLUGIN_CALENDARIMPORTER_DEFAULT_TIMEZONE + 'default_calendar' => PLUGIN_CALENDARIMPORTER_DEFAULT, + 'default_timezone' => PLUGIN_CALENDARIMPORTER_DEFAULT_TIMEZONE ) ) ) @@ -78,4 +90,5 @@ class Plugincalendarimporter extends Plugin { )); } } + ?> diff --git a/resources/css/calendarimporter-main.css b/resources/css/calendarimporter-main.css index d3d595a..d101e01 100644 --- a/resources/css/calendarimporter-main.css +++ b/resources/css/calendarimporter-main.css @@ -2,5 +2,29 @@ background: url(../images/import_icon.png) no-repeat !important; background-repeat: no-repeat; background-position: center; - background-size: 18px!important; -} \ No newline at end of file +} + +.icon_calendarimporter_export { + background: url(../images/download.png) no-repeat; + background-repeat: no-repeat; + background-position: center; +} + +.icon_calendarimporter_import { + background: url(../images/upload.png) no-repeat; + background-repeat: no-repeat; + background-position: center; +} + +.zarafa-caiplg-container { + width: 100%; + height: 50px; +} + +.zarafa-caiplg-button .x-btn-small { + width: 80%; + height: 30px; + margin-left: 10%; + margin-right: 10%; + margin-top: 10px; +} diff --git a/resources/images/download.png b/resources/images/download.png new file mode 100755 index 0000000..38a8281 Binary files /dev/null and b/resources/images/download.png differ diff --git a/resources/images/download.xcf b/resources/images/download.xcf new file mode 100755 index 0000000..9a5b62c Binary files /dev/null and b/resources/images/download.xcf differ diff --git a/resources/images/upload.png b/resources/images/upload.png new file mode 100644 index 0000000..9e3158a Binary files /dev/null and b/resources/images/upload.png differ diff --git a/resources/images/upload.xcf b/resources/images/upload.xcf new file mode 100755 index 0000000..e89500d Binary files /dev/null and b/resources/images/upload.xcf differ