1 /* -*- Mode: javascript; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 *
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
9 *
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
14 *
15 * The Original Code is Sun Microsystems code.
16 *
17 * The Initial Developer of the Original Code is
18 * Sun Microsystems, Inc.
19 * Portions created by the Initial Developer are Copyright (C) 2007
20 * the Initial Developer. All Rights Reserved.
21 *
22 * Contributor(s):
23 * Daniel Boelzle <daniel.boelzle@sun.com>
24 * Philipp Kewisch <mozilla@kewis.ch>
25 *
26 * Alternatively, the contents of this file may be used under the terms of
27 * either the GNU General Public License Version 2 or later (the "GPL"), or
28 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
37 *
38 * ***** END LICENSE BLOCK ***** */
39
calWcapCalendar
40 function calWcapCalendar(/*optional*/session, /*optional*/calProps) {
41 this.initProviderBase();
42 this.m_session = session;
43 this.m_calProps = calProps;
44 }
45 calWcapCalendar.prototype = {
46 __proto__: calProviderBase.prototype,
47
48 m_ifaces: [ calIWcapCalendar,
49 calICalendar,
50 Components.interfaces.calIChangeLog,
51 Components.interfaces.calICalendarProvider,
52 Components.interfaces.nsIInterfaceRequestor,
53 Components.interfaces.nsIClassInfo,
54 nsISupports ],
55
56 // nsISupports:
calWcapCalendar_QueryInterface
57 QueryInterface: function calWcapCalendar_QueryInterface(iid) {
58 return doQueryInterface(this, calWcapCalendar.prototype, iid, this.m_ifaces, this);
59 },
60
61 // nsIClassInfo:
calWcapCalendar_getInterfaces
62 getInterfaces: function calWcapCalendar_getInterfaces(count) {
63 count.value = this.m_ifaces.length;
64 return this.m_ifaces;
65 },
get_classDescription
66 get classDescription() {
67 return calWcapCalendarModule.WcapCalendarInfo.classDescription;
68 },
get_contractID
69 get contractID() {
70 return calWcapCalendarModule.WcapCalendarInfo.contractID;
71 },
get_classID
72 get classID() {
73 return calWcapCalendarModule.WcapCalendarInfo.classID;
74 },
calWcapCalendar_getHelperForLanguage
75 getHelperForLanguage: function calWcapCalendar_getHelperForLanguage(language) { return null; },
76 implementationLanguage: Components.interfaces.nsIProgrammingLanguage.JAVASCRIPT,
77 flags: 0,
78
79 // nsIInterfaceRequestor:
calWcapCalendar_getInterface
80 getInterface: function calWcapCalendar_getInterface(iid, instance)
81 {
82 if (iid.equals(Components.interfaces.nsIAuthPrompt)) {
83 // use the window watcher service to get a nsIAuthPrompt impl
84 return getWindowWatcher().getNewAuthPrompter(null);
85 }
86 else if (iid.equals(Components.interfaces.nsIPrompt)) {
87 // use the window watcher service to get a nsIPrompt impl
88 return getWindowWatcher().getNewPrompter(null);
89 }
90 Components.returnCode = Components.results.NS_ERROR_NO_INTERFACE;
91 return null;
92 },
93
calWcapCalendar_toString
94 toString: function calWcapCalendar_toString() {
95 var str = this.session.toString();
96 if (this.m_calId)
97 str += (", calId=" + this.calId);
98 else
99 str += ", default calendar";
100 return str;
101 },
calWcapCalendar_notifyError_
102 notifyError_: function calWcapCalendar_notifyError_(err, context, suppressOnError)
103 {
104 var msg;
105 var rc = getResultCode(err);
106 switch (rc) {
107 case calIErrors.OPERATION_CANCELLED:
108 case calIWcapErrors.WCAP_COMPONENT_NOT_FOUND:
109 case NS_ERROR_OFFLINE:
110 return;
111 default:
112 if (!checkErrorCode(rc, calIErrors.WCAP_ERROR_BASE, 8) &&
113 (getErrorModule(rc) != NS_ERROR_MODULE_NETWORK)) {
114 msg = logError(err, context);
115 break;
116 }
117 // fallthru intended
118 case calIErrors.CAL_IS_READONLY:
119 // don't bloat the js error console with these errors, just log:
120 msg = errorToString(err);
121 log("error: " + msg, context);
122 break;
123 }
124 if (!suppressOnError) {
125 this.notifyObservers("onError",
126 err instanceof Components.interfaces.nsIException
127 ? [err.result, err.message] : [isNaN(err) ? -1 : err, msg]);
128 }
129 },
calWcapCalendar_notifyError
130 notifyError: function calWcapCalendar_notifyError(err, suppressOnError) {
131 this.notifyError_(err, this, suppressOnError);
132 },
133
134 // calICalendarProvider:
get_prefChromeOverlay
135 get prefChromeOverlay() {
136 return null;
137 },
138 // displayName attribute already part of calIWcapCalendar
calWcapCalendar_createCalendar
139 createCalendar: function calWcapCalendar_createCalendar(name, url, listener) {
140 throw NS_ERROR_NOT_IMPLEMENTED;
141 },
calWcapCalendar_deleteCalendar
142 deleteCalendar: function calWcapCalendar_deleteCalendar(calendar, listener) {
143 throw NS_ERROR_NOT_IMPLEMENTED;
144 },
calWcapCalendar_getCalendar
145 getCalendar: function calWcapCalendar_getCalendar(url) {
146 throw NS_ERROR_NOT_IMPLEMENTED;
147 },
148
149 // calICalendar:
calWcapCalendar_nameGetter
150 get name calWcapCalendar_nameGetter() {
151 var name = this.getProperty("name");
152 if (!name) {
153 name = this.displayName;
154 }
155 return name;
156 },
calWcapCalendar_nameSetter
157 set name calWcapCalendar_nameSetter(aValue) {
158 return this.setProperty("name", aValue);
159 },
160
get_type
161 get type() { return "wcap"; },
162
163 m_uri: null,
get_uri
164 get uri() {
165 return this.m_uri;
166 },
set_uri
167 set uri(thatUri) {
168 this.m_uri = thatUri.clone();
169 var path = thatUri.path;
170 var qmPos = path.indexOf("?");
171 if (qmPos != -1) {
172 var pos = path.indexOf("?calid=", qmPos);
173 if (pos != -1) {
174 var start = (pos + "?calid=".length);
175 var end = path.indexOf("&", start);
176 this.m_calId = decodeURIComponent(
177 path.substring(start, end == -1 ? path.length : end));
178 }
179 }
180 return this.uri;
181 },
182
calWcapCalendar_getProperty
183 getProperty: function calWcapCalendar_getProperty(aName) {
184 var value = this.__proto__.__proto__.getProperty.apply(this, arguments);
185 switch (aName) {
186 case "cache.supported":
187 value = false; // until bug 412914 and bug 412606 are fixed
188 break;
189 case "private.wcapCalendar":
190 value = this;
191 break;
192 case "readOnly":
193 if (value === null) {
194 // tweak readOnly default to true for non-owned calendars:
195 value = (this.m_session && this.session.isLoggedIn && !this.isOwnedCalendar);
196 }
197 break;
198 case "calendar-main-in-composite":
199 if (value === null && !this.isDefaultCalendar) {
200 // tweak in-composite to false for secondary calendars:
201 value = false;
202 }
203 break;
204 case "capabilities.alarms.popup.supported":
205 // CS cannot store X-props reliably (thus writing X-MOZ stamps etc is not possible).
206 // Popup alarms not available no matter what; wtf.
207 value = false;
208 }
209 return value;
210 },
211
calWcapCalendar_notifyObservers
212 notifyObservers: function calWcapCalendar_notifyObservers(func, args) {
213 if (g_bShutdown) {
214 return;
215 }
216 this.observers.notify(func, args);
217 },
218
219 // xxx todo: batch currently not used
calWcapCalendar_startBatch
220 startBatch: function calWcapCalendar_startBatch() {
221 this.notifyObservers("onStartBatch");
222 },
calWcapCalendar_endBatch
223 endBatch: function calWcapCalendar_endBatch() {
224 this.notifyObservers("onEndBatch");
225 },
226
get_sendItipInvitations
227 get sendItipInvitations() {
228 return false;
229 },
230
get_canRefresh
231 get canRefresh() { return true; },
calWcapCalendar_refresh
232 refresh: function calWcapCalendar_refresh() {
233 log("refresh.", this);
234 // invalidate cached results:
235 delete this.m_cachedResults;
236 // notify about refreshed calendar:
237 this.notifyObservers("onLoad", [this]);
238 },
239
calWcapCalendar_issueNetworkRequest
240 issueNetworkRequest: function calWcapCalendar_issueNetworkRequest(
241 request, respFunc, dataConvFunc, wcapCommand, params, accessRights)
242 {
243 var this_ = this;
244 // - bootstrap problem: no cal_props, no access check, no default calId
245 // - assure being logged in, thus the default cal_props are available
246 // - every subscribed calendar will come along with cal_props
247 return this.session.getSessionId(
248 request,
249 function getSessionId_resp(err, sessionId) {
250 try {
251 if (err)
252 throw err;
253 this_.assureAccess(accessRights);
254 params += ("&calid=" + encodeURIComponent(this_.calId));
255 this_.session.issueNetworkRequest(
256 request, respFunc, dataConvFunc, wcapCommand, params);
257 }
258 catch (exc) {
259 request.execSubRespFunc(respFunc, exc);
260 }
261 });
262 },
263
264 // calIWcapCalendar:
265
266 m_session: null,
get_session
267 get session() {
268 if (!this.m_session) {
269 var uri = this.uri;
270 ASSERT(uri, "no URI set!");
271 var path = uri.path;
272 var qmPos = path.indexOf("?");
273 if (qmPos != -1) {
274 uri = uri.clone();
275 uri.path = path.substring(0, qmPos); // get rid of params
276 }
277 this.m_session = getWcapSessionFor(this, uri);
278 }
279 return this.m_session;
280 },
281
282 m_calId: null,
get_calId
283 get calId() {
284 if (this.m_calId)
285 return this.m_calId;
286 return this.session.defaultCalId;
287 },
288
get_ownerId
289 get ownerId() {
290 var ar = this.getCalProps("X-NSCP-CALPROPS-PRIMARY-OWNER");
291 if (ar.length == 0) {
292 var calId = this.calId;
293 log("cannot determine primary owner of calendar " + calId, this);
294 // fallback to calId prefix:
295 var nColon = calId.indexOf(":");
296 if (nColon >= 0)
297 calId = calId.substring(0, nColon);
298 return calId;
299 }
300 return ar[0];
301 },
302
get_description
303 get description() {
304 var ar = this.getCalProps("X-NSCP-CALPROPS-DESCRIPTION");
305 if (ar.length == 0) {
306 // fallback to display name:
307 return this.displayName;
308 }
309 return ar[0];
310 },
311
get_displayName
312 get displayName() {
313 var ar = this.getCalProps("X-NSCP-CALPROPS-NAME");
314 if (ar.length == 0) {
315 // fallback to common name:
316 ar = this.getCalProps("X-S1CS-CALPROPS-COMMON-NAME");
317 if (ar.length == 0) {
318 ar = [this.calId];
319 }
320 }
321 var name = ar[0];
322 var defaultCal = this.session.defaultCalendar;
323 if (defaultCal) {
324 var defName = (defaultCal.getProperty("account_name") ||
325 defaultCal.getProperty("name"));
326 if (defName) {
327 name += (" (" + defName + ")");
328 }
329 }
330 return name;
331 },
332
get_isOwnedCalendar
333 get isOwnedCalendar() {
334 if (this.isDefaultCalendar)
335 return true; // default calendar is owned
336 return (this.ownerId == this.session.userId);
337 },
338
get_isDefaultCalendar
339 get isDefaultCalendar() {
340 return !this.m_calId;
341 },
342
calWcapCalendar_getCalendarProperties
343 getCalendarProperties: function calWcapCalendar_getCalendarProperties(propName, out_count) {
344 var ret = this.getCalProps(propName);
345 out_count.value = ret.length;
346 return ret;
347 },
348
349 m_calProps: null,
calWcapCalendar_getCalProps
350 getCalProps: function calWcapCalendar_getCalProps(propName) {
351 if (!this.m_calProps) {
352 log("soft error: no calprops, most possibly not logged in.", this);
353 // throw new Components.Exception("No calprops available!",
354 // Components.results.NS_ERROR_NOT_AVAILABLE);
355 }
356 return filterXmlNodes(propName, this.m_calProps);
357 },
358
get_defaultTimezone
359 get defaultTimezone() {
360 var tzid = this.getCalProps("X-NSCP-CALPROPS-TZID");
361 if (tzid.length == 0) {
362 logError("defaultTimezone: cannot get X-NSCP-CALPROPS-TZID!", this);
363 return "UTC"; // fallback
364 }
365 return tzid[0];
366 },
367
calWcapCalendar_getAlignedTzid
368 getAlignedTzid: function calWcapCalendar_getAlignedTzid(tz) {
369 var tzid = tz.tzid;
370 // check whether it is one cs supports:
371 if (!tz.isUTC && !tz.isFloating && !compareObjects(tz.provider, this.session)) {
372 log("not a server timezone: " + tzid);
373 var prefix = getTimezoneService().tzidPrefix;
374 if (tzid.indexOf(prefix) == 0) {
375 // cut mozilla prefix: assuming that the latter string portion
376 // semantically equals the demanded timezone
377 tzid = tzid.substring(prefix.length);
378 }
379 }
380 if (!this.session.getTimezone(tzid)) {
381 // xxx todo: we could further on search for a matching region,
382 // e.g. CET (in TZNAME), but for now stick to
383 // user's default if not supported directly
384 var ret = this.defaultTimezone;
385 // use calendar's default:
386 log(tzid + " not supported, falling back to default: " + ret, this);
387 return ret;
388 }
389 return tzid;
390 },
391
calWcapCalendar_checkAccess
392 checkAccess: function calWcapCalendar_checkAccess(accessControlBits)
393 {
394 // xxx todo: take real acl into account
395 // for now, optimistically assuming that everybody has full access, server will check:
396 var granted = calIWcapCalendar.AC_FULL;
397 if (this.getProperty("readOnly")) {
398 granted &= ~(calIWcapCalendar.AC_COMP_WRITE |
399 calIWcapCalendar.AC_PROP_WRITE);
400 }
401 // check whether every bit fits:
402 return ((accessControlBits & granted) == accessControlBits);
403 },
404
calWcapCalendar_assureAccess
405 assureAccess: function calWcapCalendar_assureAccess(accessControlBits)
406 {
407 if (!this.checkAccess(accessControlBits & (calIWcapCalendar.AC_COMP_WRITE |
408 calIWcapCalendar.AC_PROP_WRITE))) {
409 // throw different error code for read-only:
410 throw new Components.Exception("Access denied!",
411 calIErrors.CAL_IS_READONLY);
412 }
413 if (!this.checkAccess(accessControlBits)) {
414 throw new Components.Exception("Access denied!",
415 calIWcapErrors.WCAP_ACCESS_DENIED_TO_CALENDAR);
416 // xxx todo: throwing different error here, no
417 // calIErrors.CAL_IS_READONLY anymore
418 }
419 },
420
calWcapCalendar_defineAccessControl
421 defineAccessControl: function calWcapCalendar_defineAccessControl(
422 userId, accessControlBits)
423 {
424 throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
425 },
426
calWcapCalendar_resetAccessControl
427 resetAccessControl: function calWcapCalendar_resetAccessControl(userId)
428 {
429 throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
430 },
431
calWcapCalendar_getAccessControlDefinitions
432 getAccessControlDefinitions: function calWcapCalendar_getAccessControlDefinitions(
433 out_count, out_users, out_accessControlBits)
434 {
435 throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
436 }
437 };