diff --git a/egwical/doc/EgwIcal-BUGS-and-TODOS.txt b/egwical/doc/EgwIcal-BUGS-and-TODOS.txt deleted file mode 100644 index 1cd51ba64d..0000000000 --- a/egwical/doc/EgwIcal-BUGS-and-TODOS.txt +++ /dev/null @@ -1,95 +0,0 @@ -/*! \page pageegwicalbugandtodo BUGS and TODOS - -
-Know BUGS and things todo
----------------------------
-TODO means: should be done/would be nice  in a newer release
-BUG means: known problem needs to be fixed
-FAIl means: known failure to provide (not easily to be done/fixed
-
-(note: this list is probably not quite up todate)
-
-
-release: VERSION 0.9.0 NEED TO UPDATE THIS!!
-
-new in V0.7.78 versus v0.7.70:
-
-  bovevents:
-
-+ whole day events import/export seems to work nice
-+ continue on erroneous overwrites (errors only visible in errorlog)
-+ no error messages for forbidden overwrite events of non owned events
-+ errormessages (when activated) only shows problematic events
-++ basic (multiple) VALARM import and export, working! (without action select)
-+ allow for vevents with either DTEND or DURATION
-+ provided (horde iCalendar) patch to prevent segfaults on some bad iCal inputs
-
-1) EgwIcal package general (V0.9)
-----------------
-
-
-[ ]1.2 TODO get it nicely into egw cvs
-[+/-]1.7 TODO/WISH allow for import of ATTENDEEs not in Egw yet (create new addressbook entry?)
-         [+](ad hoc solution: add CN and mailto to description)
-[+/-]1.4 TODO check and generate source code documentation(phpdoc or doxygen)
-
-[ ]1.5 TODO test these routines in use for syncml import/export
-
-1.6 TODO/WISH: nothing done yet for vfreebusy, vjournal, notes, components 
-    only vevents and vtodos are supported.
-
-
-3) egwical.egwical (V0.9.01)
---------------------
-
-[+?]3.1 TODO check/implement correct timezone handling (seems ok) 
-[ ]3.9 TEST with syncml 		
-[ ]3.2 TODO/WISH handle location (GEO), link(?), url, delegation, ()CONTACT?
-[ ]3.3 TODO write more documentation (continue mainpage)
-[ ]3.4 TODO add accumulting buffer system to egwical
-
-4) egwical.bocalupdate_vevents (V0.9.02)
-------------------------------
-
-[+?]4.1 TODO check/implement correct timezone handling (related 3.1)
-[ ]4.2a TODO/WISH handle URL, GEO etc. fields. (needs extra fields handling in bocalupdate!)
-[ ]4.2b FAIL rrule-COUNT import not implemented in egw?
-[+]4.2 BUG!!!!  rrule-BYDAY import goes wrong. FIXED (v0.7.76)
-[+]4.3 TODO check and improve ORGANIZER,ATTENDEE<-> participants mapping
-	     ATTENDEE s import and export (appears to work oke >= V0.7.71) 
-[+]4.4 TODO handle import and export of ALARMS
-[ ]4.7 TODO (ad hoc) add non egw known attendees to description on import
-[ ]4.8 TODO move compatibility code to compat classes.
-
-
-4.9 see 3.2
-
-
-5) egwical.boinfolog_vtodos (V0.9.02)
-----------------------------
-5.1 TODO check/implement correct timezone handling  (related 3.1)
-5.3 FAIL import/export more than 1 category per task (egw doesnot allow)
-5.3 TODO check and improve ORGANIZER,ATTENDEE<-> info_responsible etc mapping
-5.4 TODO handle import and export of ALARMS
-5.5 TODO rewrite code into supportedFields structure (for next version)
-[ ]5.9 TODO rewrite into skeleton structure analog to egwical.bocalupdate_vevents
-
-
-
-10.) in  used routines from others:
-
-10.1 BUG Horde_iCalendar(1.2rc6): EXDATE bug
-  -[+]fixed by patch 'exdate ....'
-10.2 BUG  Horde_iCalendar(1.2rc6): standard.php Warning
-  -[+]fixed by patch '...??..'
-
-10.3 BUG infolog(1.2rc6): datetime is 1 hour wrong for untimed due field in tasks
-
-11) detected errors/flaws in other programs
-
-11.1 Korganizer 3.5: recurrence endondate display is interpreted different from egw and
-mozilla (and probable also rfc 2445) 
-
-
-
-*/ \ No newline at end of file diff --git a/egwical/doc/EgwIcal-Timezone-handling.txt b/egwical/doc/EgwIcal-Timezone-handling.txt deleted file mode 100644 index d75b3c49b3..0000000000 --- a/egwical/doc/EgwIcal-Timezone-handling.txt +++ /dev/null @@ -1,183 +0,0 @@ -/*! \page pageegwicaltzh EgwIcal Timezone Handling - -Short description on the timezone handling in EgwIcal - -@date 20060216 -@version 0.9.04 -@author JVL -@note Document needs further editing and annotations!! - - - -In EgwIcal the timed data of Egroupware like events and tasks get -converted to elements for an iCalendar. In the Egroupware server we -are dealing with socalled "egw server" time, in applications that a -user of egw runs, the user can set a "locale" and thereby defining a -"local timezone". And finally when events and task get exported to an -iCalendar that is sent to a client or uploaded from it, they may also -have their timesettings defined according to some "timezone". - -How is this all handled in EgwIcal? - - - -@section secegwicalgentzh EgwIcal general Timezone handling - -In general EgwIcal distinguishes between two different types of time -descriptions for an event. An event can either be a: - - - -For handling DT events it can be profitable to use a globally unified standard -for describing the timingly definitions, like e.g. UTC. -And indeed: - - - -For handling D events you can best give a (timezone/geo) relative -description together with the GEO location. Then someone who wants to -visit such a event can checkout the location and see what timezone -they have there at moment of the event, calculate it back to UTC and -then she knows when to get there. -Egw and EgwIcal are no very sophisticated in handling these: - -- RE.1 (I am not 100% sure:) Egw tries to handle DATE events relative to - the UserInterface its timezone: the so called USER-TIME. - -and for EgwIcal: - -- REI.1 EgwIcal tries to handle DATE events relative to - the UserInterface timezone (USER-TIME) of the IcalSrv proces of the - logged in user. - -and keep in mind: - -- REI.2 EgwIcal currently will only import or export DATE events - for whole day events or for occurence settings of recurrent - events - -In the following sections I will explain a bit more what this means -for import of Ical data from clients and export to it. - - - - -@section secegwicalimptzh EgwIcal Timezone handling for icaldata import from a client. - -..... - -@subsection subsecvtmz VTIMEZONE import handling. - - No VTIMEZONE ical elements are parsed or used - This has a consequence: - - - no basic import timezone setting via this supported - - - no imported timezones with identifiers that can be referenced by - VEVENTS or VTODOS are supported - -@subsection subsecdtimp DATETIME formatted data import handling. - - DATETIME formatted data is inspected for its timezone. If the - timezone is UTC ('Z') then it is converted (i.e. copied) to UTC - before processing further. If the timezone is not given of is - referenced with a key to a VTIMEZONE component in the Icalendar - file, this timezone info is discarded and a "timezoned" DATETIME - is just interpreted as relative to the USERTIME of the IcalSrv - process: any timezone info is neglected. - - Clearly this can be wrong in many occasions: thus this should be - considered a BUG! - -@subsection subsecdimp DATE formatted data import handling. - - DATE formatted data is ust interpreted as relative to the USERTIME of the IcalSrv - process: any timezone info is neglected. - - -@subsection subsecrruleimp Importing Recurrence Elements - - - - Doing recurrence calculation in UTC is notably not a good thing to - do because DayTime Savings changes during the runtime of the - recurring event can cause troubles. The best thing to do is to - calculate the recurrence in the geo/time-zone of the definer. See - @url ... of the CAlConnect Group for this. But as clients often dont - export their timezones, (and we dont do any processing of it anyhow) - we do the following: - -
    -
  1. first the START and (if there UNTIL) dates are converted to UTC - dates. Then these are converted to the IcalSrv locale setting. - -
  2. Then the recurrence rules are evaluated, and converted to the info - Egw needs. Note: Egw cannot use the COUNT field, so EgwIcal has to - rewrite it to a UNTIL value. -
- - - -@section secegwicalexptzh EgwIcal Timezone handling for icaldata export to a client. - -On export .... - -- all Egw DATETIME info is exported in UTC time. - -- all Egw DATE info is exported without any timezone info, - and thus should best be considered in the USERTIME of the IcalSrv - process. - - -@subsection subsecrruleexp Exporting Recurrence Elements - -On export Recurrence Rules are interpreted as follows: - - - - - -Hope this explains things a bit. - -Jan - -*/ \ No newline at end of file diff --git a/egwical/doc/EgwIcal-intro.txt b/egwical/doc/EgwIcal-intro.txt deleted file mode 100644 index 1f01966be9..0000000000 --- a/egwical/doc/EgwIcal-intro.txt +++ /dev/null @@ -1,182 +0,0 @@ -/*! @mainpage EgwIcal package for Egroupware - -@NOTE this text is not up to date -@version 0.9.01 -@author jvl - -The EgwIcal package provides routines for converting between iCalendar RFC -2445 conformant dataelements (like VEVENTS, VTODOS, VALARMS etc.) and -corresponding Egroupware database entries (like calendar events, -infolog tasks etc.). EgwIcal also provides routines to do import to -and export from the Egroupware system for these iCalendar elements, -thereby doing the conversion on the fly. Finally, EgwIcal provides a -buffering feature where mixed sets of these elements can be accumulated and -then be imported or exported all at once. - -@section secinstall SHORT experimental Install How-To: - - - Install the EgwIcal package by either checking out the egwical module from cvs - or untarring some tarball egwical-vx.y.x.tgz of the package (when available). - - -@section secusage Usage of the EgwIcal system - -The EgwIcal system allows four(or 3?) characteristic ways to help you -with manipulating iCalendar data in a Egw context:..... - -@section secusageiecnv Converting iCalendar elements to Egw elements - -To convert a iCalendar datacomponent e.g. of type "VEVENT" into a -corresponding egw component of e.g. "calendar event" you can use the -following in your code: - - ...... - - -@section secusageeicnv Converting Egw elements to iCalendar elements. - -To convert a egw component of e.g. "calendar event" into a -corresponding iCalendar datacomponent of e.g. type "VEVENT"you can use the -following in your code: - - ...... - - -@section secusageimport Importing iCalendar elements into Egw -applications storage. - -To import a iCalendar datacomponentof e.g. type "VEVENT" as a -corresponding egw component of type "calendar event" into your -calendar application (its database) you can use the -following in your code: - - ...... - - -@section secusageexport Exporting Egw application elements as iCalendar elements. - -To export as a egw datacomponent of e.g. type "calendar event" from your -calendar application (its database) as a iCalendar datacomponentof e.g. type "VEVENT", -you can use the following in your code: - - ...... - - -@section secusageexpimpbuffer Exporting (mixed) collections of iCalendar elements. - -Beside directly exporting single elements or sets of -iCalendar data generated generated from a egw application like -calendar, you can also use the "buffer" system of EgwIcal, to collect -various sets of such dataelements, even from different Egw -applications (like calendar and infolog), and then later on export -these all together as one big iCalendar. - -To do collection followed by export you can use code like below: - ...... - - - -@section secimplementation How is EgwIcal implemented? - -To use or extend EgwIcal best, as a developer, it may be good know a bit about -its implementation. -EgwIcal is built according to the Workers Union Representatives -Hierarchy (WURH) pattern. Quite a mouthfull, and probably there are -somewhere better names for this pattern (see ...). In @ref pageegwicalwurh -you can read more on this. - -Basically it means that there is one super "worker" class -@ref egwical that uses for specific work like e.g. conversion -between VEVENTS and calendar tasks, a specific subclass -like e.g. bocalupdate_vevents that is connected to the -egwical object via a socalled "representative" member in the registry $reg_rscs -(attribute). - -Currently EgwIcal has the following subclasses: - -- bocalupdate_vevents for manipulating calendar events as - VEVENTS. - -- boinfolog_vtodos for manipulating infolog tasks as VTODOS. - -Future subclasses might be: - -- ???_vjournals for manipulating .... as VJOURNALS. - -- bocal_vfreebusies for manipulating calendar data as - VFREEBUSY elements. - -- addressbook_vcard for manipulating addressdata data as - VCARDS. - -- ???_vnotes for manipulating .... as VNOTES. - - - -@section secdeletioncheatcode Cheatcode for Deleting Calendars, events or todos - -Egwical provides a special "hackish" feature specifically meant for -use with the crippeld ical-over-http (aka webcal) implementation that -the package IcalSrv provides for Egroupware. - -This IcalSrv implementation does not support deletion of egw calendar -or infolog elements directly (see the IcalSrv package). As a help out -the "cheat" is implemented that: you can though delete an item by -simply giving the VEVENT or VTODO 'SUMMARY' field a value -X-DELETE or _DELETED_ and then importing it -through the Egwical system. I you do so the the corresponding egw -element from calendar or infolog will get deleted. - - -@section secpatches Patches - - -You may need to apply some of the patches found in PATCHES. -Currently there a two patches to fix a warning and a bug (related to EXDATE -fields handling) in the horde routines. -Note these may be already committed in the CVS version. - - - -@section sectest Extra testing - -The package contains two "compatibility" classes (@ref boical and @ref vcalinfolog) with -which you can replace -the current infolog/inc/class.vcalinfolog.inc.php resp. -calendar/inc/class.boical.inc.php -files. - -When done so, the egw syncml, ical import/export and infolog import/export in egw -will all use the new code. This way you can discover more bugs and failure in the code :) - -But, when not renamed, these programs will use the old code (and thus are not broken or -improved by the new one..) - - -@section secdocumentation Documentation - -There is (somewhere) complete doxygen generated documentation for the -EgwIcal package. Otherwise you can generate it yourself by using -doxygen on the source filetree. Maybe phpdocumenter can give you also -something usefull. And maybe you are just reading it now this very moment... - - - -@section secbugandtodo BuG and todo list - - @todo notably timezone handling in EgwIcal should be documented and -possible features to allow import/export and use of iCalendar -VTIMEZONE components should be provided. - - -see BUGs and TODOs in @ref pageegwicalbugandtodo - - - - -have fun - - -JVL - - -*/ \ No newline at end of file diff --git a/egwical/doc/egwical-doxydoc.tgz b/egwical/doc/egwical-doxydoc.tgz deleted file mode 100644 index a3c46fdf8b..0000000000 Binary files a/egwical/doc/egwical-doxydoc.tgz and /dev/null differ diff --git a/egwical/doc/egwical-wurh-pattern.txt b/egwical/doc/egwical-wurh-pattern.txt deleted file mode 100644 index b33329a01c..0000000000 --- a/egwical/doc/egwical-wurh-pattern.txt +++ /dev/null @@ -1,205 +0,0 @@ -/*! -\page pageegwicalwurh EgwIcal Workers Union Representatives Hierarchy Pattern -implementation. - -@author JVL -@date 20060214 -@version v0.9.02 - -The current Egw Ical package provides routines for exporting iCalendar -data like vevents, vtodos, vcards etc. from the various corresponding -Egroupware packages (the "backends"). And vice versa importing these to the datastores -of these packages. On the other hand there can also be a variety of -interface components that transport e.g these exported vevents to -further applications (the "clients"). Think e.g on the "icalsrv" -service to transport whole sets of vevents in one go over http to a -client, or the "syncml" service that transports them to syncml -speaking device, or simple routine that let you save or upload a -calendar file from within the webgui. - -An iCalendar data object can hold a set of these various kinds of -data-elements as parts of itself. And these data-elements itself can -also be composed of sub-elements (like e.g. VALARM and VTIMEZONE -components). - - -So in this situation we have Wholes (like an iCalendar object) with -Parts (like groups of Vevents and groups of Vtodos) on the one hand. -And on the other hand we have dedicated subappliations that may handle -these groups of Part data. To implement this we can make use of a -smart combination of two implementation primitives "compounds" and -"classes and subclasses". - -In the WURH pattern the combination of these two is very rather -outspoken and quite entangled and even a bit tricky: each specific -type of Part is "represented" by specific subclass of the class of -Whole compound. The data in the parts can now be manipulated in two -ways: - -1) all together as whole, via methods of the compound, or -2) all in the group of a part, by the methods of the (associated) -subclass its representative. - -@note I forgot the official (GOF) name of the pattern (if there is -any..) - - - -\section secwurhexample Example WURH pattern implementation: Meal preparation - -As simple example should explain this: Meal preparation URH pattern -implementation - -think of the preparation of meal, that consist of soup and meat. -To "cook" the meal, the soup has to be boiled and the meat has to be -baked. - -in OO notation: <>- or . . means member of, -<- means subclass of - -Classes: -
-MealCooker <- SoupCooker;     MealCooker <- MeatCooker;
-MealCooker <>- SoupCooker;    MealCooker <>- MeatCooker;
-
-Methods: -
-MealCooker->cook();  SoupCooker->boil();   MeatCooker->bake();
-
-and possibly the cook() method may even, for easy of use in the Soup and -Meat classes by implemented (overridden) by the boil() resp. bake() method. - -Now the code to prepare to have $mymealck prepare a meail with $mysoupck and $mymeatck (without -subclass overrriding): -
-$mymealck = New MealCooker;
-$mymeatck = New MeatCooker;
-$mysoupck = New SoupCooker;
-
-$meat_in_mealck =  $mymealck->addMeatHandler($mymeatck);  
-$soup_in mealck =  $mymealck->addSoupHandler($mysoupck);
-
-// these are in class MealCooker implemented as
-// $this.m = meatcooker_config($mymeatck); resp. $this.s = soupcooker_config($mysoupck); 
-
- -Now cooking the meal is done by, cooking the soup in its appropiate -way (namely "boiling()" )via its union representative ($soup_in_mealck). Note that it is -called "union" representative because multiple SoupCookers parts may have been -added already to use. And also cooking the meat in its appropiate way -("baking()") likewise. Thus -
-$mymealck->cook([$apiec_of_meat,$avolum_of_soup]) can be done by calling:
-
-		$meat_in_mealck->bake($apiece_of_meat);
-		$soup_in_mealck->boil($avolume_of_soup);
-
-and then you can serve boths parts in one go with: -
-$mymealck->serve();
-
- -If we implemented the specific ways of cooking as overriding subclass -methods for Meal->cook() then in simple cases we dont even need to use -the representatives to call the preparation as we implement to main -cook() method to call all itself on all its parts: -
-$mymealck = New MealCooker;
-$mymeatck = New MeatCooker;
-$mysoupck = New SoupCooker;
-
-		  $mymealck->addMeatHandler($mymeatck);  
-		  $mymealck->addSoupHandler($mysoupck);
-
- -And $mymealck->cook([$apiec_of_meat,$avolum_of_soup]) can then done by -just calling: - -
-  $meat_in_mealck->bake($apiece_of_meat);
-  $soup_in_mealck->boil($avolume_of_soup);
-
-  // which effects in $mymealck.m->cook($apiece_o_fmeat);
-  //           and    $mymealck.s ->cook($avolume_of_soup);
-  // that effects again in $mymealck.m->bake($apiece_o_fmeat);
-  //            and    $mymealck.s->boil($avolume_of_soup);
-
-
- -So this allows for using of manipulation methods of the whole (in case -of simple generic actions reimplemented in the subclasses of the -parts) together with using more specific methods for specific -parts. (e.g. $soup_in_mealck->set_boil_time(10) etc.) - - - -\section securhinei WURH pattern usage in Egwical. - -The Egwical class manages an complete iCalendar component with -VEVENTS, VTODOS etc. as parts. The handling of these part(unions)s is -done by specific subclasses of Egwical, like e.g. infolog_bovtodo and -calendar_bovevents. -The system can be used in two different modes of operation: - -- 1) for conversion of egw tasks, events, etc. to their iCal - counterparts. (the cnv_ methods). - -- 2) for filling the (internal) egwical object with al lot of vtodos and - vevents, either coming from import or from conversion of egw - counterparts. When the compound is filled it can (as a whole) be - exported or imported. - - -add 1) So e.g. exporting a group of events refered to by $event_ids as -VEVENTS goes as follows: -
-$cal = New Bocal;                       // build calendar
-$event_ids = $cal->search("filt_def');  // get group of egw event ids to export.
-
-$ei = New Egwical;		                // build Compound iCalendar processor
-$bve = $ei->addRsc($cal);               // add calendar part and get representive
-$vcalstr = $bve->cnv2VEVENTS($event_ids); // export some events
-
-
- -if we also want to export some VTODOs this goes as follows: - -
-$binf = New Infolog                     // build infolog app. object
-$task_ids = $binf->search("filt_def');  // get group of egw task ids to export.
-
-$bvt = $ei->addRsc($binf);              // add infolog part and get representive
-$vcalstr = $bvt->cnv2VTODOS($task_ids);
-
-
-add 2) the same egw elements from 1) are now first collected in -egwical and then as a whole exported. - -
-$cal = New Bocal;                       // build calendar
-$event_ids = $cal->search("filt_def');  // get group of egw event ids to export.
-
-$ei = New Egwical;		                // build Compound iCalendar processor
-$bve = $ei->addRsc($cal);               // add calendar sys part and get representive
-	 $bve->clear();                     // empty the list of Vevents in bve
-	 $bve->addEventsOntoVEVENTS($event_ids); // add the converted events to vevents in $ei
-
-
-if we also want to add some VTODOs this goes as follows: -
-$binf = New Infolog                     // build infolog app. object
-$task_ids = $binf->search("filt_def');  // get group of egw task ids to export.
-
- $bvt = $ei->addRsc($binf);             // add infolog sys part and get representive
-	  $bvt->clear();                    // empty the list of Vtodos  in bvt
-	  $bvt>addTasksOntoVTODOS($task_ids); // add the converted tasks to vtodos in $ei
-
-
-and finally export the whole iCalendar -
-$ei->export()
-
- - ---------- - -*/ \ No newline at end of file diff --git a/egwical/inc/class.bocalupdate_vevents.inc.php b/egwical/inc/class.bocalupdate_vevents.inc.php deleted file mode 100644 index f263e65ee5..0000000000 --- a/egwical/inc/class.bocalupdate_vevents.inc.php +++ /dev/null @@ -1,1075 +0,0 @@ - (This version. new api rewrite, - * refactoring, and extension). - * @author Lars Kneschke (parts from boical that are reused here) - * @author Ralf Becker (parts from boical that are - * reused here) - * @version 0.9.03 (First WURH version, most stuff used from old bovevents class) - * @since 0.9.03 changed mke_RECUR2rar() api - * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License - */ - class bocalupdate_vevents extends egwical - { - - /** - * @private - * @var boolean - * Switch to print extra debugging about imported and exported events to the httpd errorlog - * stream. - */ - var $evdebug = true; - - /** - * @private - * @var object - * The egw bocal calendar that will be used to transport events from and to - * This is set by setRsc() - */ - var $mycal = null; - - /** - * Describe the provided work capabilities of the class. - * @return string The description as entries for the @ref $reg_workers registry - * table. - */ - function provides_work() - { - return - array('bocalupdate' => array('workerclass' => 'bocalupdate_vevents', - 'workerobj' => null, - 'icalsup' => array('VEVENT')), - // next one is a subclass of bocalupdate, we can work for that too - 'boical' => array('workerclass' => 'bocalupdate_vevents', - 'workerobj' => null, - 'icalsup' => array('VEVENT')), - ); - } - - /** - * Our Constructor, sets the basic class members @ref $ei , @ref supportedFields - * @ref $ical2egwFields and @ref $iprovide_work - */ - function bocalupdate_vevents($prodid='all') - { - // call our abstract superclass constructor - egwical::egwical(); - //@todo rewrite supportedFields setting to distribute it over the egwical - // baseclass and the subclasses cleverly - $this->_set_ical2egwFields(); // add VEVENT and event pairs only - $this->setSupportedFields($prodid); - - return true; - } - - /** - * Set the egw resource that this worker will handle. - * This worker is only capable of handling bocalupdate calendar objects, so it should - * be of that class. This method is mostly called indirectly from a egwical compound - * addRsc() call. But you can call it also directly (if you know what your doing ..) - * @return boolean false on error, true else - */ - function setRsc($egw_rsc) - { - if(!is_a($egw_rsc,'bocalupdate')) - return false; - $this->mycal = $egw_rsc; - return true; - } - - // -------- below only conversion and import/export stuff ----- - - /** - * @private - * @var array $ical2egwFields - * An array containing roughly the mapping from iCalendar - * to egw fields. Set by constructor. - */ - var $ical2egwFields; - - /** - * @private - * @var array $supportedFields - * An array with the current supported fields of the - * importing/exporting device. - * To detect if a certain ical property (eg ORGANIZER) is supported in the current - * data import/export do a isset($this->supportedFields['ORGANIZER']). - * To detect if a certain egw field (eg status) is supported in the current - * data import/export do a - * in_array(array_flatten(array_values($this->supportedFields)),'status') - * or something like that (not tested, implemented, or needed yet..) Maybe should - * implement a method for this.. - * @note This table should probably better be in class @ref egwical - */ - var $supportedFields; - - - - - /** - * @var boolean - * Switch that determines if uid matching is tried. - * - * For a more on uidmatching @see \secimpumatch - * - * If $uid_matching is true then: - * - on import of a vevent the update routines will first try to - * find an existing egw event with the same uid value as present - * in the UID field of the newly to be imported vevent. If this - * succeeds this egw event will get updated with the info from - * the vevent. If this fails a new event will be generated and - * the uid taken from the vevent will be stored in its uid - * field. - * - * if $uid_matching is false then: - * - On import the VEVENT UID field will be checked, if it - * appears to be a previously exported uid value then the - * encoded egw id of the old egw event is retrieved and used for - * update. If it doesnot have a uid value with a valid egw id - * encoding, then the its is handled as being a new VEVENT to be - * imported, and a new egw id will be generated. The old vevent - * uid will though be saved for possible later use, (just as - * with uid_matching on). - */ - var $uid_matching = false; - - /** - * @var boolean - * Switch that determines if events not anymore in egw are allowed to be reimported - * - * Default this is on - */ - var $reimport_missing_events = true; - - - - /** - * Export Egw events and add them to a Horde_iCalendar. - * - * The eGW events in $events are exported to iCalendar VEVENTS and then these are added to - * the Horde_iCalendar object &$hIcal. - * Note that only supported Fields are exported as VEVENTS to the iCalendar. - * - * @section secexpeuid Egw uid export switch - * If $euid_export is set, then for each exported event, the current value of the event uid - * as stored in Egw, will be used to produce a value for the vevent its UID field. When off - * a new UID value will generated with the egw event id encoded. - * - * @param Horde_iCalendar &$hIcal - * object to wich the produced VEvents are added. - * @param array $events the array with eGW events (or event id's) that will be exported - * @param boolean $euid_export switch to enable export of the egw uid fields, when off - * default) the vevents uid fields get a value generated with the egw id encoded. - * @return boolean|int $ok/$vcnt on error: false / on success: nof vevents exported - * @ref $supportedFields determines which fields of VEVENT will be exported - */ - function exportEventsOntoIcal(&$hIcal, $events, $euid_export=false, - $reimport_missing_events=false) - { - $vexpcnt =0; // number of vevents exported - - $veExportFields =& $this->supportedFields; - - if (!is_array($events)) $events = array($events); - - foreach($events as $event) { - // event was passed as an event id - if (!is_array($event)){ - $eid = $event; - if( !$event = $this->mycal->read($eid,null,false,'server')){ - // server = timestamp in server-time(!) - return false; // no permission to read $cal_id - } - // event was passed as an array of fields - } else { - $eid = $event['id']; - // now read it again to get all fields (including our alarms) - $event = $this->mycal->read($eid); - } - - // error_log('>>>>>>>>>>>' .'event to export=' . print_r($event,true)); - - // now create a UID value - if ($euid_export) { - // put egw uid into VEVENT, to allow client to sync with his uids - $eventGUID = $event['uid']; - } else { - $eventGUID = $this->mki_v_guid($eid,'calendar'); - } - - $vevent = Horde_iCalendar::newComponent('VEVENT',$hIcal); - $parameters = $attributes = array(); - // to important to let supportedFields decide on this - $attributes['UID'] = $eventGUID; - - foreach($veExportFields as $veFieldName) { - - switch($veFieldName) { - case 'UID': - // already set - break; - - case 'ATTENDEE': - foreach((array)$event['participants'] as $pid => $partstat) { - if (!is_numeric($pid)) continue; - - list($propval,$propparams) = - $this->mki_vp_4ATTENDEE($pid,$partstat,$event['owner']); - // NOTE: we need to add it already: multiple ATTENDEE fields may be occur - $this->addAttributeOntoVevent($vevent,'ATTENDEE',$propval,$propparams); - } - break; - - case 'CLASS': - $attributes['CLASS'] = $event['public'] ? 'PUBLIC' : 'PRIVATE'; - break; - - // according to rfc, ORGANIZER not used for events in the own calendar - case 'ORGANIZER': - if (!isset($event['participants'][$event['owner']]) - || count($event['participants']) > 1) { - $attributes['ORGANIZER'] = $this->mki_v_CAL_ADDRESS($event['owner']); - $parameters['ORGANIZER'] = $this->mki_p_CN($event['owner']); - } - break; - - // Note; wholeday detection may change the DTEND value later! - case 'DTEND': - // if(date('H:i:s',$event['end']) == '23:59:59') - // $event['end']++; - $attributes[$veFieldName] = $event['end']; - break; - - case 'RRULE': - if ($event['recur_type'] == MCAL_RECUR_NONE) - break; // no recuring event - $attributes['RRULE'] = $this->mki_v_RECUR($event['recur_type'], - $event['recur_data'], - $event['recur_interval'], - $event['start'], - $event['recur_enddate']); - break; - - case 'EXDATE': - if ($event['recur_exception']) { - list( $attributes['EXDATE'], $parameters['EXDATE'])= - $this->mki_vp_4EXDATE($event['recur_exception'],false); - } - break; - - case 'PRIORITY': - if (is_numeric($eprio = $event['priority']) && ($eprio >0) ) - $attributes['PRIORITY'] = $this->mki_v_prio($eprio); - break; - - case 'TRANSP': - $attributes['TRANSP'] = $event['non_blocking'] ? 'TRANSPARENT' : 'OPAQUE'; - break; - - case 'CATEGORIES': - if ($catids = $event['category']){ - $catnamescstr = $this->cats_ids2idnamescstr(explode(',',$catids)); - $attributes['CATEGORIES'] = $catnamescstr; - } - break; - - // @todo find out about AALARM, DALARM, Is this in the RFC !? - case 'AALARM': - foreach($event['alarm'] as $alarmID => $alarmData) { - $attributes['AALARM'] = $hIcal->_exportDateTime($alarmData['time']); - // lets take only the first alarm - break; - } - break; - - case 'DALARM': - foreach($event['alarm'] as $alarmID => $alarmData) { - $attributes['DALARM'] = $hIcal->_exportDateTime($alarmData['time']); - // lets take only the first alarm - break; - } - break; - - case 'VALARM': - foreach($event['alarm'] as $alarmID => $alarmData) { - $this->mki_c_VALARM($alarmData, $vevent, - $event['start'], $veExportFields); - } - break; - - case 'STATUS': // note: custom field in event - if (! $evstat = strtoupper($event['status'])) - $evstat = 'CONFIRMED'; //default.. - $attributes['STATUS'] = $evstat; - break; - - default: - // only use default for level1 VEVENT fields - if(strpos($veFieldName, '/') !== false) - break; - // use first related field only for the simple conversion - $efield = $this->ical2egwFields[$veFieldName][0]; - if ($event[$efield]) { // dont write empty fields - $attributes[$veFieldName] = $event[$efield]; - } - break; - } - - } //end foreach - - // wholeday detector (DTEND =23:59:59 && DTSTART = 00:00) - // if detected the times will be exported in VALUE=DATE format - if(((date('H:i:s',$event['end']) == '23:59:59') || - (date('H:i:s',$event['end']) == '00:00:00')) - && (date('H:i',$event['start'] == '00:00'))){ - $attributes['DTSTART'] = - $this->hi->_parseDate(date('Ymd',$event['start'])); - $attributes['DTEND'] = - $this->hi->_parseDate(date('Ymd',$event['end']+1)); - $parameters['DTEND']['VALUE'] = 'DATE'; - $parameters['DTSTART']['VALUE'] = 'DATE'; - // error_log('WHOLE DAY DETECTED'); - } - - // handle created and modified field setting - $created = $this->get_TSdbAdd($event['id'],'calendar'); - if (!$created && !$modified) - $created = $event['modified']; - if ($created) - $attributes['CREATED'] = $created; - if (!$modified) - $modified = $event['modified']; - if ($modified) - $attributes['LAST-MODIFIED'] = $modified; - - // add all collected attributes (not yet added) to the vevent - foreach($attributes as $aname => $avalue) { - $this->addAttributeOntoVevent($vevent, - $aname, - $avalue, - $parameters[$aname]); - } - $hIcal->addComponent($vevent); - $vexpcnt += 1; - } - - return $vexpcnt; //return nof vevents exported - } - - - - - /** - * Import all VEVENTS from a Horde_iCalendar into Egw - * - * The ical VEVENTS components that are contained in de $hIcal Horde_iCalendar - * are converted to eGW events and imported into the eGW calendar. - * Depending on the value of $importMode, the conversion will generate either eGW - * events with completely new id s (DUPLICATE mode) or generate ids created after - * the VEVENT;UID field so that VEVENTS that refer to already existing eGW events - * will be used to update these (OVERWRITE mode). - * - * @section secimpumatch Uidmatching - * When $uid_matching is not set, the default situation, the uid field of each vevent - * to be imported will examined to check if it has a valid egw id encoded. If so the import - * will try to update the egw event indicated by this id with the contents of the vevent. - * When this doesnot succeed an appropiate error or skip (if you had not enough write rights) - * will be the result. If there can be no valid egw id be decoded, the vevent will be considered - * as a new one and an hence a new egw id will automatically be produced. - * - * When $uid_matching is enabled, the value of the uid field of the vevent will matched against - * all the uid fields of existing egw events. If a matching egw event with id is found, - * the import - * routine will try to update this event. If no success an appropiate error will be generated. - * If no match is found, the import proceeds, just as without uidmatching, by generating a - * new egw event with a new id. The events uid field will be filled with the vevents uid, - * for possible later re-use. - * - * @note Mostly it is best to disable uidmatching. It prevents that multiple duplicates - * of a event will be created in Egw, that may not be accessible anymore via the Ical-Service - * interface. Only use it when you really need to reimport an already once imported calendar - * because you accidentally deleted parts of it in Egw. Better still would be copy these lost - * events into a downloaded version of your original calendar and then update this one without - * the uid_matching enabled. (It has namely no effect for new events and the old (i.e. - * already downloaded to the client) events will be recognized without uidmatching. - * - * @param Horde_iCalendar &$hIcal object with ical VEVENT objects - * @param string $importMode toggle for duplicate (ICAL_IMODE_DUPLICATE) - * or overwrite (ICAL_IMODE_OVERWRITE) import mode - * @param int $cal_id strange parameter, at least for -1 create new events - * and if 0 then always add user to participants - * JVL: THIS NEEDS TO BE CLARIFIED! - * @param boolean $reimport_missing_events enable the import of previously exported events - * that are now gone in egw (probably deleted by someone else) Default false. - * @return boolean| int $false|$evcnt on error: false | on success: nof imported elms - * @ref $supportedFields determins the VEVENTS that will be used for import - */ - function importVEventsFromIcal(&$hIcal, $importMode='OVERWRITE', $cal_id=0, - $reimport_missing_events=false) - { - $overwritemode = stristr($importMode,'overwrite') ? true : false; - $evokcnt = 0; // nof events imported ok - $everrcnt = 0; // nof events imported erroneous - $evskipcnt = 0; // nof events imported skipped (user !== owner) - $evdelcnt = 0; // nof events deleted ok - $evmisskipcnt =0; // nof missing event updates skipped - - $veImportFields =& $this->supportedFields; - -// error_log('veImportFields::'. print_r($veImportFields,true)); - - $eidOk = false; // returning false, if file contains no components - $user_id = $GLOBALS['egw_info']['user']['account_id']; - - foreach($hIcal->getComponents() as $vevent) { - // HANDLE ONLY VEVENTS HERE - if(!is_a($vevent, 'Horde_iCalendar_vevent')) - continue; - -// $event = array('participants' => array()); - $event = array('title' => 'Untitled'); - $alarms = array(); - unset($owner_id); - $evduration = false; - $nonegw_participants = array(); - - // handle UID field always first according to uid_matching algorithm - $cur_eid = false; // current egw event id - $cur_owner_id = false; // current egw event owner id - $cur_event = false; // and the whole array of possibly correspond egw event - // import action description (just for fun and debug) : - // NEW|NEW-NONUID|NEW-FOR-MISSING - // DEL-MISSING|DEL-READ|DEL-READ-UID| - // UPD-MISSING|UPD-READ|UPD-READ-UID - $imp_action = 'NEW-NONUID'; - - if($uidval = $vevent->getAttribute('UID')){ - // ad hoc hack: egw hates slashes in a uid so we replace these anyhow with - - $vuid = strtr($uidval,'/','-'); - $event['uid'] = $vuid; - - if(!$this->uid_matching){ - - // UID_MATCHING DISABLED, try to decode cur_eid from uid - if ($cur_eid = $this->mke_guid2id($vuid,'calendar')){ - // yes a request to import a previously exported event! - if ($cur_event = $this->mycal->read($cur_eid)){ - // oke we can read the old event - $cur_owner_id = $cur_event['owner']; - $imp_action = 'UPD-READ'; - $event['id'] = $cur_eid; - } elseif($reimport_missing_events){ - // else: a pity couldnot read the corresponding cur_event, - // maybe it was deleted in egw already.. - $imp_action = 'UPD-MISSING'; - unset($event['id']); // import as a new one - } else{ - // go on with next vevent - $evmisskipcnt += 1; - continue; - } - }else{ - // no decodable egw id there, so per definition no corresponding egw event - // so will just import the vevent as a new event - $imp_action = 'NEW'; - } - - //UID_MATCHING ENABLED - } elseif($overwritemode && $cal_id <= 0 && !empty($vuid)){ - // go do uidmatching, search for a egw event with the vuid as uid field - if ($cur_event = $this->mycal->read($vuid)) { - $cur_eid = $uidmatch_event['id']; - $cur_owner_id = $uidmatch_event['owner']; - $imp_action = 'UPD-READ-UID'; - $event['id'] = $cur_eid; - }else{ - // uidmatch failed, insert as new - $imp_action = 'NEW'; - } - } - - } - - // lets see what other supported veImportFields we can get from the vevent - foreach($vevent->_attributes as $attr) { - $attrval = $GLOBALS['egw']->translation->convert($attr['value'],'UTF-8'); - - - // SKIP UNSUPPORTED VEVENT FIELDS - if(!in_array($attr['name'],$veImportFields)) - continue; - -// error_log('cnv field:' . $attr['name'] . ' val:' . $attrval); - - switch($attr['name']) { - // oke again these strange ALARM properties... - case 'AALARM': - case 'DALARM': - if (preg_match('/.*Z$/',$attrval,$matches)) { - $alarmTime = $hIcal->_parseDateTime($attrval); - $alarms[$alarmTime] = array('time' => $alarmTime); - } - break; - - case 'CLASS': - $event['public'] = (int)(strtolower($attrval) == 'public'); - break; - - case 'DESCRIPTION': - $event['description'] = $attrval; - break; - - case 'DTEND': - // will be reviewed after all fields are collected - $event['end'] = $attrval; - break; - - // note: DURATION and DTEND are mutually exclusive - case 'DURATION': - // duration after eventstart in secs - $evduration = $attrval; - break; - - case 'DTSTART': - // will be reviewed after all fields are collected - $event['start'] = $attrval; - break; - - case 'LOCATION': - $event['location'] = $attrval; - break; - - case 'RRULE': - // we may need to find a startdate first so delegate to later - // by putting it in event['RECUR'] - $event['RECUR'] = $attrval; - break; - case 'EXDATE': - if (($exdays = $this->mke_EXDATEpv2udays($attr['params'], $attrval)) - !== false ){ - foreach ($exdays as $day){ - $event['recur_exception'][] = $day; - } - } - break; - - case 'SUMMARY': - $event['title'] = $attrval; - break; - - case 'TRANSP': - $event['non_blocking'] = $attrval == 'TRANSPARENT'; - break; - // JVL: rewrite! - case 'PRIORITY': - $event['priority'] = $this->mke_prio($attrval); - break; - - case 'CATEGORIES': - $catnames = explode(',',$attrval); - $catidcstr = $this->cats_names2idscstr($catnames,$user_id,'calendar'); - $event['category'] .= (!empty($event['category'])) - ? ',' . $catidcstr : $catidcstr; - break; - - // when we encounter an new valid cal_address but not yet in egw db - // should we import it? - case 'ATTENDEE': - if ($pid = $this->mke_CAL_ADDRESS2pid($attrval)){ - if( $epartstat = $this->mke_params2partstat($attr['params'])){ - $event['participants'][$pid] = $epartstat; - } elseif ($pid == $event['owner']){ - $event['participants'][$pid] = 'A'; - } else { - $event['participants'][$pid] = 'U'; - } - // egw unknown participant, add to nonegw_participants list - } else { - $nonegw_participants[] = - $this->mke_ATTENDEE2cneml($attrval,$attr['params']); - } - break; - - // make organizer into a accepting participant - case 'ORGANIZER': // make him - if ($pid = $this->mke_CAL_ADDRESS2pid($attrval)) - $event['participants'][$pid] = 'A'; - //$event['owner'] = $pid; - break; - - case 'CREATED': // will be written direct to the event - if ($event['modified']) break; - // fall through - - case 'LAST-MODIFIED': // will be written direct to the event - $event['modified'] = $attrval; - break; - - case 'STATUS': // note: custom field in event - $event['status'] = strtoupper($attrval); - break; - - default: - error_log('VEVENT field:' .$attr['name'] .':' - . $attrval . 'HAS NO CONVERSION YET'); - } - } // end of fields loop - - // now all fields are gathered do some checking and combinations - - // we may have a RECUR value set? Then convert to egw recur def - if ($recurval = $event['RECUR']){ -//error_log('recurval=' . $recurval . '='); - if(!($recur = $this->mke_RECUR2rar($recurval,$event['start'])) == false){ - foreach($recur as $rf => $rfval){ - $event[$rf] = $rfval; - } - } - unset($event['RECUR']); - } - - // build endtime from duration if dtend was not set - if (!isset($event['end']) && ($evduration !== false)){ - $event['end'] = $this->mke_DDT2utime($event['start']) + $evduration; - } - - // a trick for whole day handling or ...?? - if(date('H:i:s',$event['end']) == '00:00:00') - $event['end']--; - - // check vevent for subcomponents (VALARM only at the moment) - // maybe some day do it recursively... (would be better..) - foreach($vevent->getComponents() as $valarm) { - // SKIP anything but a VALARM - if(!is_a($valarm, 'Horde_iCalendar_valarm')) - continue; - $this->upde_c_VALARM2alarms($alarms,$valarm,$user_id,$veImportFields); - } - - // AD HOC solution: add nonegw participants to the description - // should be controlable by class member switch - if (count($nonegw_participants) > 0) - $this->upde_nonegwParticipants2description($event['description'], - $nonegw_participants); - - // handle fixed id call (for boical compatibility) - // @todo test boical compatibility (esp. with $cal_id>0 case) - if($cal_id > 0) { - $event['id'] = $cal_id; - } - - // SORRY THE PARTICPANTS HANDLING OF EGW IS NOT YET CLEAR TO ME (JVL) - // so I do the bold solution to add ourself to participants list if we are not on yet - if(!isset($event['participants'][$user_id])) - $event['participants'][$user_id] = 'A'; - - // error_log('<< ok <<<<' . 'event read for import=' . print_r($event,true)); - - - // -- finally we come to the import into egw --- - - if (($event['title'] == 'X-DELETE') || ($event['title'] == '_DELETED_')){ - - - // -------- DELETION -------------------- - // error_log('delete event=' . print_r($event,true)); - $imp_action = 'DEL-' . $imp_action; - if(! $cur_eid) { - $this->_errorlog_evupd('ERROR: ' . $imp_action, - $user_id, $event, false); - $everrcnt += 1; - continue; - } else { - // event to delete is found readable - if($eidOk = $this->mycal->delete($cur_eid)){ - // DELETE OK - $evdelcnt += 1; - - // ASSUME Alarms are deleted by egw on delete of the event... - // otherwise we should use this code: - // delete the old alarms - //foreach($cur_event['alarm'] as $alarmID => $alarmData) { - // $this->delete_alarm($alarmID); - //} - continue; - } elseif ($user_id != $cur_owner_id){ - // DELETE BAD but it wasnt ours anyway so skip it - if ($this->evdebug) - $this->_errorlog_evupd('SKIPPED: ' . $imp_action . ' (INSUFFICIENT RIGHTS)', - $user_id, $event, $cur_event); - $evskipcnt += 1; - continue; - } else { - // DELETE BAD and it was ours - $this->_errorlog_evupd('ERROR: ' . $imp_action . '(** INTERNAL ERROR ? **)', - $user_id, $event, $cur_event); - $everrcnt += 1; - continue; - } - - } - - // -------- UPDATE -------------------- - } elseif ($eidOk = $this->mycal->update($event, TRUE)){ - // UPDATE OKE ,now update alarms - $evokcnt += 1; // nof imported ok vevents - // handle the found alarms - if(in_array('VALARM',$veImportFields)){ - // delete the old alarms for the event, note: we could also have used $cur_event - // but jus to be sure - if(!$updatedEvent = $this->mycal->read($eidOk)){ - error_log('ERROR reading event for Alarm update, will skip update..'); - continue; - } - - // ******** for serious debugging only.. ************** - // if ($this->evdebug){ - // $this->_errorlog_evupd('OK: ' . $imp_action, - // $user_id, $event, $cur_event); - //error_log('event readback dump:' . print_r($updatedEvent,true)); - // } - // ******** eof serious debugging only.. ************** - - foreach($updatedEvent['alarm'] as $alarmID => $alarmData) { - $this->delete_alarm($alarmID); - } - // set new alarms - foreach($alarms as $alarm) { - if(!isset($alarm['offset'])){ - $alarm['offset'] = $event['start'] - $alarm['time']; - } elseif (!isset($alarm['time'])){ - $alarm['time'] = $event['start'] - $alarm['offset']; - } - $alarm['owner'] = $user_id; -// error_log('setting egw alarm as:' . print_r($alarm,true)); - $this->save_alarm($eidOk, $alarm); - } - } - continue; - - // ---UPDATE BAD -------- - } elseif ($user_id != $cur_owner_id){ - // UPDATE BAD, but other ones event, so skip - if ($this->evdebug) - $this->_errorlog_evupd('SKIPPED: ' . $imp_action . ' (INSUFFICIENT RIGHTS)', - $user_id, $event, $cur_event); - $evskipcnt += 1; - continue; - } else { - // UPDATE BAD and we own it or it was a new one - $this->_errorlog_evupd('ERROR: ' . $imp_action . '(** INTERNAL ERROR ? **)', - $user_id, $event, $cur_event); - $everrcnt += 1; - continue; - } - error_log('CODING ERROR: SHOULDNOT GET HERE'); - } // for each - - if (($everrcnt > 0) || $this->evdebug) - error_log('** user[' . $user_id . '] vevents imports: ' . $everrcnt . ' BAD,' . - $evskipcnt . ' skip-(insufficient rights), ' . $evmisskipcnt . - ' skip-(ignore reimport missings), ' . - $evokcnt . ' upd-ok, ' . $evdelcnt . ' del-ok'); - return ($everrcnt > 0) ? false : $evokcnt+ $evdelcnt; - } - - - /** - * @private - * Log event update problems to http errorlog - * @param string $fault description of the fault type - * @param ind $user_id the id of the logged in user - * @param array $new_event the info converted from the vevent to be imported - * @param array|false $cur_event_ids settings of owner, id and uid field of a possibly found - * corresponding egw event. When no such event found: false. - */ - function _errorlog_evupd($fault='ERROR', $user_id, &$new_event, $cur_event) - { - // ex output: - // ** bovevents import for user(12 [pietje]): ERROR - // current egw event: id=24, owner=34, uid='adaafa'\n - // vevent info event: id=24, owner=--, uid='dfafasdf'\n - - $uname =(is_numeric($user_id)) - ? $user_id . '[' . $GLOBALS['egw']->accounts->id2name($user_id) . ']' - : '--'; - if ($cur_event === false){ - $cid = $cown = $cuid = '--'; - }else{ - $cid = $cur_event['id']; - $cown = $cur_event['owner']; - $cuid = $cur_event['uid']; - } - $nid = ($vi = $new_event['id']) ? $vi : '--'; - $nown = ($vi = $new_event['owner']) ? $vi : '--'; - $nuid = ($vi = $new_event['uid']) ? $vi : '--'; - - error_log('** bovevents import for user (' . $cur_eid . - '['. $uname . ']):' . $fault . '\n' . - 'current egw event: id=' . $cid . ',owner=' . $cown . ',uid=' . $cuid .'\n' . - 'vevent info event: id=' . $nid . ',owner=' . $nown . ',uid=' . $nuid .'\n' ); -// error_log('vevent info event dump:' . print_r($new_event,true) . '\n <<-----------<<\n'); - } - - - /** - * @private - * - * Fill member var that holds the iCalendar property to Egw fields mapping. - * - * Copy keys from this var to the supportedFields member var to allow import/export - * of the field refered to by the key. - * @todo Maybe someday rethink the ical2egwFields trafo system by rewriting it in paths - * starting from iCalendar/Component=>Field or iCalendar/Comp/SubComp etc. - * @see $ical2egwFields member var that holds the mapping - */ - function _set_ical2egwFields() - { - $this->ical2egwFields = - array( - 'UID' => array('uid'), - 'CLASS' => array('public'), - 'SUMMARY' => array('title'), - 'DESCRIPTION' => array('description'), - 'LOCATION' => array('location'), - 'DTSTART' => array('start'), - 'DTEND' => array('end'), - 'DURATION' => array('end-duration'), - 'ORGANIZER' => array('owner'), - 'ATTENDEE' => array('participants'), - 'RRULE' => array('recur_type','recur_interval','recur_data','recur_enddate'), - 'EXDATE' => array('recur_exception'), - 'PRIORITY' => array('priority'), - 'TRANSP' => array('non_blocking'), - 'CATEGORIES'=> array('category'), - 'URL' => array(''), - 'CONTACT' => array(''), - 'GEO' => array(''), - 'CREATED' => array(''), - 'AALARM' => array('alarms'), // NON RFC2445!! - 'DALARM' => array('alarms'), // NON RFC2445!! - 'VALARM' => array('alarms'), - 'VALARM/TRIGGER' => array('alarms/time') - ); - return true; - } - - - /** - * Set the list of ical fields that are supported during the next imports and exports. - * - * The list of iCal fields that should be converted during the following imports and exports - * of VEVENTS is set. This is done by providing a productmanufacturer name and - * (optionally) a prductname. In a small lookup table the set of currently supported - * fields for this is searched and then set thus in the class member @ref $supportedFields. - * - * @note JVL: I can only see sense in defining supported fields in iCal fields as - * these are the fields (terminology) that the devices have in common. - * in addressbook this approach is also --correctly-- taken. Why not here? - * @param string $_productManufacturer a string indicating the device manufacturer - * @param string $_productName a further specification of the current device that is used - * for import or export. - */ - function setSupportedFields($_productManufacturer='file', $_productName='') - { - $defaultFields = array('CLASS','SUMMARY','DESCRIPTION','LOCATION','DTSTART', - 'DTEND','RRULE','EXDATE','PRIORITY'); - // not: 'TRANSP','ATTENDEE','ORGANIZER','CATEGORIES','URL','CONTACT' - - switch(strtolower($_productManufacturer)) { - case 'nexthaus corporation': - switch(strtolower($_productName)){ - default: - // participants disabled until working correctly - // $this->supportedFields = array_merge($defaultFields,array('ATTENDEE')); - $this->supportedFields = $defaultFields; - break; - } - break; - - // multisync does not provide anymore information then the manufacturer - // we suppose multisync with evolution - case 'the multisync project': - switch(strtolower($_productName)) { - case 'd750i': - default: - $this->supportedFields = $defaultFields; - break; - } - break; - case 'sonyericsson': - switch(strtolower($_productName)){ - default: - $this->supportedFields = $defaultFields; - break; - } - break; - - case 'synthesis ag': - switch(strtolower($_productName)){ - default: - $this->supportedFields = $defaultFields; - break; - } - break; - // used outside of SyncML, eg. by the calendar itself ==> all possible fields - case 'file': - case 'all': - $this->supportedFields = - array_merge($defaultFields, - array('ATTENDEE','ORGANIZER','TRANSP','CATEGORIES', - 'DURATION','VALARM','VALARM/TRIGGER')); -// error_log('OKE setsupportedFields (all)to:'. print_r($this->supportedFields,true)); - break; - - // the fallback for SyncML - default: - error_log("Client not found: $_productManufacturer $_productName"); - $this->supportedFields = $defaultFields; - break; - } - } - - - /** - * - * Exports calendar events as an iCalendar string - * - * @note -- PART OF calendar.boical API COMPATIBILITY INTERFACE ----------- - * @param int/array $events (array of) cal_id or array of the events - * @param string $method='PUBLISH' - * @return string|boolean string with vCal or false on error - * (eg. no permission to read the event) - * - * @see _hiCal class member to hold a temporary Horde_iCalendar object - */ - function &exportVCal($events,$version='1.0',$method='PUBLISH') - { - $hIcal = &new Horde_iCalendar; - $euid_export = false; - - // set some header values of the Horde_iCalendar object - $hIcal->setAttribute('PRODID', '-//eGroupWare//NONSGML eGroupWare Calendar ' - . $GLOBALS['egw_info']['apps']['calendar']['version'].'//' - . strtoupper($GLOBALS['egw_info']['user']['preferences']['common']['lang'])); - $hIcal->setAttribute('VERSION',$version); - $hIcal->setAttribute('METHOD',$method); - - // convert the eGW events to VEVENTS and add them to hIcal - if(!$this->exportEventsOntoIcal($hIcal, $events,$euid_export)) - return false; - - // conversion oke, now let Horde stringify it and deliver as result - $vcal = $hIcal->exportvCalendar(); - // JVL: destroy the object by hand or does automagic this in php ? - $hIcal = null; - - return $vcal; - - } - - - - /** - * Convert VEVENT components from an iCalendar string into eGW calendar events - * and write these to the eGW calendar as new events or changes of existing events - * - * @note -- PART OF calendar.boical API COMPATIBILITY INTERFACE ----------- - * @param string $_vcalData ical data string to be imported - * @param int $cal_id id of the eGW event to fill with the VEvent data - * when -1 import the VEvent content to new EGW events - * (JVL HACK when 0 allow change but no deletion user is added to participants - * if needed) - * @return boolean $ok false on failure | true on success - */ - function importVCal($_vcalData, $cal_id=-1) - { - - $hIcal = &new Horde_iCalendar; - // our (patched) horde classes, do NOT unfold folded lines, - // which causes a lot trouble in the import, so we do it here - $_vcalData = preg_replace("/[\r\n]+ /",'',$_vcalData); - - // let the Horde_iCalendar object parse the Vcal string into its components - if(!$hIcal->parsevCalendar($_vcalData)){ - return FALSE; - } - $importMode = 'OVERWRITE'; - - // now import the found VEVENTS into eGW calendar - if(!$this->importVEventsFromIcal($hIcal, $importMode, $cal_id)) - { - //error_log('importVCal(): errors in importVEventsFromIcal'); - $hIcal = null; - return false; - } - - $hIcal = null; - return true; - } - - - } - - -?> diff --git a/egwical/inc/class.boical.inc.compat.php b/egwical/inc/class.boical.inc.compat.php deleted file mode 100644 index 71d1681c3c..0000000000 --- a/egwical/inc/class.boical.inc.compat.php +++ /dev/null @@ -1,69 +0,0 @@ -ei =& CreateObject('egwical.egwical'); - $this->wkobj =& $this->ei->addRsc($this); - // alternatively the fast, shortcut, road for knowingly experts only: - //$this->wkobj =& CreateObject('egwical.bocalupdate_vevents'); - //$this->wkobj->setRsc($this); - - if ($this->wkobj == false){ - error_log('boical constructor: couldnot add boical resource to egwical: FATAL'); - return false; - } - } - - - // now implement the compatibility methods, that are all moved to egwical! - - function &exportVCal($events,$version='1.0',$method='PUBLISH') - { - return $this->wkobj->exportVCal($events,$version,$method); - } - - function importVCal($_vcalData, $cal_id=-1) - { - return $this->wkobj->importVCal($_vcalData, $cal_id); - } - - - function setSupportedFields($_productManufacturer='file', $_productName='') - { - return $this->wkobj->setSupportedFields($_productManufacturer, $_productName); - } - - } -?> diff --git a/egwical/inc/class.boinfolog_vtodos.inc.php b/egwical/inc/class.boinfolog_vtodos.inc.php deleted file mode 100644 index d3ad5a9a98..0000000000 --- a/egwical/inc/class.boinfolog_vtodos.inc.php +++ /dev/null @@ -1,561 +0,0 @@ - * - * -------------------------------------------- * - * This program is free software; you can redistribute it and/or modify it * - * under the terms of the GNU General Public License as published by the * - * Free Software Foundation; either version 2 of the License. * - **************************************************************************/ - - /* JVL Todo V0.7: - * - add structure and API terminology from class.bovevents.inc.php:DONE - * - rewrite all vevent to vtodo strings: DONE.. - * - Maybe add a supportFields system as done in calendar.bovevents, to allow for - * handling vtodos for various devices - * - if done document the supportFields method and show how it can be used - * - find out how to do deletion based on imported VTODOS ? Can that be done? - * - check the usage and conversions of user time and server times - * - add compatibility API for the class infolog.vcalinfolog: DONE but UNTESTED - * - add ORGANIZER export: DONE (V0.51) removed (dont know map field) - * - add ORGANIZER import: ... maybe map t info_responsible - * - add CATEGORIES export: DONE (V0.52) - * - add CATEGORIE import: DONE (V0.7.01) - * - add "subtask" export: DONE (v0.52) - * - add "subtask" import: PARTLY - * - rewrite PRIORITY export: DONE (V0.52) - * - rewrite PRIORITY import:DONE (V0.7.01) - * - repair datecreated: DONT know map field - * - repair date modified export: PARTLY done - * - repair startdate or enddate without time details: DONE (V0.7.02) - */ - - - // require_once EGW_SERVER_ROOT.'/infolog/inc/class.boinfolog.inc.php'; - require_once EGW_SERVER_ROOT.'/phpgwapi/inc/horde/Horde/iCalendar.php'; -// require_once EGW_SERVER_ROOT.'/icalsrv/inc/class.egwical.inc.php'; - - /** - * - * iCal vtodos import and export via Horde iCalendar classes - * @note the routines in this package should be used OO only so that de constructor - * can initialize the data common to the import and export routines - * @note this package provides compatibilty routines for class infolog.vcalinfolog - * this can e.g. be used by making infolog.vcalinfolog a simple extension of - * infolog.bovtodos - * - * @todo move the compatibility functions for vcalinfolog completely to the compat class. - * There is no need to have them here anymore. - * @todo rewrite bovtodos to use a ical2egw and supportedFields system - * @todo IMPORTANT rewrite bovtodos to handle uid_matching analogous to bovevents - * - * @package egwical - * @author Jan van Lieshout This version. - * @author Lars Kneschke (parts of reused code) - * @author Ralf Becker (parts of reused code) - * @version 0.9.02 First for use with new WURH egwical class - * @license http://opensource.org/licenses/gpl-license.php GPL - - * GNU General Public License - */ - - class boinfolog_vtodos extends egwical - { - - /** - * @var object - * The egw infolog object that will be used to transport events from and to - * This is set by setRsc() - */ - var $myinf = null; - - - /** - * Describe the provided work capabilities of the class. - * @return string The description as entries for the @ref $reg_workers registry - * table. - */ - function provides_work() - { - return - array('boinfolog' => array('workerclass' => 'boinfolog_vtodos', - 'workerobj' => $null, - 'icalsup' => array('VTODO')), - 'vcalinfolog' => array('workerclass' => 'boinfolog_vtodos', - 'workerobj' => $null, - 'icalsup' => array('VTODO')) - ); - - } - - - /* - * Our Constructor, fills the basic class members - * and set the description of our worker capabilities. - */ - function bovtodos() { - - // call superclass constructor by hand - boinfolog::boinfolog(); - - $this->TASKMAGIC = $GLOBALS['egw_info']['server']['install_id'] - ? $GLOBALS['egw_info']['server']['install_id'] - : 'local'; - - // $this->setSupportedFields(); //not implemented yet - return true; - } - - - /** - * Set the egw resource that this worker will handle. - * This worker is only capable of handling boinfolog objects, so it should - * be of that class. This method is mostly called indirectly from a egwical compound - * addRsc() call. But you can call it also directly (if you know what your doing ..) - * @return boolean false on error, true else - */ - function setRsc($egw_rsc) - { - if(!is_a($egw_rsc,'boinfolog')) - return false; - $this->myinf = $egw_rsc; - return true; - } - - - // --- conversion and import code -- - - /** - * @private - * @var $TASKMAGIC - * Magic unique number used for de/encoding our uids. - * - * This string that contains global unique magic number that is - * unique for our current database installed etc. It is used to recognize - * earlier exported VTODO or VEVENT UID fields as referring to their eGW counterparts. - */ - var $TASKMAGIC='dummy'; - - - - - // Some helper functions first - - - /** - * generate a unique id, with the todo id encoded into it, which can be - * used for later synchronisation. - * - * @param $todo_id string|int eGW id of the content - * @use $TASKMAGIC string that holds our unique ID - * @return false|string on error: false - * on success the global unique id - */ - function _id2guid($todo_id) - { - if (empty($todo_id)) - return false; - - return 'infolog_task'.'-'.$todo_id.'-'. $this->TASKMAGIC; - } - - - - /** - * get the local content id from a global UID - * - * @param string $globalUid the global UID - * @return false|int on error: false - * on success: local egw todo id - */ - function _guid2id($VTodoUID) - { - // error_log('_guid2id: trying to recover id from' . $VTodoUID); - if (!preg_match('/^infolog_task-(\d+)-' . - $this->TASKMAGIC . '$/',$VTodoUID,$matches)) - return false; - - // error_log("_guid2id: found (" . $matches[1] . ")"); - return $matches[1]; - } - - - - /** - * export the eGW todos in $todos to iCalendar VTODOS and add these to - * the Horde_iCalendar object &$hIcal - * Note: that because eGW does not store uid fields for tasks in its db we - * are in general not able to recoginize VTODOS by their uid-field. - * Because of this it is only possible to have a VTODO overwrite an internal - * eGW todo (task) when this VTODO was in an earlier fase build as export of an - * internal eGW todo. In other words to later on change your imported VTODO, - * you first have export it and in the client make your changes on this exemplar. - * - * @param &$hIcal Horde_iCalendar object to wich the produced VTodos are added - * @param $todos array with either id s (tids) for a eGW todoData structs - * or an array of such todoData structs, that will be exported - * @param boolean $euid_export if true export the uid field (Note: Currently not available!) - * else generate a uid from with the task id encoded (Default setting) - * @return $ok/$vcnt boolean/int on error: false / on success: nof vtodos exported - * @use members supportedFields(), _id2guid() - */ - function exportTodosOntoIcal(&$hIcal, $todos, $euid_export=false) - { - //NOTE: $euid_export has currently no effect -# error_log("ical_export_add_Todos here, for " . count($todos) . "todos"); - - $todo = array(); // container for each todo to be exported - $tid = null; // id of the todo to be exported - $vexpcnt =0; // number of vtodos exported -# $options = array('CHARSET' => 'UTF-8','ENCODING' => 'QUOTED-PRINTABLE'); - - - if (!is_array($todos)) $todos = array($todos); - - foreach($todos as $todo) { - // some hocuspocus to handle the polymorphy of the $todos arg - if (!is_array($todo) - && !($todo = $this->myinf->read($todo))){ - - return false; // no permission to read $tid - } - $tid = $todo['info_id']; - // oke, now sure $todo is a todoData array and $tid its info_id field.. - //_debug_array($todo); - - $todo = $GLOBALS['egw']->translation-> - convert($todo,$GLOBALS['egw']->translation->charset(),'UTF-8'); - -# error_log('todo to export=' . print_r($todo,true)); - - //someday: $this->newComponent() ??? - $vtodo = Horde_iCalendar::newComponent('VTODO',$hIcal); - - $vGUID = $this->_id2guid($tid); - - // if (!$euid_export) - // append Non Recoverable so _guid2id() wont recognize it later - // $vGUID .= 'NR'; - $vtodo->setAttribute('UID',$vGUID); - // for subtasks set the parent - // egw2vtodo: info_id_parent => pid -> RELATED-TO:parent_uid - if ($parid = $todo['info_id_parent']) - $vtodo->setAttribute('RELATED-TO', $this->_id2guid($parid)); - - $vtodo->setAttribute('SUMMARY', $todo['info_subject']); - $vtodo->setParameter('SUMMARY', $options); - $vtodo->setAttribute('DESCRIPTION', $todo['info_des']); - $vtodo->setParameter('DESCRIPTION', $options); - if($todo['info_startdate']) - $vtodo->setAttribute('DTSTART', $todo['info_startdate']); - if($todo['info_enddate']) - $vtodo->setAttribute('DUE', $todo['info_enddate']); - $vtodo->setAttribute('DTSTAMP',time()); - - $lastmodDate = $todo['info_datemodified']; - $vtodo->setAttribute('LAST-MODIFIED', $lastmodDate ); - - if ($createDate = $this->get_TSdbAdd($tid,'infolog')){ - $vtodo->setAttribute( 'CREATED', $createDate); - } else { - $vtodo->setAttribute( 'CREATED', $lastmodDate); - } - - // egw2VTOD: owner -> ORGANIZER field - if ($tfrom_id = $todo['info_owner']){ - $mailtoOrganizer = $GLOBALS['egw']->accounts->id2name($tfrom_id,'account_email'); - $vtodo->setAttribute('ORGANIZER', $this->mki_v_CAL_ADDRESS($tfrom_id)); - $vtodo->setParameter('ORGANIZER', $this->mki_p_CN($tfrom_id)); - } - - $vtodo->setAttribute('CLASS', - ($todo['info_access'] == 'public')?'PUBLIC':'PRIVATE'); - // CATEGORIES, value= all category names from info_cat field comma-separated list - // n.b. dont mind catid ==0 (this is none categorie, I think) - if ($catids = $todo['info_cat']){ - $catnamescstr = $this->cats_ids2idnamescstr(explode(',',$catids)); - $vtodo->setAttribute('CATEGORIES',$catnamescstr); - } - - - // egw2vtodo status trafo: - // done -> COMPLETE:lastmoddate, PERCENT-COMPLETE:100, STATUS:COMPLETED - // ongoing -> STATUS: IN-PROCESS - // offer -> STATUS: NEEDS-ACTION, PERCENT-COMPLETE:0 - switch ($todo['info_status']){ - case 'done': - $vtodo->setAttribute('COMPLETED',$lastmodDate); // for ko35, lastmod? - $vtodo->setAttribute('PERCENT-COMPLETE','100'); - $vtodo->setAttribute('STATUS','COMPLETED'); - break; - case 'ongoing': - $vtodo->setAttribute('STATUS','IN-PROCESS'); - break; - case 'offer': - $vtodo->setAttribute('STATUS','NEEDS-ACTION'); -# $vtodo->setAttribute('PERCENT-COMPLETE',"0"); - break; - default: - // check for percentages - if (ereg('([0-9]+)%',$todo['info_status'],$matches)){ - $vtodo->setAttribute('PERCENT-COMPLETE',$matches[1]); - $vtodo->setAttribute('STATUS','IN-PROCESS'); - }else{ - $vtodo->setAttribute('STATUS','NEEDS-ACTION'); - } - } - - if (is_numeric($eprio = $todo['info_priority']) && ($eprio >0) ) - $vtodo->setAttribute('PRIORITY', - $this->mki_v_prio($eprio) ); - -# $vtodo->setAttribute('TRANSP','OPAQUE'); - - $hIcal->addComponent($vtodo); - $vexpcnt += 1; - } - - return $vexpcnt; //return nof vtodos exported - } - - - - /* @note PART OF COMPATIBILITY API for INFOLOG.VCALINFOLOG - * @note UNTESTED - * Export a single eGW task as a VTODO string - * - * @param $_taskID int/string id of the eGW task to be exported - * @param $_version string version the produced iCalendar content should get - * @return false|string on error | content of the resulting VTODO iCal element - */ - function exportVTODO($_taskID, $_version) - { - $hIcal = &new Horde_iCalendar; - $hIcal->setAttribute('VERSION',$_version); - $hIcal->setAttribute('METHOD','PUBLISH'); - - if(! $tcnt = $this->exportTodosOntoIcal(&$hIcal, array($_taskID), true)) - return false; - - return $hIcal->exportvCalendar(); - } - - - - /** - * Convert the ical VTODOS components that are contained in de $hIcal Horde_iCalendar - * to eGW todos and import these into the eGW calendar. - * Depending on the value of $importMode, the conversion will generate either eGW - * todos with completely new id s (DUPLICATE mode) or try to recover an egw id from - * the VTODO;UID field (so called OVERWRITE mode). Note that because eGW currently - * does not store todo uid field info in its database, such recovering is only - * possible for previously exported todos. - * - * @param &$hIcal Horde_iCalendar object with ical VTODO objects - * @param $importMode string toggle for duplicate (ICAL_IMODE_DUPLICATE) - * or overwrite (ICAL_IMODE_OVERWRITE) import mode - * @return $false|$timpcnt on error: false | on success: nof imported elms - * @use .supportedFields() to steer the VTODOS to eGW todos conversion - * @use members _guid2id() - */ - function importVTodosFromIcal(&$hIcal, $importMode='DUPLICATE') - { - - $overwritemode = stristr($importMode,'overwrite') ? true : false; -# $ftid = $fixed_taskId; - $timpcnt = 0; // nof todos imported - $tidOk = true; // return true, if hIcal contains no vtodo components - - foreach($hIcal->getComponents() as $component) { - // ($ftid < 0) => recover id (overwritemode) or use no id - // ($ftid > 0) => use this value to set the id (compatibility mode) - - if(is_a($component, 'Horde_iCalendar_vtodo')){ - $tidOk = $this->_importVTodoIcalComponent(&$component, $overwritemode, -1); - if (!$tidOk){ - error_log('infolog.bovtodos.importVTodosFromIcal(): ' - . ' ERROR importing VTODO '); - break; // stop at first error - } - - - $timpcnt += 1; // nof imported ok vtodos - } - } - return (!$tidOk) ? false : $timpcnt; - } - - - /* convert a single vtodo horde icalendar component to a eGW todo and write it to - * the infolog system. - * - * @note this routine should better not be exported - * @param &$hIcalComponent Horde_iCalendar_vtodo element that contains the VTODO - * that is to be converted and imported - * @param $overwriteMode boolean generate a new eGW todo (when false) or allow - * overwrite of an existing one (when true) - * @param $newtask_id int/string if >0 : the id of the eGW todo that must be - * overwritten. if <0 : generation of new task or recover taskId from UID field - * @return false | int on error: false | on success: the id of the eGW todo - * that was produced/changed - */ - function _importVTodoIcalComponent(&$hIcalComponent, $overwriteMode, $newtask_id) - { - $ftid = $newtask_id; - $todo = array(); //container for eGW todo - $user_id = $this->owner; // we logged in? - - if(!is_a($hIcalComponent, 'Horde_iCalendar_vtodo')) - return false; - - if($ftid > 0) { - // just go for a change of the content of the eGW task with id=$ftid - $todo['info_id'] = $ftid; - // we will now ignore a UID field later in this VTodo - } - - // now process all the fields found - foreach($hIcalComponent->_attributes as $attributes) { -# error_log( $attributes['name'].' - '.$attributes['value']); - //$attributes['value'] = - // $GLOBALS['egw']->translation->convert($attributes['value'],'UTF-8'); - switch($attributes['name']){ - case 'UID': - if ($ftid > 0) // fixed id mode so we got id from $newtask_id - break; - $vguid = $attributes['value']; - if( $overwriteMode && $tid = $this->_guid2id($vguid)){ - // an old id was recovered from the UID field, we will use it - $todo['info_id'] = $tid; - #error_log('import: using existing id:'.$tid); - } // else we leave the info_id empty so automatically a new todo gets created - break; - // rfc s4.8.1.3.egw2vtodo: public|private|confidential - case 'CLASS': - $todo['info_access'] = strtolower($attributes['value']); - break; -# case 'ORGANIZER': -# $todo['info_from'] = $attributes['value']; -# may be put it in info_responsible field ? -# // full name + mailto see bovevents on a method to handle this - break; - - case 'DESCRIPTION': - $todo['info_des'] = $attributes['value']; - break; - case 'DUE': - $todo['info_enddate'] = $this->mke_DDT2utime($attributes['value']); - break; - case 'DTSTART': - $todo['info_startdate'] = $this->mke_DDT2utime($attributes['value']); - break; - case 'PRIORITY': - $todo['info_priority'] = $this->mke_prio($attributes['value']); - break; - // rfc s4.8.1.11 egw2vtodo status trafo: (now use it backwards) - // done -> COMPLETE:lastmoddate, PERCENT-COMPLETE:100, STATUS:COMPLETED - // ongoing -> STATUS: IN-PROCESS - // offer -> STATUS: NEEDS-ACTION, PERCENT-COMPLETE:0 - case 'STATUS': - switch (strtolower($attributes['value'])){ - case 'completed': - $todo['info_status'] = 'done'; - break; - case 'cancelled': - $todo['info_status'] = 'done'; - break; - case 'in-process': - $todo['info_status'] = 'ongoing'; - break; - default: - // probably == 'needs-action' - $todo['info_status'] = 'offer'; - } - break; - // date and time when completed - case 'COMPLETED': - $todo['info_status'] = 'done'; - break; - case 'PERCENT-COMPLETE': - $pcnt = (int) $attributes['value']; - if ($pcnt < 1) { - $todo['info_status'] = 'offer'; - }elseif($pcnt > 99) { - $todo['info_status'] = 'done'; - }else{ - $todo['info_status'] = $pcnt . '%'; // better should do rounded to 10s - } - break; - case 'SUMMARY': - $todo['info_subject'] = $attributes['value']; - break; - case 'RELATED-TO': - $todo['info_id_parent'] = $this->_guid2id($attributes['value']); - break; - // unfortunately infolog can handle only one cat atm - case 'CATEGORIES': - $catnames = explode(',',$attributes['value']); - $catids = $this->cats_names2idscstr($catnames,$user_id,'infolog'); - $todo['info_cat'] = $catids; - break; - - case 'LAST-MODIFIED': - $todo['info_datemodified'] = $attributes['value']; - break; - - default: -// error_log('VTODO field:' .$attributes['name'] .':' -// . $attributes['value'] . 'HAS NO CONVERSION YET'); - } - } - // error_log('todo=' . print_r($todo,true)); - - if($todo['info_subject'] == 'X-DELETE' && $tid){ - // delete the todo (secret HACK, donot use...) - return $this->myinf->delete($tid); - }else{ - $tidOk = $this->myinf->write($todo,true,false); - // error_log('ok import id:'. $tidOk .' VTODO UID:' . $vguid); - return $tidOk; - } - } - - - - - - /* @note PART OF COMPATIBILITY API for INFOLOG.VCALINFOLOG - * @note UNTESTED - * Import a single iCalendar VTODO string as eGW task(aka: todo) - * - * @param $_vcalData string content of an VTODO iCalender element - * @param $_taskID int/string id of the eGW task to be overwritten - * when < 0 a new task will get produced - * @return false | int on error: false | on success: the id of the eGW todo - * that was produced/changed - */ - function importVTODO(&$_vcalData, $_taskID=-1) - { - $hIcal = &new Horde_iCalendar; - if(!$hIcal->parsevCalendar($_vcalData)) - return FALSE; - - $components = $hIcal->getComponents(); - if(count($components) < 1) - return false; - - return $this->_importVTodoIcalComponent(&$components[0], - true, $_taskID); - } - - - - } - - -?> diff --git a/egwical/inc/class.egwical.inc.php b/egwical/inc/class.egwical.inc.php deleted file mode 100644 index 0bd5ee97a5..0000000000 --- a/egwical/inc/class.egwical.inc.php +++ /dev/null @@ -1,1278 +0,0 @@ - - *
  • mki_ - * This is for methods that MaKe a Ical thing like a component, field, fieldvalue or - * fieldparameter. Thus these are subdived in:
  • - *
      - *
    • mki_c to make ical Components like VEVENTS or VALARMS
    • - *
    • mki_v to make ical field Values like e.g. a ATTENDEE field value
    • - *
    • mki_vp to make both ical field Values and Parameters
    • - *
    - * - *
  • mke_ - * This is for methods that MaKe a Egw things like a field of egw event or task.
  • - *
  • updi_ - * This is for methods that UPDate an Ical component or field. Note that the Ical component - * to be updated will be passed by reference to these routines
  • - *
  • upde_ - * This is for methods that UPDate an Egw entity like an event or task or.... Note again - * that the Egw entity will be passed by reference to these routines.
  • - * - * - * @section secworkersubclasses Worker Subclasses - * Egwical is implemented following the WURH pattern (see @ref pageegwicalwurh). - * Currently there are two worker subclasses available: - * - bocalupdate_vevents to convert between egw calendar events and VEVENTS - * and allow import and export of these. When added as a resource to an Egwical object, - * the representative member for this subclass is set in the attribute $this->buverpr - * - * - boinfolog_vtodos to convert between egw infolog tasks events and VTODOS - * and allow import and export of these. When added as a resource to an Egwical object, - * the representative member for this subclass is set in the attribute $this->ivtrpr - * - * @note At this moment (V 0.9.01) there is still a little unpleasant piece of extra - * coding needed to get - * it working: when you develop a new workerssubclass you must enter it manually in - * the egwical constructor, - * so that it can later on automatically be found and matched to the appropiat egw resource. - * (I couldnot find an easy way to search for existing subclasses so therefore it is needed) - * - * @note in future this package may become a full wrapper around the Horde_iCalendar - * libraries. This way we can keep the relevant egw and ical objects alive between - * calls so that code could be made faster and less memory consuming.. - * - * @since 0.9.0 api is incompatible with lower versions - * @author Jan van Lieshout (This version) - * @author Lars Kneschke (original code of reused parts) - * @author Ralf Becker (original code of reused parts) - * - * - * @version 0.9.04 (First wurh pattern implementation, with RRULE count= impl.) - * @date 20060216 - * @license http://opensource.org/licenses/gpl-license.php GPL - - * GNU General Public License - */ - class egwical - { - - /** - * @var Horde_iCalendar - * Placeholder object used to access various Horde_iCalendar methods - * In here the constructor will create a Horde_iCalendar object that can be used - * by the various routines in the class - */ - var $hi; - - // ----------- first the implementation of the WURH pattern ------------ - - -// /** Description of the resource handling capacity this object provides -// * @var array -// * Decsription, in the form of an entry for the @ref $reg_rscworkers registry, -// * of the worker capabilities this object provides. -// * When an object of this (sub) class is instatiated and added to a egwical object as -// * a socalled worker representative, this capability description is copied into the -// * (compounds) reg_rscworkers registry. -// * @note in genuine worker subclasses this variable must be initialized -// * by the constructor. -// */ -// var $iprovide_work = null; - - - /** Registry for Resource Worker classes - * - * @var array - * The resource workers registry is an array that holds - * an entry for each type of resource classs with the appropiate worker class and - * the currently set worker (representative) instantiated object of that class. - * @note the (instantiated) worker representative object in the registry entry is - * firstly set when an appropiate worker subclass is actually instantiated during - * runtime. (This setting then is done by the constructor of the worker class of course. - * that uses the info from the workerclass its variable @ref $iprovide_rscwork) - * - * Structure of the registry: - *
    -	   *  $reg_rscworkers = array($rsclass_name =>
    -	   *                          array('workerclass' =>$workerclass_name,
    -	   *                                'workerobj'   => $worker_obj,
    -	   *                                'vcsup'     =>array($velmc1,$velmc2,..)),
    -	   *                           ..)
    -	   *
    - * example of an entry: - *
    -	   *  $reg_rscworkers['boinfolog'] = array('workerclass' =>'boinfolog_vtodos',
    -	   *                                       'workerobj'   => null,
    -	   *                                       'icalsup'     =>array('VTODO'))
    -	   * 
    - */ - var $reg_rscworkers = array(); - - - /** Registry for Resources - * - * @var array - * - * The resources registry is an array that holds an entry for - * types of icalendar component class ('VEVENT, VTODO etc.) - * with: - *- 1) an appropiate egw resource object for storing and - * retrieving the info for these components (thus a calendar- or - * infolog- or .. etc. object) and - *- 2) an (instantiated) worker object to handle transport from - * and to the resource. - * The entries of this registry get filled when the - * resources are added to the egwical object by calls to the - * addRsc() method. - * @note multiple entries for the same icalendar component are allowed. - * This can occur when multiple resources can provide e.g. VEVENT data. - * - * Structure of the registry: - *
    -	   *   reg_rscs = array($icalcompclass_name => array($rsc_obj, $worker_obj),..)
    -	   *
    - * example of an entry: - *
    -	   *  reg_rscs['VTODO'] = array(null, null)
    -	   * 
    - */ - var $reg_rscs = array(); - - - - /** - * Constructor, init the auxiliary object @ref $hi and @ref $TASKMAGIC - * and instantiate the @ref $reg_rscworkers workers registry and the - * @ref $reg_rscs resources - * registry. - * @note At this moment (V 0.9.01): when you develop a new workerssubclass you must - * manually add its characteristics via a class call to its provides_work() function - * from within the constructor code. - * (It is needed because I couldnot find an easy way to search for existing subclasses - * yet) - * - */ - function egwical() - { - // actually this would only be needed by the abstract superclass? - $this->hi = &new Horde_iCalendar; - - $this->TASKMAGIC = $GLOBALS['egw_info']['server']['install_id'] - ? $GLOBALS['egw_info']['server']['install_id'] - : 'local'; - // update following list when a new worker subclasses becomes available - // (i.e. copy the info from its $iprovide_work var) - $this->reg_rscworkers = - array_merge( - $this->reg_rscworkers, - bocalupdate_vevents::provides_work(), - boinfolog_vtodos::provides_work() - ); - // error_log('**now reg_workers=' . print_r($this->reg_rscworkers,true)); - $this->reg_rscs = array(); - } - - - /** - * Add a egw resource. - * - * The egw resource (calendar, infolog, ..) in $egw_rsc is added - * to egwical. This will be used for storing and retrieving - * types of iCalendar components (VEVENT, VTODO,..) for which it has corresponding - * egw data elements (like egw events or egw tasks. - * - * Following the WURH pattern, adding the egw resource $rsc will result in - * the creation of a dedicated representative "worker" subclass object to handle the - * transport to and from the resource. The appropiate worker class is looked up in the - * $reg_workers registry. When the worker is created, the resource and its worker will - * be entered as a resource worker pair in the egwical $reg_rscs registry. - * This representative worker object will also be - * returned by reference to the caller. Using this reference the caller can later on do - * specific settings for the worker, (like setSupportedFields()). - * - * @param object $egw_rsc egw resource (like calendar or infolog,..) object that will be - * used by the egwical representative worker class to transport converted - * ical components to and from. - * @return egwical|false $rpr_worker the representative worker class for handling the - * added egw resource. On error false is returned. - */ - function addRsc($egw_rsc) - { - //step 1: detect the egw_rsc class - if (!$rsc_classname = get_class($egw_rsc)) - // bad value for $egw_rsc - return false; - - //step 1a check that the egwrsc is not already registered - foreach($this->reg_rscs as $vc => $rscwkpair){ - if($rscwkpair[0] === $egw_rcs){ - error_log('Warning: egwical.addRsc(): trying add resource multiple times,' . - ' for class: ' . $rsc_classname . ' : ignored'); - return $rscwkpair[1]; - } - } - - //step 1: detect the egw_rsc class - if (!$rsc_classname = get_class($egw_rsc)) - // bad value for $egw_rsc - return false; - - // step 2a: look in reg_rscworkers for appropiate worker class - if (!$wkprov = $this->reg_rscworkers[$rsc_classname]){ - error_log('Error: egwical.addRsc(): no workerclass available yet for resourcetype:' . - $class_name . ' sorry'); - return false; - } - - // step 2b create a workerobject of the correct type - // note that we dont reuse an already available workerobj of the right type because - // probably the workerclasses are not reentrantly coded yet... - if(! $wkobj =& CreateObject('egwical.' . $wkprov['workerclass'])){ - // workerclass object creation problem - return false; - } - // step 2c give the workerobj the egw_rsc to handle - $wkobj->setRsc($egw_rsc); - - // step3: use the found worker info to register the egw_rsc and workerobj for - // each of the supported type of ical elements - foreach ($wkprov['icalsup'] as $icomptype ){ - //error_log('adding reg_rscs['. $icomptype . '] entry'); - $this->reg_rscs = array_merge($this->reg_rscs, - array($icomptype => array($egw_rsc, $wkobj))); - } - // step 4: return the workerclass (representative obj) - - return $wkobj; - } - - - - // ------------- second: below only generic conversion stuff -------------- - - - // --- generic conversion auxilliary routines ------------- - // --- note: this could be left out in the abstract baseclass instantiation - // but is not that much, so leave it get duplicated... - - /** - * @private - * @var string - * Magic unique number used for de/encoding our uids. - * - * This string that contains global unique magic number that is - * unique for our current database installed etc. It is used to recognize - * earlier exported VTODO or VEVENT UID fields as referring to their eGW counterparts. - */ - var $TASKMAGIC='dummy'; - - - /** - * @var array $status_ical2egw - * Conversion of the egw used priority values(0..3) to corresponding ical values(0..9). - * @private - */ - var $priority_egw2ical = - array( - 0 => 0, // undefined - 1 => 9, // low - 2 => 5, // normal - 3 => 1, // high - ); - /** - * @var array $status_ical2egw conversation of the priority ical => egw - * Conversion of the icalendar used priority values(0..9) to corresponding egw values (0..3). - * @private - */ - var $priority_ical2egw = - array( - 0 => 0, // undefined - 9 => 1, 8 => 1, 7 => 1, // low - 6 => 2, 5 => 2, 4 => 2, // normal - 3 => 3, 2 => 3, 1 => 3, // high - ); - - - /** - * @var array $partstatus_egw2ical - * Conversion of the egw used participant status values to the corresponding icalendar - * attendee status terminology. - * @private - */ - var $partstatus_egw2ical = - array( - 'U' => 'NEEDS-ACTION', - 'A' => 'ACCEPTED', - 'R' => 'DECLINED', - 'T' => 'TENTATIVE', - ); - /** - * @var array - * Conversion of the icalendar used attendee status values to the corresponding icalendar - * participants status terminology. - * @private - */ - var $partstatus_ical2egw = - array( - 'NEEDS-ACTION' => 'U', - 'ACCEPTED' => 'A', - 'DECLINED' => 'R', - 'TENTATIVE' => 'T', - ); - - - /** - * @var array $recur_egw2ical - * Conversion of egw recur-type to ical FREQ values for RRULE fields - * @private - */ - var $recur_egw2ical = - array( - MCAL_RECUR_DAILY => 'DAILY', - MCAL_RECUR_WEEKLY => 'WEEKLY', - MCAL_RECUR_MONTHLY_MDAY => 'MONTHLY', - MCAL_RECUR_MONTHLY_WDAY => 'MONTHLY', - MCAL_RECUR_YEARLY => 'YEARLY', - ); - // BYMONHTDAY={1..31}, BYDAY={1..5}{MO..SO} - - /** - * @var array - * recur_days translates MCAL recur-days to verbose labels - * (copied from class.bocal.inc.php file - * @private - */ - var $recur_days = - array( - MCAL_M_MONDAY => 'Monday', - MCAL_M_TUESDAY => 'Tuesday', - MCAL_M_WEDNESDAY => 'Wednesday', - MCAL_M_THURSDAY => 'Thursday', - MCAL_M_FRIDAY => 'Friday', - MCAL_M_SATURDAY => 'Saturday', - MCAL_M_SUNDAY => 'Sunday', - ); - - /** - * @var array - * Get sequential indexes for the daynames in a week. Used for recurrence count - * calculations. - */ - var $dowseqid = - array('SU' => 1, 'MO' => 2, 'TU' => 3, 'WE' => 4, 'TH' => 5, 'FR' => 6, 'SA' => 7); - - - // --- generic conversion auxilliary routines ------------- - - /** - * Parse a vCalendar string into an Horde_iCalendar object. - * - * To actually parse the string, the Horde_iCalendar in member @ref $hi is used. - * @param string $vcalstr the icalendar input string - * @return boolean|Horde_iCalendar the resulting parsed elements collected in a - * horde ical object. On error: false - */ - function parsevCalendar($vcalstr) - { - // unfoldlines as this was removed from our horde stuff - $vcalstr = preg_replace("/[\r\n]+ /",'',$vcalstr); - - // $this->hi->clear(); - if(!$this->hi->parsevCalendar($vcalstr)){ - error_log('egwical parsevCalendar: ERROR- couldnot parse..'); - return false; - } - - return $this->hi; - } - - - - - /** - * Generate ical UID from egw id. - * - * generate a unique id, with the egw id encoded into it, which can be - * used for later synchronisation. - * @param string|int $egw_id eGW id of the egw entity (event, task,..) - * @param string $app_prefix prefix to use in ecnoding the name - * - * @return string|false on success the global unique id. On error: false. - * - * Uses @ref $TASKMAGIC string that holds our unique ID - */ - function mki_v_guid($egw_id,$app_prefix='egw') - { - if (empty($egw_id)) - return false; - return $app_prefix .'-' . $egw_id. '-' . $this->TASKMAGIC; - } - - - - /** - * Try to decode an egw id from a ical UID - * - * @param string $guid the global Icalendar UID value - * @param string $app_prefix prefix to be found in the encoding - * @return false|int On error: false. - * On success: local egw todo id. - */ - function mke_guid2id($guid,$app_prefix='egw') - { - // error_log('mke_guid2id: trying to recover id from' . $guid); - if (!preg_match('/^' . $app_prefix . '-(\d+)-' . - $this->TASKMAGIC . '$/',$guid,$matches)) - return false; - - // error_log("mke_guid2id: found (" . $matches[1] . ")"); - return $matches[1]; - } - - - - /** - * Get database add date of event or todo - * @private - * @param int $id id of event or todo - * @param string $appname name of the application (='calendar' or 'infolog') - * @return int $createdate of db insert or false on error - */ - function get_TSdbAdd($id,$appname='calendar') - { - if (!(($appname == 'calendar') || ($appname == 'infolog'))) - return false; - if (! $auid = $GLOBALS['egw']->common->generate_uid($appname,$id)) - return false; - - return $GLOBALS['egw']->contenthistory->getTSforAction($auid,'add'); - } - - - /** - * Convert a egw prio into a value for the ical property PRIORITY - * @param int $eprio priority in egw (0..3) - * @return int $iprio conversion of $eprio as value (0..9) for the ical PRIORITY prop - */ - function mki_v_prio($eprio = 0) - { - return $this->priority_egw2ical[$eprio]; - } - - /** - * Convert a ical prio into a value for egw - * @param int $iprio priority in ical (0..9) - * @return int $eprio conversion of $iprio as value (0..3) for egw - */ - function mke_prio($iprio = 0) - { - return $this->priority_ical2egw[$iprio]; - } - - - - /** - * Translate cat-ids to array with id-name pairs - * - * JVLNOTE: boldly copied from class.xmlrpc_server.inc.php because I donot know how - * to instantiate $GLOBALS['server'] (that provides this method) atm. - * @note THIS CODE SHOULD BE SOMEWHERE ELSE: IT HAS NOTHING TO DO WITH ICAL!! - * @param array $cids the list with category ids - * @return string|false $idnamescstr commasep string with names for the category ids or - * on error false - */ - function cats_ids2idnamescstr($cids) - { - if(empty($cids)) - return false; - - if (!is_object($GLOBALS['egw']->categories)) - $GLOBALS['egw']->categories = CreateObject('phpgwapi.categories'); - - $idnames = array(); - foreach($cids as $cid) { - if ($cid) - $idnames[$cid] = stripslashes($GLOBALS['egw']->categories->id2name($cid)); - } - return implode(',',$idnames); - } - - - // ************ JVL CHECK THE CODE BENEATH ***************** - // oke: seems to work for a single categorie (tested form bovtodos calls) - - /** - * Translate catnames back to cat-ids creating/modifying cats on the fly - * - * JVLNOTE boldly copied from class.xmlrpc_server.inc.php because I donot know how - * to instantiate $GLOBALS['server'] (that provides this method) atm. - * - * @note THIS CODE SHOULD BE SOMEWHERE ELSE: IT HAS NOTHING TO DO WITH ICAL!! - * @param array $cnames list with category names - * @return string $cidscstr commasep string with ids generated or found for - * the category names. - */ - function cats_names2idscstr($cnames,$owner_id,$app_name='infolog') - { - if (empty($cnames)) - return false; - - if (!is_object($catsys =& $GLOBALS['egw']->categories)) { - $GLOBALS['egw']->categories =& CreateObject('phpgwapi.categories', - $owner_id,$app_name); - $catsys =& $GLOBALS['egw']->categories; - } - $cids = array(); - foreach($cnames as $name) { - if (!($cid = $catsys->name2id($name))) { - // existing cat-name use the id - // new cat - $cid = $catsys->add(array('name' => $name,'descr' => $name)); - } - $cids[] = (int)$cid; - } - return implode(',',$cids); - } - - - /** - * Convert and egw account id into a iCalendar CAL-ADDRESS type value string - * @param int $aid egw account(person) id - * @return string $cls cal_address format string (mailto:. On error - * the emailadr part will stay empty. - */ - function mki_v_CAL_ADDRESS($aid) - { - $mailtoAid = $GLOBALS['egw']->accounts->id2name($aid,'account_email'); - return $mailtoAid ? 'MAILTO:'.$mailtoAid : 'MAILTO:'; - } - - - /** - * Convert and egw account id into a iCalendar CN type parameter string - * @param int $account_id egw account(person) id - * @return string $cnparam CN param value format string. On erro this will be empty. - */ - function mki_p_CN($account_id) - { - $cns = trim($GLOBALS['egw']->accounts->id2name($account_id,'account_firstname') - . ' ' - . $GLOBALS['egw']->accounts->id2name($account_id,'account_lastname')); - - return array('CN' => $cns ? $cns : ''); - } - - - /** - * Convert a horde_icalendar parsed attribute date- or date-time value - * to a unix timestamp. - * @note this is just a hack because horde_icalendar converts only date-times to utime - * @param array|string $ddtval DATE array or DATE-TIME utime string - * @return int $utime unix time of the date or date time - */ - function mke_DDT2utime($ddtval) - { - if(!is_array($ddtval)){ - // assume an already parsed(by Horde_iCalendar) date-time value - return $ddtval; - } else { - //assume a DATE, BUT WHERE DO I GET A POSSIBLE TIMEZONE FROM? - // assume user time zone (for utc use gmmktime() - return @mktime(0,0,0,$ddtval['month'],$ddtval['mday'],$ddtval['year']); - } - } - - - /** - * Convert a unix timestamp to a 6 field hash array in the current active timezone - * - * This is basically alike the php getdate() function but with different field names - * - * The a6date array has fields as in the php getdate() function: - * - year four digit year field - * - month integer month number - * - mday integer day of month number - * - hour integer hour - * - minute integer minutes - * - second integer seconds - * - * @param int $utime a unixtimestamp assumed in utc timezone - * @return array The date in a6date in local timezone format. - */ - function utimetoa6($utime) - { - $t=getdate($utime); - return array('hour' => $t['hours'], 'minute' => $t['minutes'], - 'second' => $t['seconds'],'month' => $t['mon'], - 'mday' => $t['mday'],'year' => $t['year']); - } - - - /** - * Convert a 6 field hash array in the current active timezone to a unix timestamp. - * - * This is basically the inverseof php getdate() function. - * - * The a6date array has fields as in the php getdate() function: - * - year four digit year field - * - month integer month number note: mon, not month!! - * - mday integer day of month number - * - hour integer hour - * - minute integer minutes - * - second integer seconds - * - * @param array $a6 The date in a6date in local timezone format. - * @return int a unixtimestamp assumed in utc timezone - */ - function a6toutime ($a6) - { - return mktime($a6['hour'],$a6['minute'],$a6['second'], - $a6['month'],$a6['mday'],$a6['year']); - } - - - /** - * Convert the egw person id and its participant status into - * an ATTENDEE value and parameterslist - * - * The resulting value of the ATTENDEE field will be in CAL_ADDRESS type format. - * The resulting parameterlist may contain fields of the following: - * - ROLE={CHAIR|REQ-PARTICIPANT|OPT-PARTICIPANT|NON-PARTICIPANT} - * this parameter is NOT used by eGW atm. - * - RSVP={TRUE|FALSE} - * resonse is expected, not set in eGW then status will have value U. - * - PARTSTAT={NEEDS-ACTION|ACCEPTED|DECLINED|TENTATIVE|DELEGATED| - * COMPLETED|IN-PROGRESS} everything from delegated is NOT used by eGW atm. - * - CUTYPE={INDIVIDUAL|GROUP|RESOURCE|ROOM|UNKNOWN} only GROUP or INDIVIDUAL - * are produced atm. - * - * @param int $pid egw id of a participant - * @param array $partstat egw particpant status of person with $uid - * @param int $owner_id id of the owner of the todo or event (needed to set the CHAIR) - * @return array ($val,$params) list with value and parameter-array for ATTENDEE property - * @note no error handling atm - */ - function mki_vp_4ATTENDEE($pid,$partstat,$owner_id) - { - $atdval = $this->mki_v_CAL_ADDRESS($pid); - // first parameter - $atdpars = $this->mki_p_CN($pid); - $atdpars['ROLE'] = ($pid == $owner_id) ? 'CHAIR' : 'REQ-PARTICIPANT'; - $atdpars['RSVP'] = $partstat == 'U' ? 'TRUE' : 'FALSE'; - $atdpars['CUTYPE'] = $GLOBALS['egw']->accounts->get_type($uid) == 'g' - ? 'GROUP' : 'INDIVIDUAL'; - $atdpars['PARTSTAT'] = $this->partstatus_egw2ical[$partstat]; - - return array($atdval,$atdpars); - } - - - /** - * Make a value of type RECUR for a ical RRULE property - * - * A simple example: - * ( RRULE) : (FREQ=MONTHLY;COUNT=10;INTERVAL=2) - * here the first part between parenthesis is property and the - * second is a value of type RECUR - * - * @param string $recur_type the type of recurrence frequence we have - * @param mixed $recur_data Todo describe this parameter... - * @param int $recur_interval Todo describe this parameter... - * @param utime $recur_enddate the final date that the recurrence ends - * @return string ($recurval) a value format as RECUR for the RRULE property - * (if a time is set) - */ - function mki_v_RECUR($recur_type,$recur_data,$recur_interval,$recur_start,$recur_enddate) - { - $recur = array(); - $recurval ='FREQ=' . $this->recur_egw2ical[$recur_type]; - - switch ($recur_type) { - case MCAL_RECUR_WEEKLY: - $days = array(); - foreach($this->recur_days as $did => $day) { - if ($recur_data & $did) - $days[] = strtoupper(substr($day,0,2)); - } - $recur['BYDAY'] = implode(',',$days); - break; - case MCAL_RECUR_MONTHLY_MDAY: // date of the month: BYMONTDAY={1..31} - $recur['BYMONTHDAY'] = (int) date('d',$recur_start); - break; - case MCAL_RECUR_MONTHLY_WDAY: // weekday of the month: BDAY={1..5}{MO..SO} - $recur['BYDAY'] = (1 + (int) ((date('d',$recur_start)-1) / 7)) - . strtoupper(substr(date('l',$recur_start),0,2)); - break; - } - - if ($recur_interval > 1) - $recur['INTERVAL'] = $recur_interval; - - if ($recur_enddate){ - -// $expdt= $this->hi->_exportDateTime($recur_enddate); -// error_log('EXPORT UNTIL=' . $recur_enddate . ' expdDT:' . $expdt); - - $recur['UNTIL'] = $this->hi->_exportDateTime($recur_enddate); - } - foreach($recur as $parnam => $parval){ - $recurval .= ';' . $parnam . '=' . $parval; - } - return $recurval; - } - - /** - * Make a value (commasep string of dates) for the EXDATE property - * - * In the conversion you can chose between a commastring of DATES or DATE-TIMES - * @param array $recur_exceptions list with utime exception dates - * @param boolean $dtmode if true generate DATE-TIME dates else DATES - * @return array ($exdval, $exdparams) a list with the value and parameters generated - */ - function mki_vp_4EXDATE($recur_exceptions,$dtmode=false) - { - $days = array(); - foreach($recur_exceptions as $day) { - $days[] = date('Ymd',$day); - } - - $exdparams = array(); - if(!$dtmode) - $exdparams['VALUE'] = 'DATE'; - return array( implode(',',$days), $exdparams); - } - - /** - * Convert DDT possible DATE|DATE-TIME params and a value commalist - * into an array of utime dates. - * - * Some examples - *
    -	   * ex1: ...;VALUE=DATE:20060123,20060124
    -	   * ex2: ...:20060118T101500Z,20060119T1000Z
    -	   * ex3: ...:VALUE=DATE-TIME:20060118T101500Z,20060119T1000Z
    -	   * 
    - * @note unfortunately horde_icalendar will parse ex1 into an array of - * array(month => .. , mday => .. , year=> ) - * @param array $dvals list of dates - * @return array $udays list with the days from the input list in utime format - */ - function mke_EXDATEpv2udays($params, $dvals) - { - //$exdays = (!is_array($dvals)) ? $dvals : array($dvals); - $exdays = $dvals; - - if (count($exdays) < 1) - return false; -//error_log('EXDAYS params=' . print_r($params,true)); -//error_log('EXDAYS exploded=' . print_r($exdays,true)); - if($params['VALUE'] == 'DATE'){ - // list is in awful horde DATE mode - // convert the date somehow to udays - $udays = array(); - foreach ($exdays as $day){ - $udays[] = $this->mke_DDT2utime($day); - } - } else { - // assume list is in DT mode - $udays = &$exdays; - } - - return $udays; - } - - - - /** - * Convert a RECUR value into the corresponding egw recur fields. - * - * A value of type RECUR (for a ical RRULE property) is parsed - * into the 4 related egw fields. Fields unfilled stay false A - * simple example: ( RRULE) : - * (FREQ=MONTHLY;COUNT=10;INTERVAL=2) here the first - * part between parenthesis is property and the second is a - * value of type RECUR - * - * @bug RECUR: MONTHLY;BYMONTHDAY, only ok if startdate is also on this MONTHDAY - * egw problem. - * - * @todo RECUR: COUNT=xx;WEEKLY;BYDAY, may miss the last occurence, if not started - * on a BYDAY day: to be fixed! prio=low - * - * @todo RECUR: YEARLY seems only to support the most basic variant?? To be checked! - * - * @author JVL (required some thinking..) - * @param string $recur RECUR type value of RRULE - * @param mixed $rstart start date in UTC format - * @return array $rar a assoc array with keys: 'recur_type', 'recur_data', 'recur_interval' - * and 'recur_enddate'. On error: false - * @note the class var @ref $hi is used as auxiliary Horde_iCalendar object - */ - function mke_RECUR2rar($recur,$rstart) - { - $ustart = $this->mke_DDT2utime($rstart); - - // a6sd is in Icalsrv usertime - $a6sd = $this->utimetoa6($ustart); - -// error_log('IMPORT RECURVAL=' . $recur . 'ustart=' .$ustart); - - - $r_data = 0; - $dow =array(); // for weekly count calc - $r_type = $r_interval = $r_end = $r_count = false; - - $type = preg_match('/FREQ=([^;: ]+)/i',$recur,$matches) - ? $matches[1] : $recur[0]; - if ($type == false) - return false; - - // vCard 2.0 values for all types - if (preg_match('/UNTIL=([0-9TZ]+)/',$recur,$matches)) - $r_end = $this->hi->_parseDateTime($matches[1]); - - if (preg_match('/INTERVAL=([0-9]+)/',$recur,$matches)) - $r_interval = (int) $matches[1]; - - // with count given we must calculate r_end - if (preg_match('/COUNT=([0-9]+)/',$recur,$matches)){ - $r_count = (int) $matches[1]; - // count calculation auxvars - $c_interval = ($r_interval) ? $r_interval : 1; //interval - $c_count = ($r_count - 1)*$c_interval; - } - - switch($type) { - - case 'W': - case 'WEEKLY': - $days = array(); - if(preg_match('/W(\d+) (.*) (.*)/',$recur, $recurMatches)) { // 1.0 - $r_interval = $recurMatches[1]; - $c_interval = $r_interval; - $days = explode(' ',trim($recurMatches[2])); - } elseif (preg_match('/BYDAY=([^;: ]+)/',$recur,$recurMatches)) { // 2.0 - $days = explode(',',$recurMatches[1]); - } - if ($days) { - foreach($this->recur_days as $mid => $day) { - if (in_array(strtoupper(substr($day,0,2)), $days)){ //WAS ERROR IN BOICAL!! - $r_data |= $mid; - } - } - $r_type = MCAL_RECUR_WEEKLY; - } - // --------- r_end calculation from COUNT and BYDAYs --- - if ($r_count) { - $c_count = ($r_count - 1)*$c_interval; - foreach($days as $wdd){ - $dow[] = $this->dowseqid[$wdd]; - } - sort($dow); - $ustart_seqid = $this->dowseqid[strtoupper(substr(date('D',$ustart),0,2))]; - // find index of start day 0.. - $sdi = 0; //in case start is not on a byday - foreach($dow as $i) { - if ($dow[$i] == $ustart_seqid){ // hope start is on byday - $sdi = $i; break; - } elseif($dow[$i] >= $ustart_seqid){ // else next byday - $sdi = $i; break; - } - } - $edi = $sdi + $c_count; // end day index - $dur = 0; // duration until end in days - $wic = count($dow); // week indexes count - $dur = 7 * floor($edi / $wic) + $dow[($edi % $wic)]; - $dur -= $dow[$sdi]; - $a6sd['mday'] += intval($dur); - $r_end = $this->a6toutime($a6sd); - // destroy $a6sd here.. - -//error_log('count=' . $c_count .'sdi=' . $sdi . ' edi=' . $edi . -// ' wic=' .$wic . ' dur=' .$dur . ' r_end=' . $r_end); - } - break; - - case 'D': // 1.0 - if(!preg_match('/D(\d+) (.*)/',$recur, $recurMatches)) - break; - $c_interval = $r_interval = $recurMatches[1]; - $r_end = $this->hi->_parseDateTime($recurMatches[2]); - // fall-through - - case 'DAILY': // 2.0 - $r_type = MCAL_RECUR_DAILY; - if ($r_count) { // count calc is still experimental! - $c_count = ($r_count - 1)*$c_interval; - $a6sd['mday'] += $c_count; - $r_end = $this->a6toutime($a6sd); - } - break; - - case 'MONTHLY': - $r_type = strstr($recur,'BYDAY') ? - MCAL_RECUR_MONTHLY_WDAY : MCAL_RECUR_MONTHLY_MDAY; - // break; - //fall through - - case 'M': - if(preg_match('/MD(\d+) (.*)/',$recur, $recurMatches)) { - $r_type = MCAL_RECUR_MONTHLY_MDAY; - $c_interval = $r_interval = $recurMatches[1]; - } elseif(preg_match('/MP(\d+) (.*) (.*) (.*)/',$recur, $recurMatches)) { - $r_type = MCAL_RECUR_MONTHLY_WDAY; - $c_interval = $r_interval = $recurMatches[1]; - } - // - if ($r_count) { // count calc is still experimental! - switch ($r_type) { - case MCAL_RECUR_MONTHLY_MDAY: - // error_log('DOING MOTNHLY MDAY'); Egw doesnot handle this special, see todo - $c_count = ($r_count - 1)*$c_interval; // maybe changed because 1.0 found - $a6sd['month'] += $c_count; - $r_end = $this->a6toutime($a6sd); - break; - - case MCAL_RECUR_MONTHLY_WDAY: - $c_count = ($r_count - 1)*$c_interval; // maybe changed because 1.0 found - // startday - $dowsd = date('w',$this->a6toutime($a6sd)); // day of week for sd - //end day, first try - $a6ed = array_diff($a6sd,array()); $a6ed['month'] += $c_count; - //day1 of startmonth - $a6smd1 = array_diff($a6sd,array()); $a6smd1['mday'] = 1; - $dowsmd1 = date('w',$this->a6toutime($a6smd1)); // day of week for smd1 - - //startdate as day of 5week segment, anchored on and afer smd1 - $do5wsegsd = $dowsmd1 + $a6sd['mday']; - if($dowsmd1 > $dowsd) - $do5wsegsd -= 7; - - $a6ed['mday'] =1; - $dowemd1 = date('w',$this->a6toutime($a6ed)); // endmonthday1 as day of week - $a6ed['mday'] = $do5wsegsd - $dowemd1; - if($dowemd1 > $dowsd) - $a6ed['mday'] += 7; - -// error_log('dowsd='. $dowsd . ' dowsmd1='. $dowsmd1 . ' do5wsegsd=' . $do5wsegsd . -// ' dowemd1='. $dowemd1 . ' edmday=' . $a6ed['mday'] ); - $r_end = $this->a6toutime($a6ed); - break; - } - } - break; - - - case 'Y': // 1.0 - if(!preg_match('/YM(\d+) (.*)/',$recur, $recurMatches)) - break; - $c_interval = $r_interval = $recurMatches[1]; - // fall-through - - case 'YEARLY': // 2.0 - $r_type = MCAL_RECUR_YEARLY; - if ($r_count) { // count calc is still experimental! - // is there only this BYMONTHDAY support? - $c_count = ($r_count - 1)*$c_interval; // maybe changed because 1.0 found - $a6sd['year'] += $c_count; - $r_end = $this->a6toutime($a6sd); - } - break; - } - - return array('recur_type' => $r_type, - 'recur_data' => $r_data, - 'recur_interval' => $r_interval, - 'recur_enddate' => $r_end ); - } - - - /** - * Parse a CAL_ADDRESS and try to find the associated egw person_id - * @param string $attrval CAL_ADDRESS type value string - * @return int|false $pid associated (by email) egw pid. On error: false. - */ - function mke_CAL_ADDRESS2pid($attrval) - { - if (preg_match('/MAILTO:([@.a-z0-9_-]+)/i',$attrval,$matches) && - ($pid = $GLOBALS['egw']->accounts->name2id(strtolower($matches[1]),'account_email'))){ - return $pid; - } else { - return false; - } - } - - /** - * Parse a CAL_ADDRESS and PARAMS to find the CN name and email - * @param string $aval CAL_ADDRESS type value string - * @param array $aparams parameters for a ATTENDEE - * @return array $cneml assoc array with 'cn' and 'mailto' field - */ - function mke_ATTENDEE2cneml($aval,$aparams) - { - $cneml = array('cn' => '', 'mailto' => ''); - - // if (preg_match('/MAILTO:([@.a-z0-9_-]+)/i',$aval,$matches)) - // lets be a bit more relaxed here (rfc1378).. - // try for "Fnam Lnam " first - if (preg_match('/MAILTO:([^<]+)<([@.a-z0-9_-]+)>/i',$aval,$matches)){ - $cneml['cn'] = $matches[1]; - $cneml['mailto'] = $matches[2]; - // try for second - }elseif (preg_match('/MAILTO:([@.a-z0-9_-]+)/i',$aval,$matches)){ - $cneml['mailto'] = $matches[1]; - } - // a CN from the params overrules one from the mailto - if(isset($aparams['CN'])) - $cneml['cn'] = $aparams['CN']; - - return $cneml; - } - - /** - * Update an egw event description with a list of nonegw participants. - * - * note: this is a adhoc solution, preferably the nonegw participants - * should be added automatically to the addressbook - * @param string &$edescription the participants are append to this string as - * a string formatted ([cn: name:mailto: eml] [] ... ) - * @param array &$ne_participants array of the non egw participants as - * ('cn' =>, 'mailto' =>) pairs - * @return true - */ - function upde_nonegwParticipants2description(&$edescription,&$ne_participants) - { - $edescription.= "\n - non egw participants:\n("; - $neplist = array(); - foreach ($ne_participants as $nep){ -// $li = '[cn:' . $nep['cn']; -// $li .= ($nep['mailto']) ? ';mailto:' . $nep['mailto'] .']' : ']'; - $li = '[' . $nep['cn']; - $li .= ($nep['mailto']) ? '<' . $nep['mailto'] .'>]' : ']'; - - $neplist[]= $li; - } - $edescription .= implode("\n",$neplist) . ')'; - - return true; - } - - - /** - * Search a ical parameterlist for possible setting for a egw participant status. - * - * Parse the params array to find a PARTSTAT param, convert this to - * a egw partstatus (may occur e.g. in ATTENDEE params) - * @param array $params params of e.g. an ical ATTENDEE field - * @return array|false $epartstatus egw term for particpant status if detected else false - */ - function mke_params2partstat($params) - { - if (!isset($params['PARTSTAT'])) - return false; - - return $this->partstatus_ical2egw[strtoupper($params['PARTSTAT'])]; - } - - /** - * Add (append) an new attribute (aka field) to the vevent. - * - * @param horde_iCalendar_vevent $vevent obj to which the attribute is added - * @param string $aname name for the new attribute - * @param mixed $avalue value for the new attribute - * @param array $aparams parameters for the new attribute - * @return true - */ - function addAttributeOntoVevent(&$vevent,$aname,&$avalue,&$aparams) - { - - // it appears that translation->convert() can translate an array - // (that is: the values!, not the keys though) - // so lets apply it to the avalue and aparams, that should be enough! -// error_log('n:' . $aname . 'v:' . $avalue); - $valueData = - $GLOBALS['egw']->translation->convert($avalue, - $GLOBALS['egw']->translation->charset(), - 'UTF-8'); - $paramData = - $GLOBALS['egw']->translation->convert( $aparams, - $GLOBALS['egw']->translation->charset(), - 'UTF-8'); -// error_log('n:' . $aname . 'v:' . $valueData); - $vevent->setAttribute($aname, $valueData, $paramData); - $options = array(); - // JVL:is this really needed? - if (is_string($valueData)){ - -// // JVL: TEMPORARY SWITCHED OFF... TURN ON AGAIN!!! -// if(!(in_array($aname, array('RRULE'))) -// && preg_match('/([\000-\012\015\016\020-\037\075])/',$valueData)) { -// $options['ENCODING'] = 'QUOTED-PRINTABLE'; -// } - - if( (preg_match('/([\177-\377])/',$valueData))) { - $options['CHARSET'] = 'UTF-8'; - } - } - $vevent->setParameter($aname, $options); - - return true; - } - - - /** - * Convert egw alarm info to a ical VALARM object. - * - * Make a VALARM object form data in $alarms and $utstart (in utc) - * and with $vevent as container - * @param array &$alarm a single egw alarm array to be used - * @param horde_object &$vcomp that will be the container for the valarm - * mostly vevent or vtodo. - * @param array &$veExportFields list with fields that may get imported - * @return horde_iCalendar_valarm|false valarm object or, on error, false. - */ - function mki_c_VALARM(&$alarm, &$vcomp, $utstart,&$veExportFields){ - -// error_log('export comp-alarm-field:' . print_r($alarm,true)); - - $valarm = Horde_iCalendar::newComponent('VALARM',$vevent); - - //try first an offset - if($durtime = -$alarm['offset']){ - $valarm->setAttribute('TRIGGER', - $durtime, - array('VALUE' => 'DURATION', - 'RELATED' => 'START')); - // no success then try a date-time - } elseif($dtime = $alarm['time']){ - $valarm->setAttribute('TRIGGER', - $ddtime, - array('VALUE' => 'DATE-TIME')); - } else{ - $valarm = null; - return false; - } - $vcomp->addComponent($valarm); - - return $valarm; - } - - - /** - * Update the egw alarms array with info from a VALARM - * @param array &$alarms the the egw alarms array to be updated - * @param horde_iCalendar_valarm $valarm ref to the valarm component to be updated - * @param int $user_id the user that will own the alarms found - * @param array &$veImportFields with fields that may get imported - * @return true - */ - function upde_c_VALARM2alarms(&$alarms,&$valarm,$user_id,&$veImportFields){ - - // lets see what supported veImportFields we can get from the valarm - foreach($valarm->_attributes as $vattr) { - // $vattrval = $GLOBALS['egw']->translation->convert($vattr['value'],'UTF-8'); - // handle only supported fields - if(!in_array('VALARM/' . $vattr['name'], $veImportFields)) - continue; - - switch($vattr['name']) { - case 'TRIGGER': - $vtype = (isset($vattr['params']['VALUE'])) - ? $vattr['params']['VALUE'] : 'DURATION'; //default type - switch ($vtype) { - case 'DURATION': - $alarms[] = array('offset' => -$vattr['value']); - break; - case 'DATE-TIME': - $alarms[] = array('time' => $vattr['value']); - break; - default: - // we should also do ;RELATED=START|END - error_log('VALARM/TRIGGER: unsupported value type:' . $vtype); - } - break; -// case 'ACTION': -// break; -// case 'DISPLAY': -// break; - - default: - error_log('VALARM field:' .$vattr['name'] .':' - . print_r($vattrval,true) . ' HAS NO CONVERSION YET'); - } - } -// error_log('updated alarms to:' . print_r($alarms,true)); - return true; - } - - - - - - - } - -?> \ No newline at end of file diff --git a/egwical/inc/class.vcalinfolog.inc.compat.php b/egwical/inc/class.vcalinfolog.inc.compat.php deleted file mode 100644 index 19d81d5694..0000000000 --- a/egwical/inc/class.vcalinfolog.inc.compat.php +++ /dev/null @@ -1,72 +0,0 @@ -ei =& CreateObject('egwical.egwical'); - // $this->wkobj =& $this->ei->addRsc($this); - // or the fast, shortcut, road for knowingly experts only: - $this->wkobj =& CreateObject('egwical.boinfolog_vtodos'); - $this->wkobj->setRsc($this); - - if ($this->wkobj == false){ - error_log('boical constructor: couldnot add bocal resource to egwical: FATAL'); - return false; - } - } - - - // now implement the compatibility methods, that are all moved to egwical! - - function exportVTODO($_taskID, $_version) - { - return $this->wkobj->exportVTODO($_taskID, $_version); - } - - function importVTODO(&$_vcalData, $_taskID=-1) - { - return $this->wkobj->importVTODO($_vcalData, $_taskID); - } - - -// function setSupportedFields($_productManufacturer='file', $_productName='') -// { -// return $this->wkobj->setSupportedFields($_productManufacturer, $_productName); -// } - - } -?>