4 * Created on 26 November 2006, 15:44
5 * Copyright (C) Mathew McBride 2006-2007
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Affero General Public License as
9 * published by the Free Software Foundation, either version 3 of the
10 * License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Affero General Public License for more details.
17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 package net
.bionicmessage
.funambol
.datakit
;
22 import com
.funambol
.common
.pim
.calendar
.RecurrencePattern
;
23 import com
.funambol
.common
.pim
.calendar
.RecurrencePatternException
;
24 import com
.funambol
.common
.pim
.calendar
.Task
;
25 import com
.funambol
.common
.pim
.converter
.VCalendarConverter
;
26 import com
.funambol
.common
.pim
.model
.VCalendar
;
27 import java
.io
.FileInputStream
;
29 import net
.fortuna
.ical4j
.model
.*;
30 import net
.fortuna
.ical4j
.model
.Property
.*;
32 import net
.fortuna
.ical4j
.data
.*;
33 import java
.util
.ArrayList
;
34 import java
.util
.Iterator
;
35 import java
.util
.List
;
36 import net
.fortuna
.ical4j
.model
.component
.CalendarComponent
;
37 import net
.fortuna
.ical4j
.model
.component
.VAlarm
;
38 import net
.fortuna
.ical4j
.model
.component
.VEvent
;
39 import net
.fortuna
.ical4j
.model
.component
.VToDo
;
40 import net
.fortuna
.ical4j
.model
.parameter
.AltRep
;
41 import net
.fortuna
.ical4j
.model
.parameter
.CuType
;
42 import net
.fortuna
.ical4j
.model
.parameter
.Encoding
;
43 import net
.fortuna
.ical4j
.model
.parameter
.Related
;
44 import net
.fortuna
.ical4j
.model
.property
.Action
;
45 import net
.fortuna
.ical4j
.model
.property
.Attendee
;
46 import net
.fortuna
.ical4j
.model
.property
.Categories
;
47 import net
.fortuna
.ical4j
.model
.property
.Clazz
;
48 import net
.fortuna
.ical4j
.model
.property
.DateProperty
;
49 import net
.fortuna
.ical4j
.model
.property
.Description
;
50 import net
.fortuna
.ical4j
.model
.property
.DtEnd
;
51 import net
.fortuna
.ical4j
.model
.property
.DtStart
;
52 import net
.fortuna
.ical4j
.model
.property
.Due
;
53 import net
.fortuna
.ical4j
.model
.property
.Duration
;
54 import net
.fortuna
.ical4j
.model
.property
.LastModified
;
55 import net
.fortuna
.ical4j
.model
.property
.Location
;
56 import net
.fortuna
.ical4j
.model
.property
.Priority
;
57 import net
.fortuna
.ical4j
.model
.property
.RDate
;
58 import net
.fortuna
.ical4j
.model
.property
.RRule
;
59 import net
.fortuna
.ical4j
.model
.property
.Status
;
60 import net
.fortuna
.ical4j
.model
.property
.Summary
;
61 import net
.fortuna
.ical4j
.model
.property
.Transp
;
62 import net
.fortuna
.ical4j
.model
.property
.Trigger
;
63 import net
.fortuna
.ical4j
.model
.property
.Uid
;
66 * Provides utilities for converting ical4j data objects to Fumambol
70 public class ical4j2funambol
{
72 /** Creates a new instance of ical4j2funambol */
73 public static com
.funambol
.common
.pim
.calendar
.Calendar
convertIcal4jToFunambolEvent(net
.fortuna
.ical4j
.model
.Calendar ical4j
, String clientType
) throws RecurrencePatternException
{
76 /* Setup a funambol event */
77 com
.funambol
.common
.pim
.calendar
.Calendar fnblcal
= new com
.funambol
.common
.pim
.calendar
.Calendar();
78 com
.funambol
.common
.pim
.calendar
.CalendarContent fnblcontent
= null;
79 Component comp
= null;
80 comp
= (Component
) ical4j
.getComponents().get(0);
81 if (comp
.getName().equals(VEvent
.VEVENT
)) {
82 fnblcontent
= new com
.funambol
.common
.pim
.calendar
.Event();
83 fnblcal
.setEvent((com
.funambol
.common
.pim
.calendar
.Event
) fnblcontent
);
84 } else if (comp
.getName().equals(VToDo
.VTODO
)) {
85 fnblcontent
= new com
.funambol
.common
.pim
.calendar
.Task();
86 fnblcal
.setTask((Task
) fnblcontent
);
90 String startDate
= ""; /* If we get DtStart, then cache it for Funambol recur */
91 DtStart dts
= null; /* Also cache dtstart */
92 /* Blatantly obvious attributes */
93 if (comp
.getProperty(Uid
.UID
) != null) {
94 Uid uid
= (Uid
) comp
.getProperty(Uid
.UID
);
95 com
.funambol
.common
.pim
.common
.Property uidprop
=
96 new com
.funambol
.common
.pim
.common
.Property(uid
.getValue());
97 fnblcontent
.setUid(uidprop
);
99 /* if (comp.getProperty(LastModified.LAST_MODIFIED) != null) {
100 LastModified lm = (LastModified)comp.getProperty(LastModified.LAST_MODIFIED);
101 com.funambol.common.pim.common.Property lmprop =
102 new com.funambol.common.pim.common.Property();
104 lmprop.setPropertyValue(lm.getValue());
105 fnblcontent.setLastModified(lmprop);
107 /* if (comp.getProperty(Clazz.CLASS) != null) {
108 Clazz cl = (Clazz)comp.getProperty(Clazz.CLASS);
109 com.funambol.common.pim.common.Property clprop =
110 new com.funambol.common.pim.common.Property(cl.getValue());
113 /* Start off with basic attributes.. DTSTART, DTEND, SUMMARY, DESCRIPTION, LOCATION,
115 // Do not convert DTSTART for VToDo (rejected by some clients)
116 if (comp
.getProperty(DtStart
.DTSTART
) != null &&
117 !comp
.getName().equals(VToDo
.VTODO
)) {
118 dts
= (DtStart
) comp
.getProperty(DtStart
.DTSTART
);
119 Parameter v
= dts
.getParameter("VALUE");
121 v
.getValue().equals("DATE")) {
122 String newValue
= dts
.getValue();
123 attachAllDayDtStart(fnblcontent
, newValue
, clientType
);
126 com
.funambol
.common
.pim
.common
.Property dtsprop
= new com
.funambol
.common
.pim
.common
.Property(dts
.getValue());
127 fnblcontent
.setDtStart(dtsprop
);
128 dstime
= dts
.getDate().getTime();
129 fnblcontent
.setAllDay(false);
131 startDate
= fnblcontent
.getDtStart().getPropertyValueAsString();
133 if (comp
.getProperty(DtEnd
.DTEND
) != null) {
134 DtEnd dte
= (DtEnd
) comp
.getProperty(DtEnd
.DTEND
);
135 Parameter v
= dte
.getParameter("VALUE");
137 v
.getValue().equals("DATE")) {
138 String newValue
= dte
.getValue();
139 attachAllDayDtEnd(fnblcontent
, newValue
, clientType
);
142 com
.funambol
.common
.pim
.common
.Property dteprop
=
143 new com
.funambol
.common
.pim
.common
.Property(dte
.getValue());
144 fnblcontent
.setDtEnd(dteprop
);
145 detime
= dte
.getDate().getTime();
146 fnblcontent
.setAllDay(false);
149 if (comp
.getProperty(Due
.DUE
) != null && comp
.getProperty(DtEnd
.DTEND
) == null) {
150 Due due
= (Due
) comp
.getProperty(Due
.DUE
);
151 Parameter v
= due
.getParameter("VALUE");
153 v
.getValue().equals("DATE")) {
154 String newValue
= due
.getValue();
155 attachAllDayDtEnd(fnblcontent
, newValue
, clientType
);
158 com
.funambol
.common
.pim
.common
.Property dteprop
=
159 new com
.funambol
.common
.pim
.common
.Property(due
.getValue());
160 fnblcontent
.setDtEnd(dteprop
);
163 /** See if an all day event hasn't sneaked in via the back door */
164 if (detime
- dstime
== 86340000 || detime
- dstime
== 86399000) {
165 /* See the vObject minimum interoperability profile - OMA
166 * (OMA-TS-vObjectOMAProfile-V1_0-20050118-C) for information on how to
167 * correctly establish an all day event */
168 fnblcontent
.setAllDay(true);
169 DtEnd dte
= (DtEnd
) comp
.getProperty(DtEnd
.DTEND
);
171 net
.fortuna
.ical4j
.model
.Date dt
= new net
.fortuna
.ical4j
.model
.Date(dte
.getDate().getTime());
173 net
.fortuna
.ical4j
.model
.Date ds
= new net
.fortuna
.ical4j
.model
.Date(dts
.getDate().getTime());
175 attachAllDayDtStart(fnblcontent
, dts
.getValue(), clientType
);
176 attachAllDayDtEnd(fnblcontent
, dte
.getValue(), clientType
);
178 fnblcontent
.setAllDay(false);
180 if (comp
.getProperty(Summary
.SUMMARY
) != null) {
181 /* We need to consider text encodings for this.
182 * ical2 specifies 8 bit and base64 in spec, but vcal1
183 * also allows quoted-printable (EVIL!!!). */
184 Summary summ
= (Summary
) comp
.getProperty(Summary
.SUMMARY
);
185 com
.funambol
.common
.pim
.common
.Property summprop
=
186 new com
.funambol
.common
.pim
.common
.Property();
187 // Check for encodings
188 if (summ
.getParameter(Encoding
.ENCODING
) != null) {
189 Encoding enc
= (Encoding
) summ
.getParameter(Encoding
.ENCODING
);
190 summprop
.setEncoding(enc
.getValue());
192 summprop
.setPropertyValue(summ
.getValue());
193 fnblcontent
.setSummary(summprop
);
195 if (comp
.getProperty(Description
.DESCRIPTION
) != null) {
196 /* We also need to consider alternative text encoding here */
197 Description des
= (Description
) comp
.getProperty(Description
.DESCRIPTION
);
198 com
.funambol
.common
.pim
.common
.Property desprop
=
199 new com
.funambol
.common
.pim
.common
.Property();
200 // Check for encdoings
201 if (des
.getParameter(Encoding
.ENCODING
) != null) {
202 Encoding enc
= (Encoding
) des
.getParameter(Encoding
.ENCODING
);
203 desprop
.setEncoding(enc
.getValue());
205 desprop
.setPropertyValue(des
.getValue());
206 fnblcontent
.setDescription(desprop
);
208 if (comp
.getProperty(Location
.LOCATION
) != null) {
209 Location loc
= (Location
) comp
.getProperty(Location
.LOCATION
);
210 com
.funambol
.common
.pim
.common
.Property locprop
=
211 new com
.funambol
.common
.pim
.common
.Property();
212 // Is our location pointing to a URL?
213 if (loc
.getParameter(AltRep
.ALTREP
) != null) {
214 AltRep url
= (AltRep
) loc
.getParameter(AltRep
.ALTREP
);
215 locprop
.setValue("URL");
216 locprop
.setType("VCARD");
218 locprop
.setPropertyValue(loc
.getValue());
219 fnblcontent
.setLocation(locprop
);
221 if (comp
.getProperty(Priority
.PRIORITY
) != null) {
222 Priority pri
= (Priority
) comp
.getProperty(Priority
.PRIORITY
);
223 com
.funambol
.common
.pim
.common
.Property priprop
=
224 new com
.funambol
.common
.pim
.common
.Property(pri
.getValue());
225 fnblcontent
.setPriority(priprop
);
226 } else if (comp
.getName().equals(VToDo
.VTODO
)) {
227 com
.funambol
.common
.pim
.common
.Property priprop
=
228 new com
.funambol
.common
.pim
.common
.Property("1");
229 fnblcontent
.setPriority(priprop
);
231 /* Slightly harder */
232 if (comp
.getProperty(Transp
.TRANSP
) != null && fnblcontent
instanceof com
.funambol
.common
.pim
.calendar
.Event
) {
233 Transp tsp
= (Transp
) comp
.getProperty(Transp
.TRANSP
);
234 com
.funambol
.common
.pim
.common
.Property tspprop
=
235 new com
.funambol
.common
.pim
.common
.Property();
236 if (tsp
.getValue().equals(Transp
.OPAQUE
)) {
237 // This event WILL show up as busy
238 tspprop
.setPropertyValue("0");
239 } else { // What calendar app couldn't chose between OPAQUE and TRANSPARENT?
240 tspprop
.setPropertyValue("1");
242 com
.funambol
.common
.pim
.calendar
.Event e
=
243 (com
.funambol
.common
.pim
.calendar
.Event
) fnblcontent
;
244 e
.setTransp(tspprop
);
246 if (comp
.getProperty(Status
.STATUS
) != null &&
247 fnblcontent
instanceof com
.funambol
.common
.pim
.calendar
.Task
) {
248 Status status
= (Status
) comp
.getProperty(Status
.STATUS
);
249 com
.funambol
.common
.pim
.common
.Property stat
=
250 new com
.funambol
.common
.pim
.common
.Property();
251 if (status
.equals(Status
.VTODO_COMPLETED
)) {
252 stat
.setPropertyValue("2");
253 } else if(status
.equals(Status
.VTODO_CANCELLED
)) {
254 stat
.setPropertyValue("4");
255 } else if (status
.equals(Status
.VTODO_IN_PROCESS
)) {
256 stat
.setPropertyValue("1");
257 } else if (status
.equals(Status
.VTODO_NEEDS_ACTION
)) {
258 stat
.setPropertyValue("0");
260 // stat.setPropertyValue(status.getValue());
261 com
.funambol
.common
.pim
.calendar
.Task t
=
262 (com
.funambol
.common
.pim
.calendar
.Task
) fnblcontent
;
265 PropertyList attendees
= comp
.getProperties("ATTENDEE");
266 List
<com
.funambol
.common
.pim
.calendar
.Attendee
> fnblattendees
=
267 fnblcontent
.getAttendees();
268 Iterator attendeeIterator
= attendees
.iterator();
269 while (attendeeIterator
.hasNext()) {
270 Attendee att
= (Attendee
) attendeeIterator
.next();
271 com
.funambol
.common
.pim
.calendar
.Attendee fnblatt
=
272 new com
.funambol
.common
.pim
.calendar
.Attendee();
273 URI attaddr
= att
.getCalAddress();
274 if (attaddr
.toString().length() > 0) {
275 fnblatt
.setUri(attaddr
.toString());
276 fnblatt
.setName(att
.getParameter("CN").getValue());
277 CuType ct
= (CuType
) att
.getParameter("CUTYPE");
279 if (CuType
.INDIVIDUAL
.equals(ct
)) {
280 fnblatt
.setKind(com
.funambol
.common
.pim
.calendar
.Attendee
.INDIVIDUAL
);
281 } else if (CuType
.GROUP
.equals(ct
)) {
282 fnblatt
.setKind(com
.funambol
.common
.pim
.calendar
.Attendee
.GROUP
);
285 fnblattendees
.add(fnblatt
);
288 if (comp
.getProperty(Categories
.CATEGORIES
) != null) {
289 Categories cat
= (Categories
) comp
.getProperty(Categories
.CATEGORIES
);
290 fnblcontent
.getCategories().setPropertyValue(cat
.getValue());
292 if (comp
.getProperty(RRule
.RRULE
) != null) {
293 RRule rr
= (RRule
) comp
.getProperty(RRule
.RRULE
);
294 Recur r
= rr
.getRecur();
295 /* This is where things start getting insane. Funambol wants us to
296 * find out every property of the recurrance rule and then use a custom
297 * constructor for each case! */
298 /* ical2 RULE VIOLATION: VEVENT may contain multiple RRULES... */
299 String freq
= r
.getFrequency();
300 System
.err
.println("FREQ="+freq
);
301 int interval
= r
.getInterval();
302 int count
= r
.getCount();
303 boolean noEndDate
= false;
305 if (r
.getUntil() == null) {
308 net
.fortuna
.ical4j
.model
.Date eDate
= r
.getUntil();
309 endDate
= eDate
.toString();
311 short dayOfWeekMask
= 0;
312 if (freq
.equals(Recur
.DAILY
)) {
314 RecurrencePattern rp
= RecurrencePattern
.getDailyRecurrencePattern(interval
,
320 fnblcontent
.setRecurrencePattern(rp
);
321 } catch (RecurrencePatternException re
) {
322 re
.printStackTrace();
323 // Send all RecurrencePatternExceptions to ground for now
325 } else if (freq
.equals(Recur
.HOURLY
)) {
326 /* NOT SUPPORTED BY VCAL1 AND FUNAMBOL */
327 } else if (freq
.equals(Recur
.WEEKLY
)) {
330 ArrayList wkdaylist
= r
.getDayList();
331 for (int i
= 0; i
< wkdaylist
.size(); i
++) {
332 WeekDay wday
= (WeekDay
) wkdaylist
.get(i
);
333 String day
= wday
.getDay();
334 if (day
.equals("SU")) {
336 } else if (day
.equals("MO")) {
337 dayOfWeekMask
= (short) (dayOfWeekMask
+ 2);
338 } else if (day
.equals("TU")) {
339 dayOfWeekMask
= (short) (dayOfWeekMask
+ 4);
340 } else if (day
.equals("WE")) {
341 dayOfWeekMask
= (short) (dayOfWeekMask
+ 8);
342 } else if (day
.equals("TU")) {
343 dayOfWeekMask
= (short) (dayOfWeekMask
+ 16);
344 } else if (day
.equals("FR")) {
345 dayOfWeekMask
= (short) (dayOfWeekMask
+ 32);
346 } else if (day
.equals("SA")) {
347 dayOfWeekMask
= (short) (dayOfWeekMask
+ 64);
350 RecurrencePattern rp
= RecurrencePattern
.getWeeklyRecurrencePattern(interval
,
356 fnblcontent
.setRecurrencePattern(rp
);
357 } catch (RecurrencePatternException re
) {
358 re
.printStackTrace();
360 } else if (freq
.equals(Recur
.MONTHLY
)) {
361 /* Monthly - we have two sorts of month recurrance - by number day of month
362 * or day of week of month */
363 // Do we have a set week position
364 if (r
.getDayList().size() > 0) {
365 // Get the weekday instance
366 WeekDay wd
= (WeekDay
) r
.getDayList().get(0);
367 String day
= wd
.getDay();
368 int week
= wd
.getOffset();
369 Integer weekoffset
= new Integer(week
);
370 if (day
.equals("SU")) {
372 } else if (day
.equals("MO")) {
373 dayOfWeekMask
= (short) (dayOfWeekMask
+ 2);
374 } else if (day
.equals("TU")) {
375 dayOfWeekMask
= (short) (dayOfWeekMask
+ 4);
376 } else if (day
.equals("WE")) {
377 dayOfWeekMask
= (short) (dayOfWeekMask
+ 8);
378 } else if (day
.equals("TU")) {
379 dayOfWeekMask
= (short) (dayOfWeekMask
+ 16);
380 } else if (day
.equals("FR")) {
381 dayOfWeekMask
= (short) (dayOfWeekMask
+ 32);
382 } else if (day
.equals("SA")) {
383 dayOfWeekMask
= (short) (dayOfWeekMask
+ 64);
385 RecurrencePattern rp
= RecurrencePattern
.getMonthNthRecurrencePattern(
388 weekoffset
.shortValue(),
393 fnblcontent
.setRecurrencePattern(rp
);
396 java
.util
.Calendar mcal
= java
.util
.Calendar
.getInstance();
397 mcal
.setTime(dts
.getDate());
398 Integer dayOfMonth
= new Integer(mcal
.get(java
.util
.Calendar
.DAY_OF_MONTH
));
399 dayOfWeekMask
= dayOfMonth
.shortValue();
400 RecurrencePattern rp
= RecurrencePattern
.getMonthlyRecurrencePattern(interval
,
406 fnblcontent
.setRecurrencePattern(rp
);
407 } catch (RecurrencePatternException re
) {
408 re
.printStackTrace();
412 } else if (freq
.equals(Recur
.YEARLY
)) {
413 // Same as monthly recurrence basically.
414 if (r
.getDayList().size() > 0) {
415 WeekDay wd
= (WeekDay
) r
.getDayList().get(0);
416 String day
= wd
.getDay();
417 int week
= wd
.getOffset();
418 Integer weekoffset
= new Integer(week
);
419 Integer month
= (Integer
) r
.getMonthList().get(0);
420 if (day
.equals("SU")) {
422 } else if (day
.equals("MO")) {
423 dayOfWeekMask
= (short) (dayOfWeekMask
+ 2);
424 } else if (day
.equals("TU")) {
425 dayOfWeekMask
= (short) (dayOfWeekMask
+ 4);
426 } else if (day
.equals("WE")) {
427 dayOfWeekMask
= (short) (dayOfWeekMask
+ 8);
428 } else if (day
.equals("TU")) {
429 dayOfWeekMask
= (short) (dayOfWeekMask
+ 16);
430 } else if (day
.equals("FR")) {
431 dayOfWeekMask
= (short) (dayOfWeekMask
+ 32);
432 } else if (day
.equals("SA")) {
433 dayOfWeekMask
= (short) (dayOfWeekMask
+ 64);
435 RecurrencePattern rp
= RecurrencePattern
.getYearNthRecurrencePattern(r
.getInterval(),
438 weekoffset
.shortValue(),
444 if (r
.getInterval() < 0) {
448 RecurrencePattern rp
= RecurrencePattern
.getYearlyRecurrencePattern(
456 fnblcontent
.setRecurrencePattern(rp
);
457 } catch (Exception ex
) {
458 ex
.printStackTrace();
464 com
.funambol
.common
.pim
.common
.Property prodid
=
465 new com
.funambol
.common
.pim
.common
.Property("-//BionicMessage Funambol Connector//ical4jFunambolconvert//EN");
466 fnblcal
.setProdId(prodid
);
467 com
.funambol
.common
.pim
.common
.Property ver
=
468 new com
.funambol
.common
.pim
.common
.Property("1.0");
469 fnblcal
.setVersion(ver
);
471 /* NOT YET CONVERTED: attach / attendee / exdate / exrule / geo / seq
475 public static void attachAllDayDtEnd(com
.funambol
.common
.pim
.calendar
.CalendarContent e
, String newValue
, String clientType
) {
476 if (clientType
.equals("text/x-vcalendar")) {
477 newValue
= newValue
+ "T240000";
478 com
.funambol
.common
.pim
.common
.Property dteprop
=
479 new com
.funambol
.common
.pim
.common
.Property(newValue
);
481 e
.getDtEnd().setPropertyValue(newValue
);
482 } else if (clientType
.equals("text/x-s4j-sife")) {
483 e
.getDtEnd().setPropertyValue(newValue
);
488 public static void attachAllDayDtStart(com
.funambol
.common
.pim
.calendar
.CalendarContent e
, String newValue
, String clientType
) {
489 if (clientType
.equals("text/x-vcalendar")) {
490 newValue
= newValue
+ "T000000";
491 com
.funambol
.common
.pim
.common
.Property dtsprop
=
492 new com
.funambol
.common
.pim
.common
.Property(newValue
);
494 e
.getDtStart().setPropertyValue(newValue
);
495 } else if (clientType
.equals("text/x-s4j-sife")) {
496 e
.getDtStart().setPropertyValue(newValue
);
501 /** Process any alarms in the event/todo. Since this functionality is optional,
502 * it is in another function
504 public static void attachAlarm(com
.funambol
.common
.pim
.calendar
.CalendarContent e
,
505 net
.fortuna
.ical4j
.model
.component
.CalendarComponent ical4je
) {
506 ComponentList alarms
= null;
507 if (ical4je
instanceof VEvent
) {
508 VEvent ve
= (VEvent
) ical4je
;
509 alarms
= ve
.getAlarms();
510 } else if (ical4je
instanceof VToDo
) {
511 VToDo vt
= (VToDo
) ical4je
;
512 alarms
= vt
.getAlarms();
516 Iterator alarmIterator
= alarms
.iterator();
517 while (alarmIterator
.hasNext()) {
518 VAlarm va
= (VAlarm
) alarmIterator
.next();
520 Trigger t
= va
.getTrigger();
521 String
[] dalarmComponents
= {"", "", "", ""};
522 if (va
.getAction().getValue().equals("DISPLAY")) {
523 if (t
.getDateTime() != null) {
524 dalarmComponents
[0] = t
.getDateTime().toString();
525 } else if (t
.getDuration() != null) {
526 Dur dur
= t
.getDuration();
527 DateProperty relatedTo
= null;
528 if (t
.getParameter(Related
.RELATED
) != null &&
529 t
.getParameter(Related
.RELATED
).equals(Related
.END
)) {
530 relatedTo
= (DateProperty
) ical4je
.getProperty(DtEnd
.DTEND
);
532 relatedTo
= (DateProperty
) ical4je
.getProperty(DtStart
.DTSTART
);
534 Date dt
= relatedTo
.getDate();
535 // Calculate a new DateTime relative to dt
536 java
.util
.Calendar cal
= java
.util
.Calendar
.getInstance();
538 cal
.add(java
.util
.Calendar
.SECOND
, -(dur
.getSeconds()));
539 cal
.add(java
.util
.Calendar
.MINUTE
, -(dur
.getMinutes()));
540 cal
.add(java
.util
.Calendar
.HOUR
, -(dur
.getHours()));
541 cal
.add(java
.util
.Calendar
.DAY_OF_YEAR
, -(dur
.getDays()));
542 cal
.add(java
.util
.Calendar
.WEEK_OF_YEAR
, -(dur
.getWeeks()));
543 DateTime newDate
= new DateTime(cal
.getTime());
544 newDate
.setUtc(true);
545 dalarmComponents
[0] = newDate
.toString();
548 StringBuffer buf
= new StringBuffer();
549 for (int i
= 0; i
< dalarmComponents
.length
; i
++) {
550 if (dalarmComponents
[i
] != null) {
551 buf
.append(dalarmComponents
[i
]);
553 if (dalarmComponents
.length
!= i
- 1) {
557 e
.setDAlarm(new com
.funambol
.common
.pim
.common
.Property(buf
.toString()));
560 /** Standalone tester */
561 public static void main(String args
[]) {
562 if (args
.length
< 1) {
563 System
.err
.println("Arguments: ical4j2funambol <file.ics>");
567 String file
= args
[0];
568 FileInputStream fis
= new FileInputStream(file
);
569 CalendarBuilder cbuild
= new CalendarBuilder();
570 Calendar ics
= cbuild
.build(fis
);
571 com
.funambol
.common
.pim
.calendar
.Calendar fnblcal
=
572 ical4j2funambol
.convertIcal4jToFunambolEvent(ics
, "text/x-vcalendar");
573 VCalendarConverter vcc
= new VCalendarConverter(null, "UTF-8");
574 VCalendar vc
= vcc
.calendar2vcalendar(fnblcal
, true);
575 System
.out
.println(vc
.toString());
576 } catch (Exception e
) {