1 var EXPORTED_SYMBOLS = [ "fburl" ]; 2 3 const Cc = Components.classes; 4 const Ci = Components.interfaces; 5 const Cu = Components.utils; 6 7 Cu.import("resource://calendar/modules/calUtils.jsm"); 8 Cu.import("resource://calendar/modules/calIteratorUtils.jsm"); 9 Cu.import("resource:///modules/mailServices.js"); 10 Cu.import("resource://gre/modules/XPCOMUtils.jsm"); 11 12 if ("undefined" == typeof(fburl)) { 13 var fburl = {}; 14 }; 15 16 const calIFreeBusyInterval = Ci.calIFreeBusyInterval; 17 const calIDateTime = Ci.calIDateTime; 18 19 fburl.fbUrlProvider = function(cal) { 20 this.cal = cal; 21 this._query = null; 22 this._context = null; 23 this._result = null; 24 this._searched = false; 25 this._error = null; 26 this._listener = null; 27 this._url = null; 28 this._calId = null; 29 this._periods = null; 30 }; 31 32 fburl.fbUrlProvider.prototype = { 33 classID: Components.ID("{11291d94-b457-4322-bfba-ae9df4b6a3c1}"), 34 35 getFreeBusyIntervals: function (aCalId, aRangeStart, aRangeEnd, aBusyTypes, aListener) { 36 37 this._listener = aListener; 38 this._calId = aCalId; 39 this._periods = null; 40 this.startSearch(aCalId); 41 }, 42 43 getLDAPAddressBooks: function () { 44 45 var abManager = Cc["@mozilla.org/abmanager;1"].getService(Ci.nsIAbManager); 46 var allAddressBooks = abManager.directories; 47 var books = []; 48 49 while (allAddressBooks.hasMoreElements()) { 50 var addressBook = allAddressBooks.getNext().QueryInterface(Ci.nsIAbDirectory); 51 if (addressBook instanceof Ci.nsIAbLDAPDirectory) { 52 books.push(addressBook); 53 } 54 } 55 56 return books; 57 }, 58 59 startSearch: function (aCalId) { 60 61 var service = Cc["@mozilla.org/network/ldap-service;1"].getService(Ci.nsILDAPService); 62 var books = this.getLDAPAddressBooks(); 63 64 this._result = null; 65 aCalId = aCalId.replace(/^mailto:/i, ""); 66 67 for each (var book in books) { 68 var ldap = book.QueryInterface(Ci.nsIAbLDAPDirectory); 69 var attrmap = Cc["@mozilla.org/addressbook/ldap-attribute-map;1"].createInstance(Ci.nsIAbLDAPAttributeMap); 70 var args = Cc["@mozilla.org/addressbook/directory/query-arguments;1"].createInstance(Ci.nsIAbDirectoryQueryArguments); 71 72 attrmap.setAttributeList("PrimaryEmail", "mail", true); 73 attrmap.setAttributeList("FBURL", "calFbUrl", true); 74 args.filter = service.createFilter(aCalId.length * 2, "(%a=%v)", "", "", "mail", aCalId); 75 args.typeSpecificArg = attrmap; 76 args.querySubDirectories = true; 77 78 this._query = Cc["@mozilla.org/addressbook/ldap-directory-query;1"].createInstance(Ci.nsIAbDirectoryQuery); 79 this._context = this._query.doQuery(ldap, args, this, ldap.maxHits, 0); 80 this._searched = true; 81 82 // NOTE: Do only one query for now. 83 84 break; 85 } 86 }, 87 88 stopSearch: function stopSearch() { 89 if (this._context) { 90 this._query.stopQuery(this._context); 91 this._context = null; 92 this._listener = null; 93 } 94 }, 95 96 onSearchFinished: function (aResult, aErrorMsg) { 97 this._context = null; 98 this._error = aErrorMsg; 99 }, 100 101 onSearchFoundCard: function (aCard) { 102 103 this._result = aCard; 104 105 // Obtain the URL from the card. 106 107 this._url = aCard.getProperty("FBURL", ""); 108 109 // Retrieve the resource and parse it. 110 111 var parser = Cc["@mozilla.org/calendar/ics-service;1"].getService(Ci.calIICSService); 112 //var parser = Cc["@mozilla.org/calendar/ics-parser;1"].createInstance(Ci.calIIcsParser); 113 var service = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService); 114 var stream = Cc["@mozilla.org/scriptableinputstream;1"].createInstance(Ci.nsIScriptableInputStream); 115 var channel = service.newChannelFromURI(service.newURI(this._url, null, null)); 116 117 stream.init(channel.open()); 118 var resource = parser.parseICS(stream.read(-1), null); 119 120 // Obtain the free/busy periods. 121 122 this._periods = []; 123 var fbTypeMap = {}; 124 125 fbTypeMap["FREE"] = calIFreeBusyInterval.FREE; 126 fbTypeMap["BUSY"] = calIFreeBusyInterval.BUSY; 127 fbTypeMap["BUSY-UNAVAILABLE"] = calIFreeBusyInterval.BUSY_UNAVAILABLE; 128 fbTypeMap["BUSY-TENTATIVE"] = calIFreeBusyInterval.BUSY_TENTATIVE; 129 130 // Iterate over components in the response. 131 132 for (var comp in cal.ical.calendarComponentIterator(resource)) { 133 134 // Iterate over free/busy properties. 135 136 for (var fbProp in cal.ical.propertyIterator(comp, "FREEBUSY")) { 137 138 // Assign the stated type or busy otherwise. 139 140 var fbType = fbProp.getParameter("FBTYPE"); 141 142 if (fbType) { 143 fbType = fbTypeMap[fbType]; 144 } else { 145 fbType = calIFreeBusyInterval.BUSY; 146 } 147 148 var parts = fbProp.value.split("/"); 149 var begin = cal.createDateTime(parts[0]); 150 var end; 151 152 // Support durations. 153 154 if (parts[1].charAt(0) == "P") { 155 end = begin.clone(); 156 end.addDuration(cal.createDuration(parts[1])); 157 158 // Support plain datetimes. 159 160 } else { 161 end = cal.createDateTime(parts[1]); 162 } 163 164 interval = new cal.FreeBusyInterval(this._calId, fbType, begin, end); 165 this._periods.push(interval); 166 } 167 } 168 169 this._listener.onResult(null, this._periods); 170 }, 171 172 QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver, Ci.nsIAbDirSearchListener]) 173 }; 174 175 fburl.initProvider = function() { 176 cal.getFreeBusyService().addProvider(new fburl.fbUrlProvider(cal)); 177 } 178 179 fburl.test = function(aCalId) { 180 var fbp = new fburl.fbUrlProvider(cal); 181 fbp.startSearch(aCalId); 182 return fbp; 183 } 184 185 const NSGetFactory = XPCOMUtils.generateNSGetFactory([fburl.fbUrlProvider]);