/usr/share/syncevolution/xml/scripting/11calendar.xml is in syncevolution-common 1.5.2-2.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 | <!-- define script macros for scripts that are used by both vCalendar 1.0 and iCalendar 2.0 -->
<macro name="VCALENDAR_INCOMING_SCRIPT"><![CDATA[
STRING MATCHES[];
STRING CAT,CN,EM;
INTEGER i;
// Remove UID/RECURRENCE-ID from servers which do not support
// the semantic properly (for example, Funambol supports
// UID but drops RECURRENCE-ID, causing conflicts).
if (SESSIONVAR("stripUID")) {
UID = UNASSIGNED;
ORIGSTART = UNASSIGNED;
}
// make sure we have all trailing and leading spaces eliminated
DESCRIPTION=NORMALIZED(DESCRIPTION);
SUMMARY=NORMALIZED(SUMMARY);
// eliminate description that is the same as summary
if (DESCRIPTION==SUMMARY) DESCRIPTION=EMPTY;
// calendar or todo
if (ISEVENT) {
// VEVENT
// - handle duration cases
if (ISDURATION(DURATION)) {
if (DTEND==EMPTY) DTEND = DTSTART + DURATION;
if (DTSTART==EMPTY) DTSTART = DTEND - DURATION;
}
// - detect alldays in vCalendar 1.0 (0:00-0:00 or 23:59 localtime)
i = ALLDAYCOUNT(DTSTART,DTEND,TRUE);
if (ITEMDATATYPE()=="vCalendar10" && i>0) {
// DTSTART and DTEND represent allday event, make them date-only values
// - convert start to user zone (or floating) so it represents midnight
DTSTART = CONVERTTOUSERZONE(DTSTART);
MAKEALLDAY(DTSTART,DTEND,i);
if (RR_END != EMPTY) {
RR_END = DATEONLY(CONVERTTOUSERZONE(RR_END));
}
}
else {
// iCalendar 2.0 - only if DTSTART is a date-only value this really is an allday
if (ISDATEONLY(DTSTART)) {
// reshape to make sure we don't have invalid zero-duration alldays (old OCS 9 servers)
MAKEALLDAY(DTSTART,DTEND,i);
}
}
// Make sure that all EXDATE times are in the same timezone as the start
// time. Some servers send them as UTC, which is all fine and well, but
// only if the timezone definition doesn't change. Also, libical does not
// handle such UTC EXDATEs, so let's convert it while the UTC and
// time zone definition (hopefully) are in sync.
if (TIMEZONE(DTSTART) != "UTC" && !ISFLOATING(DTSTART)) {
i = 0;
timestamp exdate;
while (i<SIZE(EXDATES)) {
exdate = EXDATES[i];
if (!ISDATEONLY(exdate) &&
(TIMEZONE(exdate) == "UTC" || ISFLOATING(exdate))) {
// "unfloat" floating time stamps: not sure whether that occcurs
// in practice, but it looks as wrong as UTC EXDATEs
EXDATES[i] = CONVERTTOZONE(exdate,DTSTART,TRUE);
}
i=i+1;
}
}
// vCalendar1.0 has no VALUE=DATE EXDATEs, so convert back to that if
// the event is all-day.
if (ITEMDATATYPE()=="vCalendar10" && ISDATEONLY(DTSTART)) {
timestamp exdate;
i = 0;
while (i<SIZE(EXDATES)) {
exdate = EXDATES[i];
if (!ISDATEONLY(exdate)) {
exdate = CONVERTTOUSERZONE(exdate);
EXDATES[i] = DATEONLY(exdate);
}
i=i+1;
}
}
// Transform absolute alarm time back to relative time (mirrors the code in
// VCALENDAR_OUTGOING_SCRIPT, see also BMC #11233). This applies to all
// events, recurring or not, if the "alarmTimeToUTC" workaround is applied.
// With a peer which cannot distinguish between absolute and relative
// alarms we better treat all alarms as relative, because that is presented
// more nicely to the user on the local side.
if (ITEMDATATYPE()=="vCalendar10" &&
ALARM_TIME!=EMPTY &&
!ISDURATION(ALARM_TIME) &&
SESSIONVAR("alarmTimeToUTC")) {
ALARM_TIME = ALARM_TIME - DTSTART;
}
// - shape attendees (and make sure ATTENDEES[] is assigned even for empty email addresses)
i=0;
while(i<SIZE(ATTENDEES) || i<SIZE(ATTENDEE_CNS)) {
PARSEEMAILSPEC(ATTENDEES[i], CN, EM);
ATTENDEES[i] = EM; // pure email address
// in case we have no specific common name, use the one extracted from the email
// This catches the vCalendar 1.0 case and eventually ill-formed iCalendar 2.0 as well
if (ATTENDEE_CNS[i]==EMPTY)
ATTENDEE_CNS[i]=CN;
// default participation status to needs-action
if (ATTENDEE_PARTSTATS[i]==EMPTY)
ATTENDEE_PARTSTATS[i]=1; // 1=needs action
i=i+1;
}
// - shape organizer
PARSEEMAILSPEC(ORGANIZER, CN, EM);
ORGANIZER = EM; // pure email address
if (ORGANIZER_CN==EMPTY)
ORGANIZER_CN=CN;
}
else {
// VTODO
// - make sure we have at least a summary
if (SUMMARY==EMPTY) SUMMARY=DESCRIPTION; // use description if we don't have a summary
if (SUMMARY==EMPTY) SUMMARY="unnamed"; // set dummy summary if we still don't have one
// due shaping for non-iCalendar 2.0
if (ITEMDATATYPE()=="vCalendar10" && ALLDAYCOUNT(DUE,DUE,TRUE,TRUE)>0) {
DUE = CONVERTTOUSERZONE(DUE);
DUE = DATEONLY(DUE);
}
if (ITEMDATATYPE()=="vCalendar10") {
$VCALENDAR_10TO20_PRIORITY_CONVERSION;
}
}
// a workaround for funambol: adding 'action' for 'alarm'
// if item data type is vCalendar1.0, also add 'action' for 'alarm'.
// This is a workaround for Mobical.net, which uses vCalendar1.0.
if (ALARM_TIME!=EMPTY && ALARM_ACTION==EMPTY) {
ALARM_ACTION = "DISPLAY";
}
]]></macro>
<macro name="VCALENDAR_OUTGOING_SCRIPT"><![CDATA[
// set UTC time of generation for iCalendar 2.0 DTSTAMP
DGENERATED = NOW();
// make sure we have all trailing and leading spaces eliminated
DESCRIPTION=NORMALIZED(DESCRIPTION);
SUMMARY=NORMALIZED(SUMMARY);
if (ISEVENT) {
// VEVENT
// - combine attendee email address and common name into single string for vCalendar 1.0
if (ITEMDATATYPE()=="vCalendar10") {
i=0;
while(i<SIZE(ATTENDEES)) {
ATTENDEES[i] = MAKEEMAILSPEC(ATTENDEE_CNS[i], ATTENDEES[i]);
i=i+1;
}
ORGANIZER = MAKEEMAILSPEC(ORGANIZER_CN, ORGANIZER);
}
}
else {
// VTODO
// interal representation is iCalendar20
if (ITEMDATATYPE()=="vCalendar10") {
$VCALENDAR_20TO10_PRIORITY_CONVERSION;
}
}
// make sure we have at least a summary
if (SUMMARY==EMPTY) SUMMARY=SUBSTR(DESCRIPTION,0,32); // derive from description
if (SUMMARY==EMPTY) SUMMARY="unnamed"; // in case description is empty as well
// make sure that we have a DESCRIPTION, because some peers only support that;
// can be avoided for peers where we are certain (from CtCaps) that they can
// receive the text as part of the summary; don't do this for VJOURNAL
if (ISAVAILABLE(SUMMARY)!=TRUE && DESCRIPTION==EMPTY && ISEVENT != 2) DESCRIPTION=SUMMARY;
// do NOT send duration (some servers crash when doing so)
DURATION = UNASSIGNED;
// shape alarm
if (ALARM_TIME!=EMPTY) {
if (ITEMDATATYPE()=="iCalendar20") {
if (ALARM_ACTION==EMPTY) ALARM_ACTION = "AUDIO";
}
else {
if (ALARM_MSG==EMPTY) ALARM_MSG="alarm";
}
}
// for 'ALARM_TIME', convert duration time to UTC time
// This workaround is for Mobical.net which can't understand duration time.
// Also used with phones. The interpretation at least by Nokia
// is that the absolute alarm time repeats together with the
// event (BMC #11233). VCALENDAR_INCOMING_SCRIPT has the
// corresponding transformation back (important for recurring events).
if (SESSIONVAR("alarmTimeToUTC") && ITEMDATATYPE()=="vCalendar10"
&& ALARM_TIME!=EMPTY && ISDURATION(ALARM_TIME)) {
TIMESTAMP ts;
if (ALARM_REL==2)
ts = DTEND; // relative to end
else {
if (ISEVENT)
ts = DTSTART; // relative to start for events
else
ts = DUE; // relative to due for todos
}
ALARM_TIME = CONVERTTOUSERZONE(POINTINTIME(ts), TRUE) + ALARM_TIME;
ALARM_TIME = CONVERTTOZONE(ALARM_TIME, "UTC");
}
]]></macro>
<macro name="FIX_EXDATE_SCRIPT"><![CDATA[
// Add time zone information to EXDATEs: necessary for
// the Maemo calendar storages because it uses EXDATE
// without TZID.
if (!ISFLOATING(DTSTART)) {
STRING tz;
tz = TIMEZONE(DTSTART);
if (tz != "UTC") {
INTEGER i;
i = 0;
while (i<SIZE(EXDATES)) {
if (ISFLOATING(EXDATES[i])) {
SETTIMEZONE(EXDATES[i], tz);
}
i=i+1;
}
}
}
]]></macro>
<!-- Uses the UID/RECURRENCE-ID fields as the only criteria for
comparing calendar data if the parameter $1 (see GLOBALIDS in <initscript>)
is true, else does a normal comparison of the
fields. That comparison is based on the datatype definition
and ignores UID because it is not trusted to be
preserved and/or implemented by peers.
In case of a UID match, the DMODIFIED fields are compared
to determine the older item.
-->
<macro name="VCALENDAR_COMPARE_SCRIPT"><![CDATA[
INTEGER RES;
if (COMPARISONMODE() != "age" && SYNCMODESUPPORTED("1122583000")) {
if (TARGET.UID == REFERENCE.UID &&
TARGET.ORIGSTART == REFERENCE.ORIGSTART) {
RES = 0;
} else {
RES = -999;
}
} else {
RES = COMPAREFIELDS();
}
return RES;
]]></macro>
<!-- invoked when reading plain text memo from storage or receiving from peer -->
<macro name="MEMO_INCOMING_SCRIPT"><![CDATA[
ISEVENT = 2;
// Copy summary into description. It is not 100% certain whether that is
// necessary (the summary might be completely unrelated to the description text),
// but this way it is consistent with the way how the EDS backend used to handle
// it and symmetric with MEMO_OUTGOING_SCRIPT.
if (SUMMARY != EMPTY && DESCRIPTION != EMPTY) {
DESCRIPTION = SUMMARY + "\n" + DESCRIPTION;
}
]]></macro>
<!-- invoked before writing plain text memo into storage or sending to peer -->
<macro name="MEMO_OUTGOING_SCRIPT"><![CDATA[
// remove SUMMARY from start of DESCRIPTION before writing if text matches,
// because sending as plain text will concatenate them again
integer lensummary, lendescr;
lensummary = LENGTH(SUMMARY);
lendescr = LENGTH(DESCRIPTION);
if (lendescr >= lensummary &&
SUBSTR(DESCRIPTION, 0, lensummary) == SUMMARY &&
(lensummary == lendescr || SUBSTR(DESCRIPTION, lensummary, 1) == "\n")) {
DESCRIPTION = SUBSTR(DESCRIPTION, lensummary + 1, lendescr - lensummary - 1);
}
]]></macro>
<macro name="CALENDAR_BEFOREWRITE_SCRIPT"><![CDATA[
if (UID == EMPTY) { UID = newuid(); }
// set UTC time of generation for iCalendar 2.0 DTSTAMP
DGENERATED = NOW();
// ensure that there is a DMODIFIED = LAST-MODIFIED property,
// not all storages add it
if (!DMODIFIED) {
DMODIFIED = DGENERATED;
}
]]></macro>
|