├── LICENSE ├── README.md ├── index.js └── package.json /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 jachwe 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | node-caldav (Work-in-Progress) 2 | =========== 3 | 4 | A lightweight Node.JS Caldav Client 5 | 6 | Usage 7 | ----------- 8 | 9 | ```sh 10 | 11 | var caldav = require("node-caldav"); 12 | 13 | caldav.getList([caldav_baseurl],[username],[password],callback) 14 | 15 | caldav.getEvents([caldav_calendarurl],[username],[password],[startDate],[endDate],callback) 16 | 17 | ``` 18 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var https = require("https"); 4 | var xmljs = require("libxmljs"); 5 | 6 | module.exports = { 7 | 8 | /** 9 | * Get a list of Folders/Calendars from a given url 10 | * 11 | * @param {String} url 12 | * @param {String} user 13 | * @param {String} pass 14 | * @param {function} cb 15 | 16 | */ 17 | 18 | getList: function (url, user, pass, cb) { 19 | 20 | var urlparts = /(https?)\:\/\/(.*?):?(\d*)?(\/.*\/?)/gi.exec(url); 21 | var protocol = urlparts[1]; 22 | var host = urlparts[2]; 23 | var port = urlparts[3] || (protocol === "https" ? 443 : 80); 24 | var path = urlparts[4]; 25 | 26 | var xml = '\n' + 27 | ' \n' + 28 | ' \n' + 29 | ' \n' + 30 | ' \n' + 31 | ' '; 32 | 33 | var options = { 34 | rejectUnauthorized: false, 35 | hostname : host, 36 | port : port, 37 | path : path, 38 | method : 'PROPFIND', 39 | headers : { 40 | "Content-type" : "text/xml", 41 | "Content-Length": xml.length, 42 | "User-Agent" : "calDavClient", 43 | "Connection" : "close", 44 | "Depth" : "1" 45 | } 46 | }; 47 | 48 | if (user && pass) { 49 | var userpass = new Buffer(user + ":" + pass).toString('base64'); 50 | options.headers["Authorization"] = "Basic " + userpass; 51 | } 52 | 53 | 54 | var req = https.request(options, function (res) { 55 | var s = ""; 56 | res.on('data', function (chunk) { 57 | s += chunk; 58 | }); 59 | 60 | req.on('close', function () { 61 | var reslist = []; 62 | try { 63 | var xmlDoc = xmljs.parseXml(s); 64 | // console.log(xmlDoc.toString() ); 65 | var resp = xmlDoc.find("a:response", { a: 'DAV:'}); 66 | for (var i in resp) { 67 | var el = resp[i]; 68 | var href = el.get("a:href", { a: 'DAV:'}); 69 | var dspn = el.get("a:propstat/a:prop/a:displayname", { a: 'DAV:'}); 70 | if (dspn) { 71 | var resobj = {}; 72 | resobj.displayName = dspn.text(); 73 | resobj.href = href.text(); 74 | reslist.push(resobj); 75 | } 76 | } 77 | } 78 | catch (e) { 79 | console.log("Error parsing response") 80 | } 81 | 82 | cb(reslist); 83 | 84 | }); 85 | }); 86 | 87 | req.end(xml); 88 | 89 | req.on('error', function (e) { 90 | console.log('problem with request: ' + e.message); 91 | }); 92 | 93 | }, 94 | 95 | /** 96 | * Get a list of Events from a given Calendarurl 97 | * 98 | * @param {String} url 99 | * @param {String} user 100 | * @param {String} pass 101 | * @param {String} date from which to start like 20140101T120000Z 102 | * @param {String} date from which to stop like 20140102T120000Z, optional (can be undefined) 103 | * @param {function} cb 104 | 105 | */ 106 | getEvents: function (url, user, pass, start, end, cb) { 107 | 108 | var urlparts = /(https?)\:\/\/(.*?):?(\d*)?(\/.*\/?)/gi.exec(url); 109 | var protocol = urlparts[1]; 110 | var host = urlparts[2]; 111 | var port = urlparts[3] || (protocol === "https" ? 443 : 80); 112 | var path = urlparts[4]; 113 | var endTimeRange = (end) ? ' end="'+end+'"' : ""; 114 | 115 | var xml = '\n' + 116 | '\n' + 117 | ' \n' + 118 | ' \n' + 119 | ' \n' + 120 | ' \n' + 121 | ' \n' + 122 | ' \n' + 123 | ' \n' + 124 | ' \n' + 125 | ' \n' + 126 | ' \n' + 127 | ''; 128 | 129 | var options = { 130 | rejectUnauthorized: false, 131 | hostname : host, 132 | port : port, 133 | path : path, 134 | method : 'REPORT', 135 | headers : { 136 | "Content-type" : "text/xml", 137 | "Content-Length": xml.length, 138 | "User-Agent" : "calDavClient", 139 | "Connection" : "close", 140 | "Depth" : "1" 141 | } 142 | }; 143 | 144 | if (user && pass) { 145 | var userpass = new Buffer(user + ":" + pass).toString('base64'); 146 | options.headers["Authorization"] = "Basic " + userpass; 147 | } 148 | 149 | var req = https.request(options, function (res) { 150 | var s = ""; 151 | res.on('data', function (chunk) { 152 | s += chunk; 153 | }); 154 | 155 | req.on('close', function () { 156 | var reslist = []; 157 | try { 158 | var xmlDoc = xmljs.parseXml(s); 159 | // console.log(xmlDoc.toString() ); 160 | var data = xmlDoc.find("a:response/a:propstat/a:prop/c:calendar-data", { a: 'DAV:', c: "urn:ietf:params:xml:ns:caldav" }); 161 | for (var i in data) { 162 | var ics = data[i].text(); 163 | var evs = ics.match(/BEGIN:VEVENT[\s\S]*END:VEVENT/gi); 164 | for (var x in evs) { 165 | var evobj = {}; 166 | var evstr = evs[x]; 167 | evstr = evstr.split("\n"); 168 | for (var y in evstr) { 169 | var evpropstr = evstr[y]; 170 | if (evpropstr.match(/BEGIN:|END:/gi)) { 171 | continue; 172 | } 173 | var sp = evpropstr.split(":"); 174 | var key = sp[0]; 175 | var val = sp[1]; 176 | if (key && val) { 177 | evobj[key] = val; 178 | } 179 | 180 | } 181 | reslist.push(evobj) 182 | } 183 | 184 | } 185 | cb(reslist); 186 | } 187 | catch (e) { 188 | console.log("Error parsing response") 189 | } 190 | 191 | }); 192 | }); 193 | 194 | req.end(xml); 195 | 196 | req.on('error', function (e) { 197 | console.log('problem with request: ' + e.message); 198 | }); 199 | 200 | } 201 | }; 202 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-caldav", 3 | "version": "0.0.2", 4 | "description": "A lightweight node.js Caldav Client", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/jachwe/node-caldav.git" 12 | }, 13 | "keywords": [ 14 | "caldav", 15 | "calendar", 16 | "json", 17 | "ics" 18 | ], 19 | "dependencies": { 20 | "libxmljs": "0.10.0" 21 | }, 22 | "author": "Jewe Pasch", 23 | "license": "MIT", 24 | "bugs": { 25 | "url": "https://github.com/jachwe/node-caldav/issues" 26 | }, 27 | "homepage": "https://github.com/jachwe/node-caldav" 28 | } 29 | --------------------------------------------------------------------------------