-Implement the v2 and v3 server protocol

-Switch to POST and secure server
-Use the password manager with custom login dialog to handle login process
This commit is contained in:
patrick.oreilly
2010-07-29 20:19:51 +00:00
parent bc74bdba27
commit 39d3e47487
22 changed files with 632 additions and 71 deletions

View File

@@ -1,10 +1,10 @@
sendtophone.init = function( prefs )
sendtophone.init = function()
{
// Try to install the toolbar button, but only once
if (!prefs.getBoolPref("installedButton"))
if (!this.prefs.getBoolPref("installedButton"))
{
this.installToolbarButton();
prefs.setBoolPref( "installedButton", true ) ;
this.prefs.setBoolPref( "installedButton", true ) ;
}
}

View File

@@ -0,0 +1,201 @@
const nsIPasswordManager = Components.interfaces.nsIPasswordManager;
var gPasswordArray = new Array();
function onLoad() {
document.getElementById("status").value = getLocalizedString("LoginRequired");
var url = "chrome://sendtophone/";
// Gecko 1.9
if (Components.classes["@mozilla.org/login-manager;1"]) {
var passwordManager = Components.classes["@mozilla.org/login-manager;1"].getService(Components.interfaces.nsILoginManager);
var passwords = passwordManager.findLogins({}, url, null, "sendtophone");
if (passwords.length > 0) {
for (var i = 0; i < passwords.length; i++) {
user = passwords[i].username;
password = passwords[i].password;
// XXX: why not call the service here to get password?
if (password === " ") {
// XXX: empty password is " " for now due to ff3 change
password = "";
}
gPasswordArray[user] = password;
document.getElementById("username").appendItem(user, user);
}
}
} else {
var passwordManager = Components.classes["@mozilla.org/passwordmanager;1"]
.createInstance(nsIPasswordManager);
var enumerator = passwordManager.enumerator;
var user, password;
while (enumerator.hasMoreElements()) {
var nextPassword;
try {
nextPassword = enumerator.getNext();
} catch(e) {
break;
}
nextPassword = nextPassword.QueryInterface(Components.interfaces.nsIPassword);
var host = nextPassword.host;
if (host == url) {
// try/catch in case decryption fails (invalid signon entry)
try {
user = nextPassword.user;
password = nextPassword.password;
gPasswordArray[user] = password;
document.getElementById("username").appendItem(user, user);
} catch (e) {
continue;
}
}
}
}
var username = window.opener.sendtophone.prefs.getCharPref("users.default");
if (username) {
document.getElementById("username").value = username;
if (gPasswordArray[username] != null) {
document.getElementById("password").value = gPasswordArray[username];
}
document.getElementById("store-password").checked =
window.opener.sendtophone.prefs.getBoolPref("users.remember");
}
}
/**
* Login window calls this if we need to store the login details
*
*/
function storeLoginDetails(aStorePassword) {
var url = "chrome://sendtophone/";
var sendtophone = window.opener.sendtophone;
var prefs = sendtophone.prefs;
var user_name = sendtophone.user_name;
var password = sendtophone.password;
if (Components.classes["@mozilla.org/login-manager;1"]) {
var passwordManager = Components.classes["@mozilla.org/login-manager;1"].getService(Components.interfaces.nsILoginManager);
if (!passwordManager) {
return;
}
var passwords = passwordManager.findLogins({}, url, null, "sendtophone");
if (passwords.length > 0) {
for (var i = 0; i < passwords.length; i++) {
if (passwords[i].username == user_name) {
passwordManager.removeLogin(passwords[i]);
break;
}
}
}
var logininfo = Components.classes["@mozilla.org/login-manager/loginInfo;1"].createInstance(Components.interfaces.nsILoginInfo);
if (aStorePassword) {
prefs.setBoolPref("users.remember", true);
prefs.setCharPref("users.default", user_name);
logininfo.init(url, null, "sendtophone", user_name, password, "", "");
passwordManager.addLogin(logininfo);
} else {
// if we don't store the password, we store the user name only
// XXX: FF3 doesn't allow empty/null names - using " ", need to reconsider
logininfo.init(url, null, "sendtophone", user_name, " ", "", "");
passwordManager.addLogin(logininfo);
}
} else {
var passwordManager = Components.classes["@mozilla.org/passwordmanager;1"].createInstance();
if (passwordManager) {
passwordManager = passwordManager.QueryInterface(nsIPasswordManager);
try {
passwordManager.removeUser(url, user_name);
} catch (e) {}
if (aStorePassword) {
prefs.setBoolPref("users.remember", true);
prefs.setCharPref("users.default", user_name);
passwordManager.addUser(url, user_name, password);
} else {
// if we don't store the password, we store the user name only
passwordManager.addUser(url, user_name, "");
}
}
}
}
function selectionChanged(aElement) {
var name = aElement.value;
if (gPasswordArray[name] != null) {
document.getElementById("password").value = gPasswordArray[name];
}
}
function getLocalizedString(aName) {
var strbundle=document.getElementById("strings");
return strbundle.getString(aName);
}
function onAccept() {
window.opener.sendtophone.initLogin(
document.getElementById("username").value,
document.getElementById("password").value);
// remember login pref
window.opener.sendtophone.prefs.setBoolPref("users.remember",
document.getElementById("store-password").checked);
return false;
}
function setStatus(aStatusNum) {
var statusMsg = "";
switch (aStatusNum){
// trying to log in
case 1:
document.getElementById("login").disabled = true;
statusMsg = getLocalizedString("LoggingStatusLoggingIn");
break;
// logged in
case 2:
statusMsg = getLocalizedString("LoggingStatusLoggedIn");
storeLoginDetails(document.getElementById("store-password").checked);
break;
// failed to login
case 3:
statusMsg = getLocalizedString("LoggingStatusFailed1");
document.getElementById("login").disabled = false;
break;
// invalid username/password
case 4:
statusMsg = getLocalizedString("LoggingStatusInvalidLogin");
document.getElementById("login").disabled = false;
break;
default:
statusMsg = getLocalizedString("LoggingStatusError");
break;
}
document.getElementById("status").value = statusMsg;
}

View File

@@ -0,0 +1,57 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<!DOCTYPE dialog SYSTEM "chrome://sendtophone/locale/overlay.dtd">
<dialog xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:html="http://www.w3.org/1999/xhtml"
id="sendtophoneLogin"
onload="return onLoad();"
ondialogaccept="return onAccept();"
buttons="accept,cancel"
title="&sendtophoneLogin.title;" style="padding:0px;"
persist="screenX screenY">
<script type="application/x-javascript" src="chrome://sendtophone/content/login.js"/>
<stringbundle id="strings" src="chrome://sendtophone/locale/overlay.properties"/>
<description id="status" style="text-align:center; padding-top:10px;" value=""/>
<grid style="padding:10px;">
<columns>
<column />
<column flex="1"/>
</columns>
<rows>
<row>
<hbox align="center">
<label control="username" value="&sendtophoneLoginUsername.label;"
accesskey="&sendtophoneLoginUsername.accesskey;" />
</hbox>
<!--<textbox flex="1" id="username"/>-->
<menulist type="autocomplete" oncommand="selectionChanged(this)" editable="true" id="username"/>
</row>
<row>
<hbox align="center">
<label control="password" value="&sendtophoneLoginPassword.label;"
accesskey="&sendtophoneLoginPassword.accesskey;"/>
</hbox>
<textbox flex="1" type="password" id="password"/>
</row>
<row>
<spacer />
<checkbox id="store-password" label="&sendtophoneLoginRememberPassword.label;"/>
</row>
</rows>
</grid>
<hbox>
<spacer flex="1"/>
<button label="&sendtophoneLoginButtonLogin.label;" id="login" dlgtype="accept"/>
<button dlgtype="cancel" />
</hbox>
</dialog>

View File

@@ -1,48 +1,33 @@
var sendtophone = {
baseUrl : '',
req : null,
apiVersion : 3,
loggedInUrl : "chrome://sendtophone/loggedIn",
loggedOutUrl : "chrome://sendtophone/loggedOut",
apkUrl : "http://code.google.com/p/chrometophone/downloads/detail?name=chrometophone-android.apk&can=2",
init: function( prefs )
init: function()
{
// Each app will implement its specific initialization
},
initPopup: function()
onLoad: function()
{
// returning true will make the popup show
return true;
},
var me = sendtophone;
logout: function()
{
var cookieMgr = Components.classes["@mozilla.org/cookiemanager;1"]
.getService(Components.interfaces.nsICookieManager);
me.strings = document.getElementById("sendtophone-strings");
// extract the domain based on the currently used one
// "chrometophone.appspot.com" by default
var domain = sendtophone.baseUrl.match(/https?:\/\/(.*)\//)[1];
for (var e = cookieMgr.enumerator; e.hasMoreElements();) {
var cookie = e.getNext().QueryInterface(Components.interfaces.nsICookie);
if (cookie.host == domain)
{
cookieMgr.remove(cookie.host, cookie.name, cookie.path, false);
break;
}
}
},
onLoad: function()
{
sendtophone.strings = document.getElementById("sendtophone-strings");
var prefs = Components.classes["@mozilla.org/preferences-service;1"]
me.prefs = Components.classes["@mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefService)
.getBranch("extensions.sendtophone.") ;
// Allow the people to use their own server if they prefer to not trust this server
sendtophone.baseUrl = prefs.getCharPref( "appUrl" ) ;
me.baseUrl = me.prefs.getCharPref( "appUrl" ) ;
sendtophone.init( prefs );
me.sendUrl = me.baseUrl + '/send?ver=' + me.apiVersion;
me.logInUrl = me.baseUrl + '/signin?ver=' + me.apiVersion + '&extret=' + encodeURIComponent(me.loggedInUrl);
me.logOutUrl = me.baseUrl + '/signout?ver=' + me.apiVersion + '&extret=' + encodeURIComponent(me.loggedOutUrl);
me.init();
},
onMenuItemCommand: function(e, type)
@@ -66,6 +51,7 @@ var sendtophone = {
selection = content.getSelection().toString();
break;
case 'page':
default:
var info = sendtophone.getInfo();
title = info.title;
url = info.url;
@@ -76,7 +62,7 @@ var sendtophone = {
if ((/https?:/i).test( info.url ))
{
*/
var max_length = 256;
var max_length = 1024;
if (selection.length > max_length)
selection = selection.substring(0, max_length);
@@ -85,21 +71,35 @@ var sendtophone = {
}
else
{
var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
.getService(Components.interfaces.nsIPromptService);
promptService.alert(window, this.strings.getString("SendToPhoneTitle"),
this.strings.getString("InvalidScheme"));
this.alert(this.strings.getString("InvalidScheme"));
}
*/
},
popupNotification: function(title, text)
// Shows a message in a modal alert
alert: function(text)
{
var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
.getService(Components.interfaces.nsIPromptService);
promptService.alert(window, this.strings.getString("SendToPhoneTitle"),
text);
},
// Shows a message in a growl-like notification
popupNotification: function(text)
{
var title = this.strings.getString("SendToPhoneTitle");
var image = "chrome://sendtophone/skin/icon.png";
try {
// Avoid crash on Fedora 12.
// Reported on 8th June https://addons.mozilla.org/en-US/firefox/reviews/display/161941
var listener = {
observe: function(subject, topic, data) {}
};
Components.classes['@mozilla.org/alerts-service;1']
.getService(Components.interfaces.nsIAlertsService)
.showAlertNotification(image, title, text, false, '', null);
.showAlertNotification(image, title, text, false, '', listener);
} catch(e)
{
// prevents runtime error on platforms that don't implement nsIAlertsService
@@ -135,42 +135,231 @@ var sendtophone = {
};
},
sendToPhone: function(title, url, selection)
processXHR: function(url, method, data, callback)
{
if (!this.req)
this.req = new XMLHttpRequest();
var req = this.req;
var sendUrl = this.baseUrl + '?title=' + encodeURIComponent(title) +
'&url=' + encodeURIComponent(url) + '&sel=' + encodeURIComponent(selection);
req.open('GET', sendUrl, true);
req.open(method, url, true);
req.setRequestHeader('X-Extension', 'true'); // XSRF protector
if (method=='POST')
req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
req.onreadystatechange = function()
{
var me = sendtophone;
if (this.readyState == 4) {
if (req.status == 200) {
if (req.responseText.substring(0, 2) == 'OK') {
me.popupNotification(me.strings.getString("SendToPhoneTitle"), me.strings.getString("InfoSent"));
} else { // most likely login, handle in new tab
me.popupNotification(me.strings.getString("SendToPhoneTitle"),
me.strings.getString("LoginRequired") );
var tab = gBrowser.addTab(sendUrl);
gBrowser.selectedTab = tab;
// here this == req
if (this.readyState == 4)
{
var body = req.responseText;
if (req.status == 200)
{
// Check if the body is a html redirect
var redirectMatch = body.match(/<meta http-equiv="refresh" content="\d;\s*url=(&#39;)?(.*)\1">/);
if (redirectMatch)
{
var redirectUrl = redirectMatch[2].replace(/&amp;/g, '&');
if (redirectUrl == sendtophone.loggedInUrl)
{
sendtophone.loginSuccessful();
return;
}
if (redirectUrl == sendtophone.loggedOutUrl)
{
sendtophone.logoutSuccessful();
return;
}
// Do the redirect and use the original callback
sendtophone.processXHR( redirectUrl, 'GET', null, callback);
}
} else {
me.popupNotification(me.strings.getString("SendToPhoneTitle"),
me.strings.getString("ErrorOnSend") + '\r\n' + req.responseText);
else
callback.call( sendtophone, req );
}
else
{
sendtophone.alert(sendtophone.strings.getString("ErrorOnSend") + ' (status ' + req.status + ')\r\n' + body);
}
}
};
req.send(null);
}
req.send( data );
},
sendToPhone: function(title, url, selection)
{
var data = 'title=' + encodeURIComponent(title) +
'&url=' + encodeURIComponent(url) + '&sel=' + encodeURIComponent(selection);
this.pendingMessage = data;
this.processXHR(this.sendUrl, 'POST', data, this.processSentData);
},
processSentData : function(req)
{
var body = req.responseText;
if (body.substring(0, 2) == 'OK')
{
delete this.pendingMessage;
this.popupNotification(this.strings.getString("InfoSent"));
return;
}
if (body.indexOf('LOGIN_REQUIRED') == 0)
{
this.openLoginWindow();
return;
/*
this.popupNotification(this.strings.getString("LoginRequired") );
var tab = gBrowser.addTab( this.logInUrl );
gBrowser.selectedTab = tab;
var c2pTab = gBrowser.getBrowserForTab(tab);
c2pTab.addEventListener("load", function () {
if(this.magicUrl==c2pTab.currentURI.spec){
c2pTab.contentDocument.location = "data:text/html;base64,PGh0bWw+PGhlYWQ+PHRpdGxlPlNlbmQgdG8gUGhvbmUgRXh0ZW5zaW9uPC90aXRsZT48c3R5bGUgdHlwZT0idGV4dC9jc3MiPg0KYm9keSB7bWluLXdpZHRoOiAzMjBweDtvdmVyZmxvdy14OiBoaWRkZW47Zm9udC1mYW1pbHk6IHZlcmRhbmE7Zm9udC1zaXplOiAxMnB4O2NvbG9yOiBibGFjazsgYmFja2dyb3VuZC1jb2xvcjogd2hpdGU7fTwvc3R5bGU+PC9oZWFkPjxib2R5PjxoMT48aW1nIHNyYz0iaHR0cDovL2NvZGUuZ29vZ2xlLmNvbS9wL2Nocm9tZXRvcGhvbmUvbG9nbz9jY3Q9MTI3NTk0MTQ2NCIgd2lkdGg9IjY0IiBoZWlnaHQ9IjY0IiB2YWxpZ249ImJvdHRvbSI+U2VuZCB0byBQaG9uZSBFeHRlbnNpb248L2gxPjxoMj5TaWduZWQgSW48L2gyPjxwPkNvbmdyYXR1bGF0aW9ucy4gWW91IGFyZSBub3cgc2lnbmVkIGluIHRvIFNlbmQgdG8gUGhvbmUuPC9wPjxwPlBsZWFzZSBjbG9zZSB0aGlzIHRhYiwgdGhlbiBhdHRlbXB0IHRvIHNlbmQgeW91ciBtYWlsIGFnYWluLjwvcD48ZGl2IGFsaWduPSJjZW50ZXIiPjxicj4mY29weTsyMDEwIC0gPGEgaHJlZj0iaHR0cHM6Ly9hZGRvbnMubW96aWxsYS5vcmcvZW4tVVMvZmlyZWZveC9hZGRvbi8xNjE5NDEvIj5BYm91dCBTZW5kIHRvIFBob25lPC9hPjwvZGl2PjwvYm9keT48L2h0bWw+";
}
}, true);
return;
*/
}
if (body.indexOf('DEVICE_NOT_REGISTERED') == 0)
{
this.popupNotification(this.strings.getString("DeviceNotRegistered"));
var tab = gBrowser.addTab( this.apkUrl );
gBrowser.selectedTab = tab;
return;
}
this.alert(this.strings.getString("ErrorOnSend") + '\r\n' + body);
},
initPopup: function()
{
// returning true will make the popup show
return true;
},
logout: function()
{
this.processXHR(this.logOutUrl, 'GET', null, function(req)
{
// This will be called only if there's a problem
this.alert(this.strings.getString("LogoutError") + '\r\n' + req.responseText );
});
},
logoutSuccessful: function()
{
this.popupNotification(this.strings.getString("LogoutSuccessful"));
},
/**
* Opens the login window and stores a reference to it
*
*/
openLoginWindow: function() {
this.login_window = window.openDialog("chrome://sendtophone/content/login.xul", "_blank", "chrome,resizable=no,dependent=yes");
},
/**
* Called by the login window
*
* @param aUserName - the username
* @param aPassword - the password
*/
initLogin: function(aUserName, aPassword)
{
this.user_name = aUserName;
this.password = aPassword;
this.login_window.setStatus(1);
this.startLoginProcess();
},
startLoginProcess: function()
{
this.processXHR(this.logInUrl, 'GET', null, this.processLoginStart);
},
processLoginStart: function(req)
{
var body = this.HTMLParser(req.responseText);
var form = body.getElementsByTagName('form')[0];
if (form && form.id=='gaia_loginform')
{
var query='';
var items = form.elements;
for (var i=0; i<items.length; i++)
{
var value='';
var input=items[i];
if (input.type=='hidden')
value=input.value;
else
{
switch (input.name)
{
case 'Email':
value = this.user_name;
break;
case 'Passwd':
value = this.password;
break;
case 'PersistentCookie':
// if (persistent)
value = input.value;
break;
case 'signIn':
value = input.value;
break;
default:
value = input.value;
break;
}
}
query += '&' + input.name + '=' + encodeURIComponent(value);
}
this.processXHR(form.action, 'POST', query, function(req)
{
// This will be called if the login fails
// Different status? 3 vs 4
this.login_window.setStatus(4);
});
return;
}
this.alert(this.strings.getString("ErrorOnSend") + '\r\n' + req.responseText );
},
loginSuccessful: function()
{
// this.popupNotification( this.strings.getString("LoggingStatusLoggedIn") );
// Save user and close login window
this.login_window.setStatus(2);
this.login_window.close();
delete this.login_window;
// Send pending message
this.processXHR(this.sendUrl, 'POST', this.pendingMessage, this.processSentData);
},
// https://developer.mozilla.org/en/Code_snippets/HTML_to_DOM#Safely_parsing_simple_HTML.c2.a0to_DOM
HTMLParser: function(aHTMLString){
var html = document.implementation.createDocument("http://www.w3.org/1999/xhtml", "html", null),
body = document.createElementNS("http://www.w3.org/1999/xhtml", "body");
html.documentElement.appendChild(body);
body.appendChild(Components.classes["@mozilla.org/feed-unescapehtml;1"]
.getService(Components.interfaces.nsIScriptableUnescapeHTML)
.parseFragment(aHTMLString, false, null, body));
return body;
}
};
window.addEventListener("load", sendtophone.onLoad, false);

View File

@@ -8,3 +8,11 @@
<!ENTITY sendtophoneContextText.accesskey "A">
<!ENTITY sendtophoneContextLogout.label "Logout">
<!ENTITY sendtophoneContextLogout.accesskey "L">
<!ENTITY sendtophoneLogin.title "&sendtophoneToolbarButton.label; - Log In">
<!ENTITY sendtophoneLoginUsername.label "Username:">
<!ENTITY sendtophoneLoginUsername.accesskey "u">
<!ENTITY sendtophoneLoginPassword.label "Password:">
<!ENTITY sendtophoneLoginPassword.accesskey "p">
<!ENTITY sendtophoneLoginRememberPassword.label "Remember password.">
<!ENTITY sendtophoneLoginButtonLogin.label "Log in">

View File

@@ -4,3 +4,9 @@ InvalidScheme=Ung
InfoSent=Der Link auf Ihr Handy geschickt worden.
ErrorOnSend=Es gab einen Fehler beim Senden:
LoginRequired=Login erforderlich, um den Link zu senden.
LoggingStatusLoggingIn=Validating login...
LoggingStatusLoggedIn=You have logged in.
LoggingStatusInvalidLogin=The data isn't correct.
DeviceNotRegistered=You must install the app in your phone and register this same email account
LogoutError=Logout error
LogoutSuccessful=You are logged out

View File

@@ -8,3 +8,11 @@
<!ENTITY sendtophoneContextText.accesskey "A">
<!ENTITY sendtophoneContextLogout.label "Logout">
<!ENTITY sendtophoneContextLogout.accesskey "L">
<!ENTITY sendtophoneLogin.title "&sendtophoneToolbarButton.label; - Log In">
<!ENTITY sendtophoneLoginUsername.label "Username:">
<!ENTITY sendtophoneLoginUsername.accesskey "u">
<!ENTITY sendtophoneLoginPassword.label "Password:">
<!ENTITY sendtophoneLoginPassword.accesskey "p">
<!ENTITY sendtophoneLoginRememberPassword.label "Remember password.">
<!ENTITY sendtophoneLoginButtonLogin.label "Log in">

View File

@@ -4,3 +4,9 @@ InvalidScheme=Invalid scheme, please only send http:// or https:// links.
InfoSent=The link has been sent to your phone.
ErrorOnSend=There was an error sending:
LoginRequired=Login required to send the link.
LoggingStatusLoggingIn=Validating login...
LoggingStatusLoggedIn=You have logged in.
LoggingStatusInvalidLogin=The data isn't correct.
DeviceNotRegistered=You must install the app in your phone and register this same email account
LogoutError=Logout error
LogoutSuccessful=You are logged out

View File

@@ -8,3 +8,11 @@
<!ENTITY sendtophoneContextText.accesskey "A">
<!ENTITY sendtophoneContextLogout.label "Salir">
<!ENTITY sendtophoneContextLogout.accesskey "L">
<!ENTITY sendtophoneLogin.title "&sendtophoneToolbarButton.label; - Conectar">
<!ENTITY sendtophoneLoginUsername.label "Nombre de usuario:">
<!ENTITY sendtophoneLoginUsername.accesskey "u">
<!ENTITY sendtophoneLoginPassword.label "Contraseña:">
<!ENTITY sendtophoneLoginPassword.accesskey "c">
<!ENTITY sendtophoneLoginRememberPassword.label "Recordar contraseña.">
<!ENTITY sendtophoneLoginButtonLogin.label "Conectar">

View File

@@ -4,3 +4,9 @@ InvalidScheme=Esquema no válido, por favor, envíe sólo enlaces http:// o http
InfoSent=El enlace ha sido enviado a su teléfono.
ErrorOnSend=Se ha producido un error al enviar:
LoginRequired=Es necesario identificarse para enviar el enlace.
LoggingStatusLoggingIn=Validando datos...
LoggingStatusLoggedIn=Se ha identificado correctamente.
LoggingStatusInvalidLogin=Los datos no son correctos.
DeviceNotRegistered=Debe instalar la aplicación en su teléfono y registrar la misma cuenta de correo
LogoutError=Error al cerrar
LogoutSuccessful=Ha cerrado su sesión

View File

@@ -8,3 +8,11 @@
<!ENTITY sendtophoneContextText.accesskey "A">
<!ENTITY sendtophoneContextLogout.label "Logout">
<!ENTITY sendtophoneContextLogout.accesskey "L">
<!ENTITY sendtophoneLogin.title "&sendtophoneToolbarButton.label; - Log In">
<!ENTITY sendtophoneLoginUsername.label "Username:">
<!ENTITY sendtophoneLoginUsername.accesskey "u">
<!ENTITY sendtophoneLoginPassword.label "Password:">
<!ENTITY sendtophoneLoginPassword.accesskey "p">
<!ENTITY sendtophoneLoginRememberPassword.label "Remember password.">
<!ENTITY sendtophoneLoginButtonLogin.label "Log in">

View File

@@ -4,3 +4,9 @@ InvalidScheme=régime Blancs, s'il vous plaît envoyer uniquement des liens http
InfoSent=Le lien a été envoyé à votre téléphone.
ErrorOnSend=Il y avait une erreur d'envoi:
LoginRequired=Login requis pour envoyer ce lien.
LoggingStatusLoggingIn=Validating login...
LoggingStatusLoggedIn=You have logged in.
LoggingStatusInvalidLogin=The data isn't correct.
DeviceNotRegistered=You must install the app in your phone and register this same email account
LogoutError=Logout error
LogoutSuccessful=You are logged out

View File

@@ -8,3 +8,11 @@
<!ENTITY sendtophoneContextText.accesskey "A">
<!ENTITY sendtophoneContextLogout.label "Logout">
<!ENTITY sendtophoneContextLogout.accesskey "L">
<!ENTITY sendtophoneLogin.title "&sendtophoneToolbarButton.label; - Log In">
<!ENTITY sendtophoneLoginUsername.label "Username:">
<!ENTITY sendtophoneLoginUsername.accesskey "u">
<!ENTITY sendtophoneLoginPassword.label "Password:">
<!ENTITY sendtophoneLoginPassword.accesskey "p">
<!ENTITY sendtophoneLoginRememberPassword.label "Remember password.">
<!ENTITY sendtophoneLoginButtonLogin.label "Log in">

View File

@@ -4,3 +4,9 @@ InvalidScheme=Scéim neamhbhailí, le do thoil seol http:// amháin nó http://
InfoSent=Tá nasc chuig do ghuthán.
ErrorOnSend=Tharla earráid agus a sheoladh:
LoginRequired=Logáil isteach ag teastáil chun a sheoladh chuig an nasc.
LoggingStatusLoggingIn=Validating login...
LoggingStatusLoggedIn=You have logged in.
LoggingStatusInvalidLogin=The data isn't correct.
DeviceNotRegistered=You must install the app in your phone and register this same email account
LogoutError=Logout error
LogoutSuccessful=You are logged out

View File

@@ -8,3 +8,11 @@
<!ENTITY sendtophoneContextText.accesskey "A">
<!ENTITY sendtophoneContextLogout.label "Logout">
<!ENTITY sendtophoneContextLogout.accesskey "L">
<!ENTITY sendtophoneLogin.title "&sendtophoneToolbarButton.label; - Log In">
<!ENTITY sendtophoneLoginUsername.label "Username:">
<!ENTITY sendtophoneLoginUsername.accesskey "u">
<!ENTITY sendtophoneLoginPassword.label "Password:">
<!ENTITY sendtophoneLoginPassword.accesskey "p">
<!ENTITY sendtophoneLoginRememberPassword.label "Remember password.">
<!ENTITY sendtophoneLoginButtonLogin.label "Log in">

View File

@@ -4,3 +4,9 @@ InvalidScheme=अवैध योजना, केवल http:// या https: /
InfoSent=लिंक आपके फोन करने के लिए भेजा गया है.
ErrorOnSend=वहाँ एक भेजने में त्रुटि थी:
LoginRequired=लॉगइन करने के लिए लिंक भेज आवश्यक है.
LoggingStatusLoggingIn=Validating login...
LoggingStatusLoggedIn=You have logged in.
LoggingStatusInvalidLogin=The data isn't correct.
DeviceNotRegistered=You must install the app in your phone and register this same email account
LogoutError=Logout error
LogoutSuccessful=You are logged out

View File

@@ -8,3 +8,11 @@
<!ENTITY sendtophoneContextText.accesskey "A">
<!ENTITY sendtophoneContextLogout.label "Logout">
<!ENTITY sendtophoneContextLogout.accesskey "L">
<!ENTITY sendtophoneLogin.title "&sendtophoneToolbarButton.label; - Log In">
<!ENTITY sendtophoneLoginUsername.label "Username:">
<!ENTITY sendtophoneLoginUsername.accesskey "u">
<!ENTITY sendtophoneLoginPassword.label "Password:">
<!ENTITY sendtophoneLoginPassword.accesskey "p">
<!ENTITY sendtophoneLoginRememberPassword.label "Remember password.">
<!ENTITY sendtophoneLoginButtonLogin.label "Log in">

View File

@@ -4,3 +4,9 @@ InvalidScheme=無効なスキームは、ちょうどはhttp://またはhttps://
InfoSent=リンクはあなたの携帯電話に送信されています。
ErrorOnSend=これは、送信に失敗しました:
LoginRequired=ログインリンクを送信するために必要です。
LoggingStatusLoggingIn=Validating login...
LoggingStatusLoggedIn=You have logged in.
LoggingStatusInvalidLogin=The data isn't correct.
DeviceNotRegistered=You must install the app in your phone and register this same email account
LogoutError=Logout error
LogoutSuccessful=You are logged out

View File

@@ -8,3 +8,11 @@
<!ENTITY sendtophoneContextText.accesskey "A">
<!ENTITY sendtophoneContextLogout.label "Logout">
<!ENTITY sendtophoneContextLogout.accesskey "L">
<!ENTITY sendtophoneLogin.title "&sendtophoneToolbarButton.label; - Log In">
<!ENTITY sendtophoneLoginUsername.label "Username:">
<!ENTITY sendtophoneLoginUsername.accesskey "u">
<!ENTITY sendtophoneLoginPassword.label "Password:">
<!ENTITY sendtophoneLoginPassword.accesskey "p">
<!ENTITY sendtophoneLoginRememberPassword.label "Remember password.">
<!ENTITY sendtophoneLoginButtonLogin.label "Log in">

View File

@@ -4,3 +4,9 @@ InvalidScheme=无效的计划请你只发送http://或https://联系。
InfoSent=该链接已发送到您的手机。
ErrorOnSend=它没有发送:
LoginRequired=登录后才可发送的链接。
LoggingStatusLoggingIn=Validating login...
LoggingStatusLoggedIn=You have logged in.
LoggingStatusInvalidLogin=The data isn't correct.
DeviceNotRegistered=You must install the app in your phone and register this same email account
LogoutError=Logout error
LogoutSuccessful=You are logged out

View File

@@ -1,5 +1,7 @@
pref("extensions.sendtophone.installedButton", false);
pref("extensions.sendtophone.appUrl", "http://chrometophone.appspot.com/send");
pref("extensions.sendtophone.appUrl", "https://chrometophone.appspot.com");
pref("extensions.sendtophone.users.default", "");
pref("extensions.sendtophone.users.remember", true);
// https://developer.mozilla.org/en/Localizing_extension_descriptions
pref("extensions.sendtophone@martinezdelizarrondo.com.description", "chrome://sendtophone/locale/overlay.properties");

View File

@@ -4,7 +4,7 @@
<em:id>sendtophone@martinezdelizarrondo.com</em:id>
<em:type>2</em:type>
<em:name>Send To Phone</em:name>
<em:version>0.6</em:version>
<em:version>0.8</em:version>
<em:creator>Alfonso Martínez de Lizarrondo</em:creator>
<em:contributor>Patrick O'Reilly</em:contributor>
<em:description>Send links to your Android 2.2 phone using the new C2DM service. Based on the ChromeToPhone extension.</em:description>
@@ -14,7 +14,7 @@
<Description>
<em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id> <!-- Firefox -->
<em:minVersion>3.0</em:minVersion>
<em:maxVersion>3.7a5pre</em:maxVersion>
<em:maxVersion>3.7a6pre</em:maxVersion>
</Description>
</em:targetApplication>
</Description>