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) 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 window.addEventListener("load",
 42   /** Initializes the MessengerOverlay class when the window has finished loading */
 43   function gCS_mainOverlayLoadListener(e) {
 44     // introduce a slight delay before initializing to let FileIO load in TB 2
 45     setTimeout(com.gContactSync.MessengerOverlay.initialize, 100);
 46   },
 47 false);
 48 
 49 /**
 50  * The main overlay removes old log files and logs basic information about
 51  * the version of gContactSync and Thunderbird.
 52  * Also resets the needRestart pref to false.
 53  * @class
 54  */
 55 com.gContactSync.MessengerOverlay = {
 56   /**
 57    * The original SetBusyCursor function that throws exceptions after
 58    * gContactSync synchronizes from messenger.xul.
 59    */
 60   mOriginalSetBusyCursor: null,
 61   /**
 62    * Initializes the MessengerOverlay class.
 63    * This consists of setting the needRestart pref to false, removing the old
 64    * log file, and logging basic TB and gContactSync information.
 65    */
 66   initialize: function MessengerOverlay_initialize() {
 67     // reset the needRestart pref
 68     com.gContactSync.Preferences.setSyncPref("needRestart", false);
 69     // remove the old log file
 70     if (com.gContactSync.FileIO.mLogFile && com.gContactSync.FileIO.mLogFile.exists()) {
 71       com.gContactSync.FileIO.mLogFile.remove(false); // delete the old log file
 72     }
 73 
 74     // override SetBusyCursor to wrap it in a try/catch block as it and
 75     // this add-on do not get along...
 76     com.gContactSync.MessengerOverlay.mOriginalSetBusyCursor = SetBusyCursor;
 77     SetBusyCursor = com.gContactSync.MessengerOverlay.SetBusyCursor;
 78 
 79     // log some basic system and application info
 80     com.gContactSync.LOGGER.LOG("Loading gContactSync at " + new Date());
 81     com.gContactSync.LOGGER.LOG(" * Version is:       " +
 82                                 com.gContactSync.getVersionString());
 83     com.gContactSync.LOGGER.LOG(" * Last version was: " +
 84                                 com.gContactSync.getVersionString(true));
 85     com.gContactSync.LOGGER.LOG(" * User Agent:       " +
 86                                 navigator.userAgent + "\n");
 87     com.gContactSync.Preferences.setSyncPref("lastVersionMajor",
 88                                              com.gContactSync.versionMajor);
 89     com.gContactSync.Preferences.setSyncPref("lastVersionMinor",
 90                                              com.gContactSync.versionMinor);
 91     com.gContactSync.Preferences.setSyncPref("lastVersionRelease",
 92                                              com.gContactSync.versionRelease);
 93     com.gContactSync.Preferences.setSyncPref("lastVersionSuffix",
 94                                              com.gContactSync.versionSuffix);
 95     com.gContactSync.Preferences.setSyncPref("synchronizing", false);
 96     com.gContactSync.MessengerOverlay.checkAuthentication(); // check if the Auth token is valid
 97     if (com.gContactSync.Preferences.mSyncPrefs.overrideGetCardForEmail.value) {
 98       try {
 99         com.gContactSync.MessengerOverlay.originalGetCardForEmail = getCardForEmail;
100         getCardForEmail = com.gContactSync.MessengerOverlay.getCardForEmail;
101       } catch (e) {}
102     }
103   },
104   /**
105    * Calls the original SetBusyCursor() function from mailCore.js wrapped in a
106    * try/catch block.  For some unknown reason, gContactSync causes
107    * SetBusyCursor to fail after a synchronization with an update from
108    * messenger.xul.
109    * See Bug 22801 for more details.
110    */
111   SetBusyCursor: function MessengerOverlay_SetBusyCursor() {
112     try {
113       com.gContactSync.MessengerOverlay.mOriginalSetBusyCursor.apply(this, arguments);
114     }
115     catch (e) {
116       com.gContactSync.LOGGER.LOG_WARNING("SetBusyCursor failed", e);
117     }
118   },
119  /**
120   * Returns an object with the first card and AB found with the given e-mail
121   * address.
122   * This is used to also search the ThirdEmail and FourthEmail properties as
123   * added by gContactSync.
124   *
125   * @param aEmail {string} The e-mail address to search for.
126   *
127   * @returns {object} An object with the AB and contact, if found.
128   *                   The object has 2 properties: book, containing the AB; and
129   *                   card, containing the contact.  Both are null if no contact
130   *                   was found with the given e-mail address, or if the e-mail
131   *                   address was empty.
132   */
133   getCardForEmail: function MessengerOverlay_getCardForEmail(aEmail) {
134     var result = { book: null, card: null };
135  
136     // abmanager should always exist as the original function doesn't exist in
137     // TB 2 (or Seamonkey 2)
138     if (!aEmail || !Components.classes["@mozilla.org/abmanager;1"]) {
139       return result;
140     }
141  
142     var abs = Components.classes["@mozilla.org/abmanager;1"]
143                         .getService(Components.interfaces.nsIAbManager)
144                         .directories;
145  
146     while (abs.hasMoreElements()) {
147       var ab = abs.getNext()
148                   .QueryInterface(Components.interfaces.nsIAbDirectory);
149       try {
150         // Search the original PrimaryEmail and SecondEmail fields
151         var card = ab.cardForEmailAddress(aEmail);
152         // Search ThirdEmail
153         if (!card) {
154           card = ab.getCardFromProperty("ThirdEmail", aEmail, false);
155         }
156         // Search FourthEmail
157         if (!card) {
158           card = ab.getCardFromProperty("FourthEmail", aEmail, false);
159         }
160         // If a card was found somewhere, setup result        
161         if (card) {
162           result.book = ab;
163           result.card = card;
164           // used in case ContactPhotos is installed
165           try {
166             com.ContactPhotos.mCurrentAb      = ab;
167             com.ContactPhotos.mCurrentContact = card;
168           } catch (e) {}
169           return result;
170         }
171       }
172       catch (ex) {}
173     }
174     return result;
175   },
176   /**
177    * Checks to see whether or not there is an authentication token in the login
178    * manager.  If so, it begins a sync.  If not, it shows the login prompt.
179    */
180   checkAuthentication: function MessengerOverlay_checkAuthentication() {
181     if (com.gContactSync.gdata.isAuthValid()) {
182       if (com.gContactSync.MessengerOverlay.mUsername) {
183         var name = com.gContactSync.Preferences.mSyncPrefs.addressBookName.value;
184         var ab   = com.gContactSync.GAbManager.getGAb(com.gContactSync.GAbManager.getAbByName(name));
185         ab.savePref("Username", com.gContactSync.MessengerOverlay.mUsername);
186         ab.setLastSyncDate(0);
187         com.gContactSync.Sync.begin();
188       }
189       else {
190         com.gContactSync.Sync.schedule(com.gContactSync.Preferences.mSyncPrefs.initialDelayMinutes.value * 60000);
191       }
192       return;
193     }
194     com.gContactSync.Overlay.setStatusBarText(com.gContactSync.StringBundle.getStr("notAuth"));
195     com.gContactSync.MessengerOverlay.promptLogin();
196   },
197   /**
198    * Prompts the user to enter his or her Google username and password and then
199    * gets an authentication token to store and use.
200    */
201   promptLogin: function MessengerOverlay_promptLogin() {
202     var prompt   = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
203                              .getService(Components.interfaces.nsIPromptService)
204                              .promptUsernameAndPassword;
205     var username = {};
206     var password = {};
207     // opens a username/password prompt
208     var ok = prompt(window, com.gContactSync.StringBundle.getStr("loginTitle"),
209                     com.gContactSync.StringBundle.getStr("loginText"), username, password, null,
210                     {value: false});
211     if (!ok)
212       return false;
213 
214     // This is a primitive way of validating an e-mail address, but Google takes
215     // care of the rest.  It seems to allow getting an auth token w/ only the
216     // username, but returns an error when trying to do anything w/ that token
217     // so this makes sure it is a full e-mail address.
218     if (username.value.indexOf("@") < 1) {
219       com.gContactSync.alertError(com.gContactSync.StringBundle.getStr("invalidEmail"));
220       return com.gContactSync.MessengerOverlay.promptLogin();
221     }
222     
223     // fix the username before authenticating
224     username.value = com.gContactSync.fixUsername(username.value);
225     var body     = com.gContactSync.gdata.makeAuthBody(username.value, password.value);
226     var httpReq  = new com.gContactSync.GHttpRequest("authenticate", null, null, body);
227     // if it succeeds and Google returns the auth token, store it and then start
228     // a new sync
229     httpReq.mOnSuccess = function authSuccess(httpReq) {
230       com.gContactSync.MessengerOverlay.login(username.value,
231                                      httpReq.responseText.split("\n")[2]);
232     };
233     // if it fails, alert the user and prompt them to try again
234     httpReq.mOnError = function authError(httpReq) {
235       com.gContactSync.alertError(com.gContactSync.StringBundle.getStr('authErr'));
236       com.gContactSync.LOGGER.LOG_ERROR('Authentication Error - ' +
237                                         httpReq.status,
238                                         httpReq.responseText);
239       com.gContactSync.MessengerOverlay.promptLogin();
240     };
241     // if the user is offline, alert them and quit
242     httpReq.mOnOffline = com.gContactSync.Sync.mOfflineFunction;
243     httpReq.send();
244     return true;
245   },
246   /**
247    * Stores the given auth token in the login manager and starts the setup
248    * window that will begin the first synchronization when closed.
249    * @param aAuthToken {string} The authentication token to store.
250    */
251   login: function MessengerOverlay_login(aUsername, aAuthToken) {
252     com.gContactSync.LoginManager.addAuthToken(aUsername, 'GoogleLogin ' + aAuthToken);
253     com.gContactSync.Overlay.setStatusBarText(com.gContactSync.StringBundle.getStr("initialSetup"));
254     var setup = window.open("chrome://gcontactsync/content/FirstLogin.xul",
255                             "SetupWindow",
256                             "chrome,resizable=yes,scrollbars=no,status=no");
257     com.gContactSync.MessengerOverlay.mUsername = aUsername;
258     // when the setup window loads, set its onunload property to begin a sync
259     setup.onload = function onloadListener() {
260       setup.onunload = function onunloadListener() {
261         com.gContactSync.MessengerOverlay.checkAuthentication();
262       };
263     };
264   }
265 };
266