1 /* ***** BEGIN LICENSE BLOCK *****
  2  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  3  *
  4  * The contents of this file are subject to the Mozilla Public License Version
  5  * 1.1 (the "License"); you may not use this file except in compliance with
  6  * the License. You may obtain a copy of the License at
  7  * http://www.mozilla.org/MPL/
  8  *
  9  * Software distributed under the License is distributed on an "AS IS" basis,
 10  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 11  * for the specific language governing rights and limitations under the
 12  * License.
 13  *
 14  * The Original Code is gContactSync.
 15  *
 16  * The Initial Developer of the Original Code is
 17  * Josh Geenen <gcontactsync@pirules.org>.
 18  * Portions created by the Initial Developer are Copyright (C) 2008-2010
 19  * the Initial Developer. All Rights Reserved.
 20  *
 21  * Contributor(s):
 22  *
 23  * Alternatively, the contents of this file may be used under the terms of
 24  * either the GNU General Public License Version 2 or later (the "GPL"), or
 25  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 26  * in which case the provisions of the GPL or the LGPL are applicable instead
 27  * of those above. If you wish to allow use of your version of this file only
 28  * under the terms of either the GPL or the LGPL, and not to allow others to
 29  * use your version of this file under the terms of the MPL, indicate your
 30  * decision by deleting the provisions above and replace them with the notice
 31  * and other provisions required by the GPL or the LGPL. If you do not delete
 32  * the provisions above, a recipient may use your version of this file under
 33  * the terms of any one of the MPL, the GPL or the LGPL.
 34  *
 35  * ***** END LICENSE BLOCK ***** */
 36 
 37 if (!com) var com = {}; // A generic wrapper variable
 38 // A wrapper for all GCS functions and variables
 39 if (!com.gContactSync) com.gContactSync = {};
 40 
 41 /**
 42  * An object that can obtain address books by the name or URI, find the synced
 43  * address books, and edit contacts.
 44  * @extends com.gContactSync.AbManager
 45  * @class
 46  */
 47 com.gContactSync.GAbManager = com.gContactSync.AbManager;
 48 
 49 /** Stores GAddressBook objects keyed by preference ID *AND* URI */
 50 com.gContactSync.GAbManager.mABs = {};
 51 
 52 /**
 53  * Resets all synchronized address books in the following ways:
 54  *  - Deletes all mailing lists
 55  *  - Deletes all contacts
 56  *  - Sets the last sync date to 0.
 57  * See AddressBook.reset for more details.
 58  *
 59  * It asks the user to restart Thunderbird when finished.
 60  *
 61  * @param showConfirm {boolean} Show a confirmation dialog first and quit if
 62  * the user presses Cancel.
 63  */
 64 com.gContactSync.GAbManager.resetAllSyncedABs =
 65 function GAbManager_resetSyncedABs(showConfirm) {
 66   if (showConfirm) {
 67     if (!com.gContactSync.confirm(com.gContactSync.StringBundle.getStr("confirmReset"))) {
 68       return false;
 69     }
 70   }
 71 
 72   com.gContactSync.LOGGER.LOG("Resetting all synchronized directories.");
 73   var abs = com.gContactSync.GAbManager.getSyncedAddressBooks(true),
 74       i,
 75       needRestart = false;;
 76   for (i in abs) {
 77     if (abs[i].ab && abs[i].ab.mPrefs.Disabled !== "true") {
 78       needRestart = abs[i].ab.reset() || needRestart;
 79     }
 80   }
 81   
 82   com.gContactSync.LOGGER.LOG("Finished resetting all synchronized directories.");
 83   if (needRestart) {
 84     com.gContactSync.alert(com.gContactSync.StringBundle.getStr("pleaseRestart"));
 85   }
 86   return true;
 87 };
 88 /**
 89  * Returns an object filled with GAddressBook objects.
 90  * The properties are the names of those address books.
 91  * @param aMakeArray {boolean} If this parameter evaluates as true then the
 92  *                             returned object will be an array.
 93  * @returns If aMakeArray then the returned object is an array of objects.
 94  *         Each object has a 'username' property with the username of this
 95  *         synced AB and an 'ab' property with a GAddressBook object.
 96  *         If !aMakeArray then the returned object is keyed by username and
 97  *         the value of that property is an array of GAddressBook objects.
 98  */
 99 com.gContactSync.GAbManager.getSyncedAddressBooks =
100 function AbManager_getSyncedAddressBooks(aMakeArray) {
101   this.mAddressBooks = {};
102   var iter,
103       abManager,
104       dir,
105       data,
106       ab,
107       username,
108       arr = [],
109       i,
110       j;
111   if (Components.classes["@mozilla.org/abmanager;1"]) { // TB 3
112     abManager = Components.classes["@mozilla.org/abmanager;1"]
113                           .getService(Components.interfaces.nsIAbManager);
114     iter = abManager.directories;
115   }
116   else { // TB 2
117     // obtain the main directory through the RDF service
118     dir = Components.classes["@mozilla.org/rdf/rdf-service;1"]
119                     .getService(Components.interfaces.nsIRDFService)
120                     .GetResource("moz-abdirectory://")
121                     .QueryInterface(Components.interfaces.nsIAbDirectory);
122     iter = dir.childNodes;
123   }
124   while (iter.hasMoreElements()) {
125     data = iter.getNext();
126     if (data instanceof Components.interfaces.nsIAbDirectory && (this.mVersion === 3 ||
127         data instanceof Components.interfaces.nsIAbMDBDirectory)) {
128       ab = this.getGAb(data);
129       username = ab.mPrefs.Username;
130       if (username && username.toLowerCase() !== "none") {
131         if (!this.mAddressBooks[username])
132           this.mAddressBooks[username] = [];
133         this.mAddressBooks[username].push(ab);
134       }
135     }
136   }
137   if (!aMakeArray)
138     return this.mAddressBooks;
139   // now convert to an array
140   arr = [];
141   for (i in this.mAddressBooks) {
142     for (j in this.mAddressBooks[i]) {
143       arr.push({
144         username: i,
145         ab:       this.mAddressBooks[i][j]
146       });
147     }
148   }
149   return arr;
150 };
151 
152 /**
153  * Backs up the given address book.  This consists of copying the Mork Address
154  * Book (MAB) file into the gContactSync directory.
155  * The backup is prefixed with the value of aPrefix (if not blank) followed by
156  * the original name of the file and ended with the value of aSuffix.
157  * NOTE: If a file already exists with the 
158  * @param aAb {GAddressBook} The address book to backup.
159  * @returns {boolean} True if the AB was successfully backed up
160  */
161 com.gContactSync.GAbManager.backupAB = function GAbManager_backupAB(aAB, aPrefix, aSuffix) {
162   var destFile    = com.gContactSync.FileIO.getProfileDirectory(),
163       uri         = aAB.mURI,
164       srcFileName = uri.substr(1 + uri.lastIndexOf("/")),
165       srcFile     = com.gContactSync.FileIO.getProfileDirectory(),
166       lines       = [];
167   // the source file is profile_dir/{FileNameFromURI}
168   srcFile.append(srcFileName);
169   // the destination is profile_dir/gcontactsync/{aPrefix}{FileName}{aSuffix}
170   destFile.append(com.gContactSync.FileIO.fileNames.FOLDER_NAME);
171   destFile.append(com.gContactSync.FileIO.fileNames.AB_BACKUP_DIR);
172   destFile.append((aPrefix || "") + srcFileName + (aSuffix || ""));
173   com.gContactSync.LOGGER.LOG("Beginning a backup of the Address Book:\n" +
174                               srcFile.path + "\nto:\n" + destFile.path);
175   // make sure the AB we are copying exists
176   if (!srcFile.exists()) {
177     com.gContactSync.LOGGER.LOG_ERROR("The source file does not exist");
178     return false;
179   }
180   if (com.gContactSync.FileIO.copyFile(srcFile, destFile)) {
181     aAB.savePref("lastBackup", (new Date()).getTime());
182     com.gContactSync.LOGGER.LOG(" - Backup finished successfully");
183     return true;
184   }
185   com.gContactSync.LOGGER.LOG(" - Unable to read the source address book");
186   return false;
187 };
188 
189 /**
190  * Returns a GAddressBook object for the given URI.
191  * If a GAddressBook for the URI or directory's pref branch has already been
192  * returned and is still stored, it is returned and no new object is created.
193  */
194 com.gContactSync.GAbManager.getGAbByURI = function GAbManager_getGAbByURI(aURI) {
195   // first check if a GAddressBook object for the URI already exists
196   var ab = com.gContactSync.GAbManager.mABs[aURI]
197   if (ab) {
198     return ab;
199   }
200   // if it hasn't been obtained yet, get the nsIAbDirectory through its URI
201   // then get a GAddressBook object from that and add it to
202   // com.gContactSync.GAbManager.mABs
203   return com.gContactSync.GAbManager.getGAb(com.gContactSync.GAbManager.getAbByURI(aURI));
204 };
205 
206 /**
207  * Returns a GAddressBook object for the given nsIAbDirectory.
208  * If a GAddressBook for the directory's URI or pref branch has already been
209  * returned and is still stored, it is returned and no new object is created.
210  */
211 com.gContactSync.GAbManager.getGAb = function GAbManager_getGAb(aDirectory, aNoPrefs) {
212   if (!aDirectory) {
213     return aDirectory;
214   }
215   // first check if a GAddressBook object for the URI already exists
216   // if so, return it
217   var uri = aDirectory.URI || aDirectory.getDirUri();
218   if (uri && com.gContactSync.GAbManager.mABs[uri]) {
219     return com.gContactSync.GAbManager.mABs[uri];
220   }
221   // otherwise create a new GAddressBook object and add it to
222   // com.gContactSync.GAbManager.mABs
223   var ab  = new com.gContactSync.GAddressBook(aDirectory, aNoPrefs);
224   com.gContactSync.GAbManager.mABs[ab.mURI] = ab;
225   com.gContactSync.GAbManager.mABs[ab.getPrefId()] = ab;
226   return ab;
227 };
228 
229 /**
230  * Returns an object filled with GAddressBook objects keyed by URI.
231  * @param aDirType {int} The type of directory (2 is the usual Mork AB)
232  * @returns {object} An object filled with GAddressBook objects keyed by URI.
233  */
234 com.gContactSync.GAbManager.getAllAddressBooks = function GAbManager_getAllAddressBooks(aDirType) {
235   var iter,
236       abManager,
237       dir,
238       abs = {},
239       data,
240       ab,
241       dirType;
242   if (Components.classes["@mozilla.org/abmanager;1"]) { // TB 3
243     abManager = Components.classes["@mozilla.org/abmanager;1"]
244                           .getService(Components.interfaces.nsIAbManager);
245     iter = abManager.directories;
246   }
247   else { // TB 2
248     // obtain the main directory through the RDF service
249     dir = Components.classes["@mozilla.org/rdf/rdf-service;1"]
250                     .getService(Components.interfaces.nsIRDFService)
251                     .GetResource("moz-abdirectory://")
252                     .QueryInterface(Components.interfaces.nsIAbDirectory);
253     iter = dir.childNodes;
254   }
255   while (iter.hasMoreElements()) {
256     data = iter.getNext();
257     if (data instanceof Components.interfaces.nsIAbDirectory && (this.mVersion === 3 ||
258         data instanceof Components.interfaces.nsIAbMDBDirectory)) {
259 
260       // If data isn't a valid AB then skip to the next one.
261       try {
262         ab = this.getGAb(data);
263       } catch (e) {
264         continue;
265       }
266       dirType = ab.getDirType();
267       // If no dir type was passed or the type matches then add it to abs
268       if (this.mVersion < 3 || aDirType === undefined || dirType === aDirType)
269         abs[ab.mURI] = ab;
270     }
271   }
272   return abs;
273 };
274