/** * A Twitter library in JavaScript * https://github.com/mynetx/codebird-js * * @package codebird * @version 2.4.0-dev * @author J.M. * @copyright 2010-2013 J.M. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ /** * Array.indexOf polyfill */ if (! Array.indexOf) { Array.prototype.indexOf = function (obj, start) { for (var i = (start || 0); i < this.length; i++) { if (this[i] == obj) { return i; } } return -1; }; } /* * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined * in FIPS PUB 180-1 * Version 2.1 Copyright Paul Johnston 2000 - 2002. * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet * Distributed under the BSD License * See http://pajhome.org.uk/crypt/md5 for details. */ var hexcase = 0; var b64pad = ""; var chrsz = 8; function hex_sha1(s) { return binb2hex(core_sha1(str2binb(s), s.length * chrsz)); } function b64_sha1(s) { return binb2b64(core_sha1(str2binb(s), s.length * chrsz)); } function str_sha1(s) { return binb2str(core_sha1(str2binb(s), s.length * chrsz)); } function hex_hmac_sha1(key, data) { return binb2hex(core_hmac_sha1(key, data)); } function b64_hmac_sha1(key, data) { return binb2b64(core_hmac_sha1(key, data)); } function str_hmac_sha1(key, data) { return binb2str(core_hmac_sha1(key, data)); } function sha1_vm_test() { return hex_sha1("abc") == "a9993e364706816aba3e25717850c26c9cd0d89d"; } function core_sha1(x, len) { x[len >> 5] |= 0x80 << (24 - len % 32); x[((len + 64 >> 9) << 4) + 15] = len; var w = Array(80); var a = 1732584193; var b = -271733879; var c = -1732584194; var d = 271733878; var e = -1009589776; for (var i = 0; i < x.length; i += 16) { var olda = a; var oldb = b; var oldc = c; var oldd = d; var olde = e; for (var j = 0; j < 80; j++) { if (j < 16) w[j] = x[i + j]; else w[j] = rol(w[j - 3] ^ w[j - 8] ^ w[j - 14] ^ w[j - 16], 1); var t = safe_add(safe_add(rol(a, 5), sha1_ft(j, b, c, d)), safe_add(safe_add(e, w[j]), sha1_kt(j))); e = d; d = c; c = rol(b, 30); b = a; a = t; } a = safe_add(a, olda); b = safe_add(b, oldb); c = safe_add(c, oldc); d = safe_add(d, oldd); e = safe_add(e, olde); } return Array(a, b, c, d, e); } function sha1_ft(t, b, c, d) { if (t < 20) return (b & c) | ((~b) & d); if (t < 40) return b ^ c ^ d; if (t < 60) return (b & c) | (b & d) | (c & d); return b ^ c ^ d; } function sha1_kt(t) { return (t < 20) ? 1518500249 : (t < 40) ? 1859775393 : (t < 60) ? -1894007588 : -899497514; } function core_hmac_sha1(key, data) { var bkey = str2binb(key); if (bkey.length > 16) bkey = core_sha1(bkey, key.length * chrsz); var ipad = Array(16), opad = Array(16); for (var i = 0; i < 16; i++) { ipad[i] = bkey[i] ^ 0x36363636; opad[i] = bkey[i] ^ 0x5C5C5C5C; } var hash = core_sha1(ipad.concat(str2binb(data)), 512 + data.length * chrsz); return core_sha1(opad.concat(hash), 512 + 160); } function safe_add(x, y) { var lsw = (x & 0xFFFF) + (y & 0xFFFF); var msw = (x >> 16) + (y >> 16) + (lsw >> 16); return (msw << 16) | (lsw & 0xFFFF); } function rol(num, cnt) { return (num << cnt) | (num >>> (32 - cnt)); } function str2binb(str) { var bin = Array(); var mask = (1 << chrsz) - 1; for (var i = 0; i < str.length * chrsz; i += chrsz) bin[i >> 5] |= (str.charCodeAt(i / chrsz) & mask) << (24 - i % 32); return bin; } function binb2str(bin) { var str = ""; var mask = (1 << chrsz) - 1; for (var i = 0; i < bin.length * 32; i += chrsz) str += String.fromCharCode((bin[i >> 5] >>> (24 - i % 32)) & mask); return str; } function binb2hex(binarray) { var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef"; var str = ""; for (var i = 0; i < binarray.length * 4; i++) { str += hex_tab.charAt((binarray[i >> 2] >> ((3 - i % 4) * 8 + 4)) & 0xF) + hex_tab.charAt((binarray[i >> 2] >> ((3 - i % 4) * 8 )) & 0xF); } return str; } function binb2b64(binarray) { var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; var str = ""; for (var i = 0; i < binarray.length * 4; i += 3) { var triplet = (((binarray[i >> 2] >> 8 * (3 - i % 4)) & 0xFF) << 16) | (((binarray[i + 1 >> 2] >> 8 * (3 - (i + 1) % 4)) & 0xFF) << 8 ) | ((binarray[i + 2 >> 2] >> 8 * (3 - (i + 2) % 4)) & 0xFF); for (var j = 0; j < 4; j++) { if (i * 8 + j * 6 > binarray.length * 32) str += b64pad; else str += tab.charAt((triplet >> 6 * (3 - j)) & 0x3F); } } return str; } /** * A Twitter library in JavaScript * * @package codebird * @subpackage codebird-js */ var Codebird = function () { /** * The OAuth consumer key of your registered app */ var _oauth_consumer_key = null; /** * The corresponding consumer secret */ var _oauth_consumer_secret = null; /** * The app-only bearer token. Used to authorize app-only requests */ var _oauth_bearer_token = null; /** * The API endpoint base to use */ var _endpoint_base = 'https://api.twitter.com/'; /** * The API endpoint to use */ var _endpoint = _endpoint_base + '1.1/'; /** * The API endpoint to use for OAuth requests */ var _endpoint_oauth = _endpoint_base; /** * API proxy endpoint */ var _endpoint_proxy = 'https://api.jublo.net/codebird/'; /** * Use JSONP for GET requests in IE7-9 */ var _use_jsonp = false; /** * Whether to access the API via a proxy that is allowed by CORS */ var _use_proxy = false; /** * The Request or access token. Used to sign requests */ var _oauth_token = null; /** * The corresponding request or access token secret */ var _oauth_token_secret = null; /** * The current Codebird version */ var _version = '2.4.0-dev'; /** * Sets the OAuth consumer key and secret (App key) * * @param string key OAuth consumer key * @param string secret OAuth consumer secret * * @return void */ var setConsumerKey = function (key, secret) { _oauth_consumer_key = key; _oauth_consumer_secret = secret; }; /** * Sets the OAuth2 app-only auth bearer token * * @param string token OAuth2 bearer token * * @return void */ var setBearerToken = function (token) { _oauth_bearer_token = token; }; /** * Gets the current Codebird version * * @return string The version number */ var getVersion = function () { return _version; }; /** * Sets the OAuth request or access token and secret (User key) * * @param string token OAuth request or access token * @param string secret OAuth request or access token secret * * @return void */ var setToken = function (token, secret) { _oauth_token = token; _oauth_token_secret = secret; }; /** * Enables or disables CORS proxy * * @param bool use_proxy Whether to use CORS proxy or not * * @return void */ var setUseProxy = function (use_proxy) { _use_proxy = !! use_proxy; }; /** * Parse URL-style parameters into object * * @param string str String to parse * @param array array to load data into * * @return object */ function parse_str(str, array) { // Parses GET/POST/COOKIE data and sets global variables // // version: 1109.2015 // discuss at: http://phpjs.org/functions/parse_str // + original by: Cagri Ekin // + improved by: Michael White (http://getsprink.com) // + tweaked by: Jack // + bugfixed by: Onno Marsman // + reimplemented by: stag019 // + bugfixed by: Brett Zamir (http://brett-zamir.me) // + bugfixed by: stag019 // - depends on: urldecode // + input by: Dreamer // + bugfixed by: Brett Zamir (http://brett-zamir.me) // % note 1: When no argument is specified, will put variables in global scope. // * example 1: var arr = {}; // * example 1: parse_str('first=foo&second=bar', arr); // * results 1: arr == { first: 'foo', second: 'bar' } // * example 2: var arr = {}; // * example 2: parse_str('str_a=Jack+and+Jill+didn%27t+see+the+well.', arr); // * results 2: arr == { str_a: "Jack and Jill didn't see the well." } var glue1 = '=', glue2 = '&', array2 = String(str).replace(/^&?([\s\S]*?)&?$/, '$1').split(glue2), i, j, chr, tmp, key, value, bracket, keys, evalStr, that = this, fixStr = function (str) { return unescape(str).replace(/([\\"'])/g, '\\$1').replace(/\n/g, '\\n').replace(/\r/g, '\\r'); }; if (!array) { array = this.window; } for (i = 0; i < array2.length; i++) { tmp = array2[i].split(glue1); if (tmp.length < 2) { tmp = [tmp, '']; } key = fixStr(tmp[0]); value = fixStr(tmp[1]); while (key.charAt(0) === ' ') { key = key.substr(1); } if (key.indexOf('\0') !== -1) { key = key.substr(0, key.indexOf('\0')); } if (key && key.charAt(0) !== '[') { keys = []; bracket = 0; for (j = 0; j < key.length; j++) { if (key.charAt(j) === '[' && !bracket) { bracket = j + 1; } else if (key.charAt(j) === ']') { if (bracket) { if (!keys.length) { keys.push(key.substr(0, bracket - 1)); } keys.push(key.substr(bracket, j - bracket)); bracket = 0; if (key.charAt(j + 1) !== '[') { break; } } } } if (!keys.length) { keys = [key]; } for (j = 0; j < keys[0].length; j++) { chr = keys[0].charAt(j); if (chr === ' ' || chr === '.' || chr === '[') { keys[0] = keys[0].substr(0, j) + '_' + keys[0].substr(j + 1); } if (chr === '[') { break; } } evalStr = 'array'; for (j = 0; j < keys.length; j++) { key = keys[j]; if ((key !== '' && key !== ' ') || j === 0) { key = "'" + key + "'"; } else { key = eval(evalStr + '.push([]);') - 1; } evalStr += '[' + key + ']'; if (j !== keys.length - 1 && eval('typeof ' + evalStr) === 'undefined') { eval(evalStr + ' = [];'); } } evalStr += " = '" + value + "';\n"; eval(evalStr); } } } /** * Main API handler working on any requests you issue * * @param string fn The member function you called * @param array params The parameters you sent along * @param function callback The callback to call with the reply * @param bool app_only_auth Whether to use app-only auth * * @return mixed The API reply encoded in the set return_format */ var __call = function (fn, params, callback, app_only_auth) { if (typeof params == 'undefined') { var params = {}; } if (typeof app_only_auth == 'undefined') { var app_only_auth = false; } if (typeof callback != 'function' && typeof params == 'function') { callback = params; params = {}; if (typeof callback == 'bool') { app_only_auth = callback; } } else if (typeof callback == 'undefined') { var callback = function (reply) {}; } switch (fn) { case "oauth_authenticate": case "oauth_authorize": return this[fn](params, callback); break; case "oauth2_token": return this[fn](callback); } // parse parameters var apiparams = {}; if (typeof params == 'object') { apiparams = params; } else { parse_str(params, apiparams); //TODO } // map function name to API method var method = ''; // replace _ by / var path = fn.split('_'); for (var i = 0; i < path.length; i++) { if (i > 0) { method += '/'; } method += path[i]; } // undo replacement for URL parameters var url_parameters_with_underscore = ['screen_name']; for (i = 0; i < url_parameters_with_underscore.length; i++) { var param = url_parameters_with_underscore[i].toUpperCase(); var replacement_was = param.split('_').join('/'); method = method.split(replacement_was).join(param); } // replace AA by URL parameters var method_template = method; var match = []; if (match = method.match(/[A-Z_]{2,}/)) { for (var i = 0; i < match.length; i++) { var param = match[i]; var param_l = param.toLowerCase(); method_template = method_template.split(param).join(':' + param_l); if (typeof apiparams[param_l] == 'undefined') { for (j = 0; j < 26; j++) { method_template = method_template.split(String.fromCharCode(65 + j)).join('_' + String.fromCharCode(97 + j)); } console.warn('To call the templated method "' + method_template + '", specify the parameter value for "' + param_l + '".'); } method = method.split(param).join(apiparams[param_l]); delete apiparams[param_l]; } } // replace A-Z by _a-z for (i = 0; i < 26; i++) { method = method.split(String.fromCharCode(65 + i)).join('_' + String.fromCharCode(97 + i)); method_template = method_template.split(String.fromCharCode(65 + i)).join('_' + String.fromCharCode(97 + i)); } var httpmethod = _detectMethod(method_template, apiparams); var multipart = _detectMultipart(method_template); return _callApi( httpmethod, method, method_template, apiparams, multipart, app_only_auth, callback ); }; /** * Gets the OAuth authenticate URL for the current request token * * @return string The OAuth authenticate URL */ var oauth_authenticate = function (params, callback) { if (typeof params.force_login == "undefined") { params.force_login = null; } if (typeof params.screen_name == "undefined") { params.screen_name = null; } if (_oauth_token == null) { console.warn('To get the authenticate URL, the OAuth token must be set.'); } var url = _endpoint_oauth + 'oauth/authenticate?oauth_token=' + _url(_oauth_token); if (params.force_login === true) { url += "?force_login=1"; if (params.screen_name !== null) { url += "&screen_name=" + params.screen_name; } } callback(url); return true; }; /** * Gets the OAuth authorize URL for the current request token * * @return string The OAuth authorize URL */ var oauth_authorize = function (params, callback) { if (typeof params.force_login == "undefined") { params.force_login = null; } if (typeof params.screen_name == "undefined") { params.screen_name = null; } if (_oauth_token == null) { console.warn('To get the authorize URL, the OAuth token must be set.'); } var url = _endpoint_oauth + 'oauth/authorize?oauth_token=' + _url(_oauth_token); if (params.force_login === true) { url += "?force_login=1"; if (params.screen_name !== null) { url += "&screen_name=" + params.screen_name; } } callback(url); return true; }; /** * Gets the OAuth bearer token * * @return string The OAuth bearer token */ var oauth2_token = function (callback) { if (_oauth_consumer_key == null) { console.warn('To obtain a bearer token, the consumer key must be set.'); } if (typeof callback == "undefined") { var callback = function (reply) {}; } var post_fields = "grant_type=client_credentials"; var url = _endpoint_oauth + "oauth2/token"; if (_use_proxy) { url = url.replace( _endpoint_base, _endpoint_proxy ); } var xml; xml = Ti.Network.createHTTPClient(); xml.open("POST", url, true); xml.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); xml.setRequestHeader( (_use_proxy ? "X-" : "") + "Authorization", "Basic " + base64_encode(_oauth_consumer_key + ":" + _oauth_consumer_secret) ); xml.onreadystatechange = function () { if (xml.readyState >= 4) { var httpstatus = 12027; try { httpstatus = xml.status; } catch (e) {} var reply = _parseApiReply("oauth2/token", xml.responseText); reply.httpstatus = httpstatus; if (httpstatus == 200) { setBearerToken(reply.access_token); } callback(reply); } }; xml.send(post_fields); }; /** * Signing helpers */ /** * URL-encodes the given data * * @param mixed data * * @return mixed The encoded data */ var _url = function (data) { if (typeof data == 'array') { return array_map([ // TODO this, '_url'], data); } else if ((/boolean|number|string/).test(typeof data)) { return encodeURIComponent(data).replace(/!/g, '%21').replace(/'/g, '%27').replace(/\(/g, '%28').replace(/\)/g, '%29').replace(/\*/g, '%2A'); } else { return ''; } } /** * Gets the base64-encoded SHA1 hash for the given data * * @param string data The data to calculate the hash from * * @return string The hash */ var _sha1 = function (data) { if (_oauth_consumer_secret == null) { console.warn('To generate a hash, the consumer secret must be set.'); } if (typeof b64_hmac_sha1 != 'function') { console.warn('To generate a hash, the Javascript SHA1.js must be available.'); } b64pad = '='; return b64_hmac_sha1(_oauth_consumer_secret + '&' + (_oauth_token_secret != null ? _oauth_token_secret : ''), data); }; var base64_encode = function (data) { // http://kevin.vanzonneveld.net // + original by: Tyler Akins (http://rumkin.com) // + improved by: Bayron Guevara // + improved by: Thunder.m // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) // + bugfixed by: Pellentesque Malesuada // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) // + improved by: RafaƂ Kukawski (http://kukawski.pl) // * example 1: base64_encode('Kevin van Zonneveld'); // * returns 1: 'S2V2aW4gdmFuIFpvbm5ldmVsZA==' // mozilla has this native // - but breaks in 2.0.0.12! //if (typeof this.window['btoa'] == 'function') { // return btoa(data); //} var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; var o1, o2, o3, h1, h2, h3, h4, bits, i = 0, ac = 0, enc = "", tmp_arr = []; if (! data) { return data; } do { // pack three octets into four hexets o1 = data.charCodeAt(i++); o2 = data.charCodeAt(i++); o3 = data.charCodeAt(i++); bits = o1 << 16 | o2 << 8 | o3; h1 = bits >> 18 & 0x3f; h2 = bits >> 12 & 0x3f; h3 = bits >> 6 & 0x3f; h4 = bits & 0x3f; // use hexets to index into b64, and append result to encoded string tmp_arr[ac++] = b64.charAt(h1) + b64.charAt(h2) + b64.charAt(h3) + b64.charAt(h4); } while (i < data.length); enc = tmp_arr.join(''); var r = data.length % 3; return (r ? enc.slice(0, r - 3) : enc) + '==='.slice(r || 3); }; var http_build_query = function (formdata, numeric_prefix, arg_separator) { // http://kevin.vanzonneveld.net // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) // + improved by: Legaev Andrey // + improved by: Michael White (http://getsprink.com) // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) // + improved by: Brett Zamir (http://brett-zamir.me) // + revised by: stag019 // + input by: Dreamer // + bugfixed by: Brett Zamir (http://brett-zamir.me) // + bugfixed by: MIO_KODUKI (http://mio-koduki.blogspot.com/) // % note 1: If the value is null, key and value is skipped in http_build_query of PHP. But, phpjs is not. var value, key, tmp = [], that = http_build_query; var _http_build_query_helper = function (key, val, arg_separator) { var k, tmp = []; if (val === true) { val = "1"; } else if (val === false) { val = "0"; } if (val != null) { if(typeof(val) === "object") { for (k in val) { if (val[k] != null) { tmp.push(_http_build_query_helper(key + "[" + k + "]", val[k], arg_separator)); } } return tmp.join(arg_separator); } else if (typeof(val) !== "function") { return _url(key) + "=" + _url(val); } else { throw new Error('There was an error processing for http_build_query().'); } } else { return ''; } }; if (!arg_separator) { arg_separator = "&"; } for (key in formdata) { value = formdata[key]; if (numeric_prefix && !isNaN(key)) { key = String(numeric_prefix) + key; } var query=_http_build_query_helper(key, value, arg_separator); if(query != '') { tmp.push(query); } } return tmp.join(arg_separator); }; /** * Generates a (hopefully) unique random string * * @param int optional length The length of the string to generate * * @return string The random string */ var _nonce = function (length) { if (typeof length == 'undefined') { var length = 8; } if (length < 1) { console.warn('Invalid nonce length.'); } var nonce = ''; for (var i = 0; i < length; i++) { var character = Math.floor(Math.random() * 61); nonce += '0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz'.substring(character, character + 1); } return nonce; }; var _ksort = function (inputArr) { // http://kevin.vanzonneveld.net // + original by: GeekFG (http://geekfg.blogspot.com) // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) // + improved by: Brett Zamir (http://brett-zamir.me) var tmp_arr = {}, keys = [], sorter, i, k, that = this, strictForIn = false, populateArr = {}; sorter = function (a, b) { var aFloat = parseFloat(a), bFloat = parseFloat(b), aNumeric = aFloat + '' === a, bNumeric = bFloat + '' === b; if (aNumeric && bNumeric) { return aFloat > bFloat ? 1 : aFloat < bFloat ? -1 : 0; } else if (aNumeric && !bNumeric) { return 1; } else if (!aNumeric && bNumeric) { return -1; } return a > b ? 1 : a < b ? -1 : 0; }; // Make a list of key names for (k in inputArr) { if (inputArr.hasOwnProperty(k)) { keys.push(k); } } keys.sort(sorter); return keys; }; /** * Clone objects * * @param object obj The object to clone * * @return object clone The cloned object */ var _clone = function (obj) { var clone = {}; for (var i in obj) { if (typeof(obj[i]) == "object") { clone[i] = clone(obj[i]); } else { clone[i] = obj[i]; } } return clone; }; /** * Generates an OAuth signature * * @param string httpmethod Usually either 'GET' or 'POST' or 'DELETE' * @param string method The API method to call * @param array optional params The API call parameters, associative * @param bool optional append_to_get Whether to append the OAuth params to GET * * @return string Authorization HTTP header */ var _sign = function (httpmethod, method, params, append_to_get) { if (typeof params == 'undefined') { var params = {}; } if (typeof append_to_get == "undefined") { var append_to_get = false; } if (_oauth_consumer_key == null) { console.warn('To generate a signature, the consumer key must be set.'); } var sign_params = { consumer_key: _oauth_consumer_key, version: '1.0', timestamp: Math.round(new Date().getTime() / 1000), nonce: _nonce(), signature_method: 'HMAC-SHA1' }; var sign_base_params = {}; for (var key in sign_params) { var value = sign_params[key]; sign_base_params['oauth_' + key] = _url(value); } if (_oauth_token != null) { sign_base_params['oauth_token'] = _url(_oauth_token); } oauth_params = _clone(sign_base_params); for (var key in params) { var value = params[key]; sign_base_params[key] = _url(value); } var keys = _ksort(sign_base_params); var sign_base_string = ''; for (var i=0;i -1) { return httpmethod; } } console.warn('Can\'t find HTTP method to use for "' + method + '".'); }; /** * Detects if API call should use multipart/form-data * * @param string method The API method to call * * @return bool Whether the method should be sent as multipart */ var _detectMultipart = function (method) { var multiparts = [ // Tweets 'statuses/update_with_media', // Users 'account/update_profile_background_image', 'account/update_profile_image', 'account/update_profile_banner' ]; return multiparts.indexOf(method) > -1; }; /** * Builds the complete API endpoint url * * @param string method The API method to call * @param string method_template The API method template to call * * @return string The URL to send the request to */ var _getEndpoint = function (method, method_template) { if (method.substring(0, 5) == 'oauth') { var url = _endpoint_oauth + method; } else { var url = _endpoint + method + '.json'; } return url; }; /** * Calls the API using cURL * * @param string httpmethod The HTTP method to use for making the request * @param string method The API method to call * @param string method_template The templated API method to call * @param array optional params The parameters to send along * @param bool optional multipart Whether to use multipart/form-data * @param bool optional $app_only_auth Whether to use app-only bearer authentication * @param function callback The function to call with the API call result * * @return mixed The API reply, encoded in the set return_format */ var _callApi = function (httpmethod, method, method_template, params, multipart, app_only_auth, callback) { if (typeof params == 'undefined') { var params = {}; } if (typeof multipart == 'undefined') { var multipart = false; } if (typeof app_only_auth == 'undefined') { var app_only_auth = false; } if (typeof callback != 'function') { var callback = function (reply) {}; } var url = _getEndpoint(method, method_template); var authorization = null; var xml = Ti.Network.createHTTPClient(); if (httpmethod == 'GET') { var url_with_params = url; if (JSON.stringify(params) != "{}") { url_with_params += '?' + http_build_query(params); } authorization = _sign(httpmethod, url, params); // append auth params to GET url for IE7-9, to send via JSONP if (_use_jsonp) { if (JSON.stringify(params) != "{}") { url_with_params += '&'; } else { url_with_params += '?'; } var callback_name = _nonce(); window[callback_name] = function (reply) { reply.httpstatus = 200; callback(reply); }; params.callback = callback_name; url_with_params = url + "?" + _sign(httpmethod, url, params, true); var tag = document.createElement("script"); tag.type = "text/javascript"; tag.src = url_with_params; var body = document.getElementsByTagName("body")[0]; body.appendChild(tag); return; } else if (_use_proxy) { url_with_params = url_with_params.replace( _endpoint_base, _endpoint_proxy ); } xml.open(httpmethod, url_with_params, true); } else { if (_use_jsonp) { console.warn('Sending POST requests is not supported for IE7-9.'); return; } authorization = _sign(httpmethod, url, {}); if (! multipart) { authorization = _sign(httpmethod, url, params); params = http_build_query(params); } post_fields = params; if (_use_proxy) { url = url.replace( _endpoint_base, _endpoint_proxy ); } xml.open(httpmethod, url, true); if (multipart) { xml.setRequestHeader("Content-Type", "multipart/form-data"); } else { xml.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); } } if (app_only_auth) { if (_oauth_consumer_key == null) { console.warn('To make an app-only auth API request, the consumer key must be set.'); } // automatically fetch bearer token, if necessary if (_oauth_bearer_token == null) { return oauth2_token(function (reply) { _callApi(httpmethod, method, method_template, params, multipart, app_only_auth, callback); }); } authorization = 'Bearer ' + _oauth_bearer_token; } if (authorization !== null) { xml.setRequestHeader((_use_proxy ? "X-" : "") + "Authorization", authorization); } xml.onreadystatechange = function () { if (xml.readyState >= 4) { var httpstatus = 12027; try { httpstatus = xml.status; } catch (e) {} if(!httpstatus){ httpstatus = 12027; } var reply = _parseApiReply(method_template, xml.responseText); if(!reply){ callback(null); } reply.httpstatus = httpstatus; callback(reply); } }; xml.send(httpmethod == "GET" ? null : post_fields); return true; }; /** * Parses the API reply to encode it in the set return_format * * @param string method The method that has been called * @param string reply The actual reply, JSON-encoded or URL-encoded * * @return array|object The parsed reply */ var _parseApiReply = function (method, reply) { if (reply == '[]' || reply == null) { return []; } var parsed = false; try { parsed = JSON.parse(reply); } catch (e) { parsed = {}; if (reply.indexOf('<' + '?xml version="1.0" encoding="UTF-8"?' + '>') === 0) { // we received XML... // since this only happens for errors, // don't perform a full decoding parsed["request"] = reply.match(/(.*)<\/request>/)[1]; parsed["error"] = reply.match(/(.*)<\/error>/)[1]; } else { // assume query format var elements = reply.split("&"); for (var i = 0; i < elements.length; i++) { var element = elements[i].split("=", 2); if (element.length > 1) { parsed[element[0]] = unescape(element[1]); } else { parsed[element[0]] = null; } } } } return parsed; }; return { setConsumerKey: setConsumerKey, getVersion: getVersion, setToken: setToken, setBearerToken: setBearerToken, setUseProxy: setUseProxy, __call: __call, oauth_authenticate: oauth_authenticate, oauth_authorize: oauth_authorize, oauth2_token: oauth2_token }; }; module.exports = Codebird;