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-2009 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 window.addEventListener("load", 42 /** Initializes the FileIO class when the window has finished loading */ 43 function gCS_FileIOLoadListener(e) { 44 com.gContactSync.FileIO.init(); 45 }, 46 false); 47 48 /** 49 * A class for reading, writing, and appending to files with an nsIFile for 50 * storing data, authentication info, and logs. 51 * @class 52 */ 53 com.gContactSync.FileIO = { 54 /** An nsIFile where the log is written */ 55 mLogFile: null, 56 /** File names */ 57 fileNames: { 58 /** Stores AB backups and the gContactSync log */ 59 FOLDER_NAME: "gcontactsync", 60 /** Stores the log from the last sync */ 61 LOG_FILE: "gcontactsync_log.txt", 62 /** The folder where AB backups are stored (inside FOLDER_NAME) */ 63 AB_BACKUP_DIR: "address_book_backups", 64 /** The folder where Google backups are stored (inside FOLDER_NAME) */ 65 GOOGLE_BACKUP_DIR: "google_feed_backups", 66 /** The folder where preferences backups are stored (inside FOLDER_NAME) */ 67 PREFS_BACKUP_DIR: "preferences_backups", 68 /** The file where TB preferences are stored */ 69 PREFS_JS: "prefs.js" 70 }, 71 /** 72 * Initializes the files contained in this class. 73 * Also creates the log directory, if necessary. 74 */ 75 init: function FileIO_init() { 76 var directory = this.getProfileDirectory(), 77 abBackupDir = this.getProfileDirectory(), 78 gBackupDir = this.getProfileDirectory(), 79 prefsBackupDir = this.getProfileDirectory(); 80 // Make sure the profile directory exists (if not something is very wrong) 81 this.checkDirectory(directory); 82 // Append the gcontactsync folder onto the directory and make sure it exists 83 directory.append(this.fileNames.FOLDER_NAME); 84 this.checkDirectory(directory); 85 // make sure the AB backup dir exists 86 abBackupDir.append(this.fileNames.FOLDER_NAME); 87 abBackupDir.append(this.fileNames.AB_BACKUP_DIR); 88 this.checkDirectory(abBackupDir); 89 // make sure the Google backup dir exists 90 gBackupDir.append(this.fileNames.FOLDER_NAME); 91 gBackupDir.append(this.fileNames.GOOGLE_BACKUP_DIR); 92 this.checkDirectory(gBackupDir); 93 // make sure the prefs backup dir exists 94 prefsBackupDir.append(this.fileNames.FOLDER_NAME); 95 prefsBackupDir.append(this.fileNames.PREFS_BACKUP_DIR); 96 this.checkDirectory(prefsBackupDir); 97 this.mLogFile = directory; 98 this.mLogFile.append(this.fileNames.LOG_FILE); 99 if (this.mLogFile.exists() && !this.mLogFile.isWritable()) { 100 com.gContactSync.alertError(com.gContactSync.StringBundle.getStr("logNotWritable") + 101 "\n" + this.mLogFile.path); 102 throw "Error - cannot write to the log file: " + 103 com.gContactSync.FileIO.mLogFile.path; 104 } 105 }, 106 /** 107 * Checks that a directory corresponding to an nsIFile exists, and creates it 108 * if necessary. 109 * This will throw an error if the directory could not be created, is not a 110 * directory, or if the directory is not writeable. 111 */ 112 checkDirectory: function FileIO_checkDirectory(aDirectory) { 113 // If the directory doesn't exist yet then create it 114 if (!aDirectory.exists()) { 115 // create the directory (type = 1) - rw for the user and r for others 116 try { aDirectory.create("1", parseInt("755", 8)); } catch (e) {} 117 // if it still doesn't exist let the user know, then quit 118 if (!aDirectory.exists()) { 119 com.gContactSync.alertError(com.gContactSync.StringBundle.getStr("couldntMkDir") + 120 "\n" + aDirectory.path); 121 throw "Error - could not create the following directory: " + 122 aDirectory.path; 123 } 124 } 125 if (!aDirectory.isDirectory()) { 126 com.gContactSync.alertError(com.gContactSync.StringBundle.getStr("isNotDir") + 127 "\n" + aDirectory.path); 128 throw "Error - " + aDirectory.path + " is not a directory."; 129 } 130 if (!aDirectory.isWritable()) { 131 com.gContactSync.alertError(com.gContactSync.StringBundle.getStr("notWritable") + 132 "\n" + aDirectory.path); 133 throw "Error - Cannot write to the following directory: " + 134 aDirectory.path; 135 } 136 }, 137 /** 138 * Gets the the file in the extension's directory with the given name. 139 * @param aName {string} The name of the file to get. 140 * @returns {nsIFile} The file with the given name in the extension's 141 * directory. 142 */ 143 getFileInExtDir: function FileIO_getFileInExtDir(aName) { 144 var MY_ID = "gContactSync@pirules.net", 145 em = Components.classes["@mozilla.org/extensions/manager;1"] 146 .getService(Components.interfaces.nsIExtensionManager); 147 return em.getInstallLocation(MY_ID).getItemFile(MY_ID, aName); 148 }, 149 /** 150 * Returns an nsIFile of the current profile directory of the application. 151 * @returns {nsIFile} The current profile directory of the application. 152 */ 153 getProfileDirectory: function FileIO_getProfileDirectory() { 154 return Components.classes["@mozilla.org/file/directory_service;1"] 155 .getService(Components.interfaces.nsIProperties) 156 .get("ProfD", Components.interfaces.nsIFile); 157 }, 158 /** 159 * Opens the given file and returns an array of the lines within it. 160 * @param aFile {nsIFile} The nsIFile to read. 161 * @returns {array} An array of the lines in the file or [] if there is an 162 * error. 163 */ 164 readFile: function FileIO_readFile(aFile) { 165 this.checkFile(aFile); 166 if (!aFile.exists()) 167 return []; 168 try { 169 var line = {}, 170 lines = [], 171 hasmore, 172 istream = Components.classes["@mozilla.org/network/file-input-stream;1"] 173 .createInstance(Components.interfaces.nsIFileInputStream); 174 istream.init(aFile, 0x01, 0444, 0); 175 istream.QueryInterface(Components.interfaces.nsILineInputStream); 176 177 do { 178 hasmore = istream.readLine(line); 179 lines.push(line.value); 180 } while (hasmore); 181 182 istream.close(); 183 return lines; 184 } 185 catch (e) { 186 throw "Unable to read from file: " + aFile + "\n" + e; 187 } 188 }, 189 /** 190 * Writes the string data to the nsIFile aFile. 191 * NOTE: This will delete any existing text in the file. 192 * @param aFile {nsIFile} The nsIFile to which the string is written. 193 * @param aData {string} The string of data to write to the file. 194 * @returns {boolean} True if there is no error. 195 */ 196 writeToFile: function FileIO_writeToFile(aFile, aData) { 197 this.checkFile(aFile); 198 if (!aData) 199 return false; 200 try { 201 var foStream = Components.classes["@mozilla.org/network/file-output-stream;1"] 202 .createInstance(Components.interfaces.nsIFileOutputStream); 203 foStream.init(aFile, 0x02 | 0x08 | 0x20, 0666, 0); 204 foStream.write(aData, aData.length); 205 foStream.close(); 206 return true; 207 } 208 catch (e) { 209 throw "Unable to write '" + aData + "' to file: " + aFile + "\n" + e; 210 } 211 return false; 212 }, 213 /** 214 * Appends the string aData to the nsIFile aFile. 215 * @param aFile {nsIFile} The nsIFile to which the string is appended. 216 * @param aData {string} The string of data to append to the file. 217 * @returns {boolean} True if there is no error. 218 */ 219 appendToFile: function FileIO_appendToFile(aFile, aData) { 220 if (!aData) 221 return false; 222 this.checkFile(aFile); 223 try { 224 var foStream = Components.classes["@mozilla.org/network/file-output-stream;1"] 225 .createInstance(Components.interfaces.nsIFileOutputStream); 226 if (aFile.exists()) 227 foStream.init(aFile, 0x02 | 0x10, 0666, 0); 228 else 229 foStream.init(aFile, 0x02 | 0x08 | 0x20, 0666, 0); 230 foStream.write(aData, aData.length); 231 foStream.close(); 232 return true; 233 } 234 catch (e) { 235 throw "Unable to append '" + aData + "' to file: " + aFile + + "\n" + aFile.path + "\n" + e; 236 } 237 return false; 238 }, 239 /** 240 * Copies the contents of one file to another using the readFile and writeFile 241 * methods of this class. 242 * If there is an error reading the source file, or if one or more of the 243 * given files are invalid an error will be thrown. 244 * NOTE: The contents of the destination file are removed permanently. 245 * 246 * @param aSrc {nsIFile} The source file. 247 * @param aDest {nsIFile} The destination file. NOTE: the contents of this 248 * file before the copy will be permanently removed. 249 * @returns {boolean} True if the copy finished successfully 250 */ 251 copyFile: function FileIO_copyFile(aSrc, aDest) { 252 this.checkFile(aSrc); 253 this.checkFile(aDest); 254 // read the file into an array 255 var lines = this.readFile(aSrc) || []; 256 // write the array into a file 257 this.writeToFile(aDest, lines.join("\n")); 258 return true; 259 }, 260 /** 261 * Checks that an argument is not null, is an instance of nsIFile, and that, 262 * if it exists, that it is a file (not a directory). 263 * @param aFile {nsIFile} The file to check. 264 * @param aCaller {string} The name of the calling method. 265 */ 266 checkFile: function FileIO_checkFile(aFile) { 267 if (!aFile || !aFile instanceof Components.interfaces.nsIFile || (aFile.exists() && !aFile.isFile())) 268 throw "Invalid File: " + aFile + " sent to the '" + this.checkFile.caller + 269 "' method" + com.gContactSync.StringBundle.getStr("pleaseReport"); 270 } 271 }; 272