# HG changeset patch # User Emmanuel Gil Peyrot # Date 1310817287 -7200 # Node ID e4916f1763e57426ecbec6435977852cebc4035e # Parent 9ff8f951da990003b7dcfbffdd0f1a8b2ec5b29c Deactivable debug; fix a stupid bug in gravatar; add a better default image and make it configurable. diff --git a/avatar.js b/avatar.js --- a/avatar.js +++ b/avatar.js @@ -41,20 +41,23 @@ process.addListener('uncaughtException', console.log('Uncaught exception (' + err + '), this should never happen:\n' + err.stack); }); -(function() { - var send = conn.send; - conn.send = function(s) { - util.log('Sent: ' + s + ''); - send.call(conn, s); - }; -})(); +if (config.debug) + (function() { + var send = conn.send; + conn.send = function(s) { + console.log('Sent: ' + s + ''); + send.call(conn, s); + }; + })(); conn.on('online', function () { - console.log('Connected'); + util.log('Connected'); }); conn.on('stanza', function (stanza) { - util.log('Recv: ' + stanza + ''); + if (config.debug) + console.log('Recv: ' + stanza + ''); + if (stanza.is('iq')) onIq(stanza); else @@ -73,12 +76,26 @@ var jids = {}; var sent = {}; var svgError = function(res, message) { + util.log('No avatar at all, display a default image with the error in the title.'); + res.writeHead(200, {'Content-Type': 'image/svg+xml'}); res.write('\n'); - res.write('\n'); - res.write('\t'+message+'\n'); - res.write('\t\n'); - res.write('\tError\n'); + res.write('\n'); + res.write('\t' + message + '\n'); + + if (config.defaultImage) + res.write('\t\n'); + else { + res.write('\t\n'); + res.write('\t\n'); + res.write('\t\n'); + } + res.end('\n'); } @@ -92,14 +109,16 @@ var makeError = function(response) { } if (config.useGravatar) - var noAvatar = function(res, from, message) { + var noAvatar = function(res, to, message) { var options = { host: 'gravatar.com', port: 80, - path: '/avatar/' + hash('md5').update(from).digest('hex') + '?d=404', + path: '/avatar/' + hash('md5').update(to).digest('hex') + '?d=404', method: 'GET' }; + util.log('No XMPP avatar, falling back to Gravatar for ' + to + '.'); + var r = http.request(options, function(r) { if (r.statusCode != 200) return svgError(res, message + ' Additionaly, no gravatar available.'); @@ -121,7 +140,8 @@ if (config.useGravatar) return r.end(); }; else - var noAvatar = function(res, _, message) { + var noAvatar = function(res, to, message) { + util.log('No XMPP avatar for ' + to + '.'); return svgError(res, message); }; @@ -148,12 +168,12 @@ function onIq(stanza) { var err = 'none'; } - return noAvatar(res, from, 'Error during query of this user’s vCard: “'+err+'”.'); + return noAvatar(res, to, 'Error during query of this user’s vCard: “'+err+'”.'); } var vCard = stanza.getChild('vCard', 'vcard-temp'); if (!vCard) - return noAvatar(res, from, 'Error: this user doesn’t have a vCard.'); + return noAvatar(res, to, 'Error: this user doesn’t have a vCard.'); try { var photo = vCard.getChild('PHOTO', 'vcard-temp'); @@ -165,7 +185,7 @@ function onIq(stanza) { if (config.guessType) type = 'image/png'; // FIXME: use magic. else - return noAvatar(res, from, 'Error: this user’s vCard doesn’t specify the MIME type of its avatar.'); + return noAvatar(res, to, 'Error: this user’s vCard doesn’t specify the MIME type of its avatar.'); } var ext; @@ -176,7 +196,7 @@ function onIq(stanza) { // Here we don’t try to guess the extension even if the option is set. if (ext === undefined) { console.log('Unknown MIME type: '+type); - return noAvatar(res, from, 'Error: this user’s avatar is in an unknown format.'); + return noAvatar(res, to, 'Error: this user’s avatar is in an unknown format.'); } var binval = new Buffer(base64.replace(/\n/g, ''), 'base64'); @@ -186,7 +206,7 @@ function onIq(stanza) { showImage(to, res); }); } catch (e) { - return noAvatar(res, from, 'Error: this user doesn’t have an avatar in his/her vCard.'); + return noAvatar(res, to, 'Error: this user doesn’t have an avatar in his/her vCard.'); } } @@ -250,11 +270,11 @@ fs.readdir(config.directory, function(er }); http.createServer(function (req, res) { - console.log('Connection from ' + (req.headers['x-forwarded-for'] || req.client.remoteAddress) + ' (' + req.headers['user-agent'] + ') to ' + req.method.toLocaleLowerCase() + ' “' + req.url + '”.'); + util.log('Connection from ' + (req.headers['x-forwarded-for'] || req.client.remoteAddress) + ' (' + req.headers['user-agent'] + ') to ' + req.method.toLocaleLowerCase() + ' “' + req.url + '”.'); var easterEggs = { source: { - re: new RegExp(config.webRoot + 'source/code$'), + re: new RegExp('^' + config.webRoot + 'source/code$'), file: process.argv[1], mime: 'application/ecmascript', error: 'source code unavailable! oO' @@ -273,11 +293,11 @@ http.createServer(function (req, res) { for (var i in easterEggs) { var ee = easterEggs[i]; var file = ee.file || i; - var re = ee.re || new RegExp(config.webRoot + file + '$'); + var re = ee.re || new RegExp('^' + config.webRoot + file + '$'); if (re.test(req.url)) { fs.readFile(file, function(err, content) { if (err) - return noAvatar(res, from, 'Error: ' + (ee.error || file + ' unavailable.')); + return noAvatar(res, to, 'Error: ' + (ee.error || file + ' unavailable.')); res.writeHead(200, {'Content-Type': ee.mime || 'text/plain'}); res.end(content); @@ -286,7 +306,7 @@ http.createServer(function (req, res) { } } - var jid = unescape(req.url.replace(new RegExp(config.webRoot), '')); + var jid = unescape(req.url.replace(new RegExp('^' + config.webRoot), '')); if (jid === 'redirect') { if (req.method !== 'POST') { diff --git a/configuration.js.example b/configuration.js.example --- a/configuration.js.example +++ b/configuration.js.example @@ -21,11 +21,11 @@ var config = exports; // The JID and password of the account used. -config.jid = 'avatar.example.org'; +config.jid = 'avatar@example.org'; config.password = 'hellohello'; // Root of the webservice, useful if you want to proxy it. -config.webRoot = '^/avatar/'; +config.webRoot = '/avatar/'; // These are the host and the port on which the web service will // listen. If you want IPv4 connection only, instead of both IPv4 and @@ -54,5 +54,12 @@ config.extensions = { gif: 'image/gif' }; +// Image to use as fallback when there is no usable avatar. If not set, +// a SVG image will be displayed. +//config.defaultImage = 'http://example.org/default.svg'; + // Try Gravatar if there is a problem during XMPP avatar retrieving. -config.useGravatar = true; +//config.useGravatar = false; + +// Prints XMPP stanzas +config.debug = false;