summaryrefslogtreecommitdiff
path: root/content
diff options
context:
space:
mode:
authorGuido Günther <agx@sigxcpu.org>2013-04-26 18:42:04 +0200
committerGuido Günther <agx@sigxcpu.org>2013-04-26 20:18:59 +0200
commit51966d70165d3f48a228fec7c47c1d0001b19efe (patch)
tree26d391a7a19a1ecdc1467bb55812edecf14fe59d /content
Initial commitHEADmaster
Diffstat (limited to 'content')
-rw-r--r--content/caDNSResolver.js99
-rw-r--r--content/calendarAutoconfig.js161
-rw-r--r--content/calendarAutoconfigDialog.js11
-rw-r--r--content/calendarAutoconfigDialog.xul32
-rw-r--r--content/calendarOverlay.xul18
-rw-r--r--content/misc.js18
6 files changed, 339 insertions, 0 deletions
diff --git a/content/caDNSResolver.js b/content/caDNSResolver.js
new file mode 100644
index 0000000..f6b029f
--- /dev/null
+++ b/content/caDNSResolver.js
@@ -0,0 +1,99 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * (C) 2013 Guido Günther <agx@sigxcpu.org>
+ */
+
+Components.utils.import("resource://gre/modules/ctypes.jsm");
+const GError = ctypes.StructType("GError");
+const GCancellable = ctypes.StructType("GCancellable");
+const GResolver = ctypes.StructType("GResolver");
+const GSrvTarget = ctypes.StructType("GSrvTarget");
+const gpointer = ctypes.void_t.ptr;
+
+var gioExist = false;
+try {
+ var glib = ctypes.open("libglib-2.0.so.0");
+ var gobject = ctypes.open("libgobject-2.0.so.0");
+ var gio = ctypes.open("libgio-2.0.so.0");
+ gioExist = true;
+} catch (ex) {
+ Components.utils.reportError("Failed to load gio: " + ex);
+}
+
+if (gioExist) {
+ caDNSResolver = function() {
+ this.gpointer = ctypes.void_t.ptr;
+ this._GList = new ctypes.StructType("_GList");
+ this._GList.define([{data: this.gpointer},
+ {next: this._GList.ptr},
+ {prev: this._GList.ptr}]);
+ this.GList = this._GList;
+
+ this.g_resolver_lookup_service = gio.declare(
+ "g_resolver_lookup_service",
+ ctypes.default_abi,
+ this.GList.ptr, // return type: GList
+ GResolver.ptr, // in: the resolver to use
+ ctypes.char.ptr, // in: the service of look for
+ ctypes.char.ptr, // in: the protocol the service should use
+ ctypes.char.ptr, // in: the domain the service is offerd in
+ GCancellable.ptr, // in: the cancellable
+ GError.ptr.ptr // out: error
+ );
+
+ this.g_srv_target_get_hostname = gio.declare(
+ "g_srv_target_get_hostname",
+ ctypes.default_abi,
+ ctypes.char.ptr, // return type: string
+ GSrvTarget.ptr // in: Record to parse
+ );
+
+ this.g_resolver_get_default = gio.declare(
+ "g_resolver_get_default",
+ ctypes.default_abi,
+ GResolver.ptr // return type: GResolver
+ );
+
+ this.g_resolver_free_targets = gio.declare(
+ "g_resolver_free_targets",
+ ctypes.default_abi,
+ ctypes.void_t,
+ this.GList.ptr // in: List of GSrvTargets
+ );
+
+ this._resolver = this.g_resolver_get_default();
+
+ this.get_srv_records = function (service, proto, domain) {
+ var ret = [];
+ var records = this.g_resolver_lookup_service(this._resolver,
+ service,
+ proto,
+ domain,
+ null,
+ null);
+ if (records.isNull()) {
+ Components.utils.reportError("Failed to lookup: " + service);
+ return [];
+ } else {
+ Components.utils.reportError("records: " + records);
+ // For PoC just look at the first record
+ // and ignore weight and prio
+ var tmp = records.contents.data;
+ var rec = ctypes.cast(tmp, GSrvTarget.ptr);
+ var val = this.g_srv_target_get_hostname (rec);
+ ret[0] = val.readString();
+ Components.utils.reportError("ret: " + ret);
+ this.g_resolver_free_targets(records);
+ }
+ return ret;
+ };
+ };
+} else {
+ caDNSResolver = function() {
+ this.get_srv_records = function (service, proto, domain) {
+ return null;
+ };
+ };
+}
diff --git a/content/calendarAutoconfig.js b/content/calendarAutoconfig.js
new file mode 100644
index 0000000..8a683c0
--- /dev/null
+++ b/content/calendarAutoconfig.js
@@ -0,0 +1,161 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * (C) 2013 Guido Günther <agx@sigxcpu.org>
+ */
+
+Components.utils.import("resource://calendar/modules/calUtils.jsm");
+
+caCalendarAutoconfig = function (aDocument, aWindow)
+{
+ this._document = aDocument;
+ this._window = aWindow;
+
+ /* The user as uri */
+ this._uri = null;
+
+ /* The calendar server */
+ this._proto = null;
+ this._host = null;
+ this._path = null;
+}
+
+caCalendarAutoconfig.prototype = {
+ parse_uri: function (aUri)
+ {
+ /* Check if it's a valid URI */
+ try {
+ var uri = cal.makeURL(aUri);
+ } catch (ex) {
+ var msg = "Invalid uri " + aUri;
+ caError(msg + " " + ex);
+ throw msg;
+ }
+
+ if (uri.scheme != 'email') {
+ throw aUri + "not a email uri";
+ }
+ this._domain = aUri.split('@')[1];
+ },
+
+ /* Query DNS SRV and TXT records */
+ query_dns: function() {
+ var proto = 'tcp';
+ var service = this.type + 's';
+ /* Currently not possible using a xulrunner interface:
+ * #14328, #545866, #735967 */
+ var resolver = new caDNSResolver();
+
+ caDebug("Checking SRV records for " + [this._domain,
+ proto,
+ service,
+ ].join(" "));
+ var records = resolver.get_srv_records(service,
+ proto,
+ this._domain);
+ caDebug("Got service records: " + records);
+ if (records[0]) {
+ this._host = records[0];
+ this._proto = 'https://';
+ }
+
+ /*
+ * FIXME: check TXT records for path
+ * this._path = ...
+ */
+ },
+
+ detect_calendar: function(aUri)
+ {
+ this.parse_uri(aUri);
+ this._uri = aUri;
+ this.query_dns();
+
+ if (this._host == null) {
+ this._host = this._domain;
+ }
+ if (this._path == null) {
+ this._path = '/.well-known/' + this.type;
+ }
+ return this.check_calendar();
+ },
+
+ _register_calendar: function(aURL, calname) {
+ caDebug("Registering " + calname + " calendar for " + aURL);
+ var uri = cal.makeURL(aURL);
+ var newCal = cal.getCalendarManager().createCalendar('ics', uri);
+ newCal.name = calname;
+ cal.getCalendarManager().registerCalendar(newCal);
+ }
+};
+
+/* CalDAV */
+function caCaldavAutoconfig(document, window) {
+ /* FIXME: handle basic auth, parse dav properties after
+ * DAV:current-user-principal
+ * request.open("GET", url, true);
+ * FIXME: use principal-URL to detect "home" collections
+ * request.send(null);
+ */
+ this.type = 'caldav';
+}
+caCaldavAutoconfig.prototype = new caCalendarAutoconfig;
+caCaldavAutoconfig.prototype.check_calendar = function() {
+ return false;
+}
+
+function makeURI(aURL, aOriginCharset, aBaseURI) {
+ var ioService = Components.classes["@mozilla.org/network/io-service;1"]
+ .getService(Components.interfaces.nsIIOService);
+ return ioService.newURI(aURL, aOriginCharset, aBaseURI);
+}
+
+/* WebCal */
+function caWebcalAutoconfig(document, window) {
+ this.type = 'webcal';
+}
+caWebcalAutoconfig.prototype = new caCalendarAutoconfig;
+caWebcalAutoconfig.prototype.check_calendar = function() {
+ this._proto = this._proto || 'https://';
+
+ var url = this._proto + this._host + this._path;
+ var calName = this._uri;
+ caDebug("Looking for calendar at " + url);
+
+ var request = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"]
+ .createInstance(Components.interfaces.nsIXMLHttpRequest);
+
+ request.onload = function (e) {
+ if (request.readyState === 4) {
+ if (request.status === 200) {
+ if (request.getResponseHeader('Content-Type') == 'text/calendar') {
+ this._register_calendar(url, calName);
+ } else {
+ caDebug("Not a calendar: " + request.getResponseHeader('Content-Type'));
+ /* FIXME: Check collection for .ics files */
+ }
+ } else {
+ caDebug(request.statusText);
+ }
+ }
+ }.bind(this);
+
+ request.onerror = function (e) {
+ caDebug("Calendar detection failed " + e);
+ };
+
+ request.open("GET", url, true);
+ request.send(null);
+}
+
+
+function do_calendarAutoconfig(aUri) {
+ caDebug(aUri);
+
+ caldav = new caCaldavAutoconfig(document, window);
+ if (! caldav.detect_calendar(aUri)) {
+ webcal = new caWebcalAutoconfig(document, window);
+ webcal.detect_calendar(aUri);
+ }
+}
diff --git a/content/calendarAutoconfigDialog.js b/content/calendarAutoconfigDialog.js
new file mode 100644
index 0000000..237326e
--- /dev/null
+++ b/content/calendarAutoconfigDialog.js
@@ -0,0 +1,11 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * (C) 2013 Guido Günther <agx@sigxcpu.org>
+ */
+
+show_calendarAutoconfigDialog = function() {
+ window.openDialog("chrome://autoconfig/content/calendarAutoconfigDialog.xul","showmore",
+ "chrome",null);
+}
diff --git a/content/calendarAutoconfigDialog.xul b/content/calendarAutoconfigDialog.xul
new file mode 100644
index 0000000..6320043
--- /dev/null
+++ b/content/calendarAutoconfigDialog.xul
@@ -0,0 +1,32 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin/global.css" type="text/css"?>
+<dialog id="calendar-autoconfig-dialog" title="Calendar Autoconfiguration"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ buttons="accept,cancel"
+ ondialogaccept="return doOK();"
+ ondialogcancel="return doCancel();">
+
+ <script src="calendarAutoconfig.js"/>
+ <script src="caDNSResolver.js"/>
+ <script src="misc.js"/>
+
+ <script>
+ function doOK() {
+ email = document.getElementById("calendar-autoconfig-email").value
+ do_calendarAutoconfig('email:' + email);
+ return true;
+ }
+
+ function doCancel(){
+ return true;
+ }
+ </script>
+
+ <dialogheader title="Calendar Autoconfiguration"
+ description="Autoconfigure CalDAV and WebCal calenders"/>
+
+ <vbox>
+ <label control="calendar-autoconfig-email" value="EMail:"/>
+ <textbox value="agx@sigxcpu.org" id="calendar-autoconfig-email"/>
+ </vbox>
+</dialog>
diff --git a/content/calendarOverlay.xul b/content/calendarOverlay.xul
new file mode 100644
index 0000000..b58776f
--- /dev/null
+++ b/content/calendarOverlay.xul
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE overlay SYSTEM "chrome://autoconfig/locale/autoconfig.dtd">
+<overlay id="autoconfig-overlay"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script src="misc.js"/>
+ <script src="calendarAutoconfigDialog.js"/>
+ <script src="calendarAutoconfig.js"/>
+
+ <menupopup id="menu_FilePopup">
+ <menuitem id="calendar-auto-config"
+ label="Calendar Autoconfiguration..."
+ observes="cmd_calendarAutoconfig"
+ insertafter="calendar-addserver-menu" />
+ </menupopup>
+
+ <commandset><command id="cmd_calendarAutoconfig" oncommand="show_calendarAutoconfigDialog();"/></commandset>
+</overlay>
diff --git a/content/misc.js b/content/misc.js
new file mode 100644
index 0000000..edabe1b
--- /dev/null
+++ b/content/misc.js
@@ -0,0 +1,18 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * (C) 2013 Guido Günther <agx@sigxcpu.org>
+ */
+
+function caDebug(aText)
+{
+ var csClass = Components.classes['@mozilla.org/consoleservice;1'];
+ var cs = csClass.getService(Components.interfaces.nsIConsoleService);
+ cs.logStringMessage(aText);
+}
+
+function caError(aText)
+{
+ Components.utils.reportError(aText);
+}