constructor facility added
[statusbox:statusbox.git] / dist / statusNet.js
1 /*! Build-Status.net Everywhere 0.1: begin.js connector/additional.js connector/crypt.js connector/store.js connector/oauth.js connector/communicator.js api/APIBase.js api/user.js api/currentUser.js api/status.js api/directMessage.js api/search.js api/statusNet.js api/eventManager.js end.js */
2 //creating the namespace
3 var net={};
4 net.status={};
5 net.status.js={};/*!
6  * Crypto-JS v2.0.0
7  * http://code.google.com/p/crypto-js/
8  * Copyright (c) 2009, Jeff Mott. All rights reserved.
9  * http://code.google.com/p/crypto-js/wiki/License
10  */
11 (function(){
12
13 var base64map = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
14
15 // Global Crypto object
16 var Crypto = window.Crypto = {};
17
18 // Crypto utilities
19 var util = Crypto.util = {
20
21         // Bit-wise rotate left
22         rotl: function (n, b) {
23                 return (n << b) | (n >>> (32 - b));
24         },
25
26         // Bit-wise rotate right
27         rotr: function (n, b) {
28                 return (n << (32 - b)) | (n >>> b);
29         },
30
31         // Swap big-endian to little-endian and vice versa
32         endian: function (n) {
33
34                 // If number given, swap endian
35                 if (n.constructor == Number) {
36                         return util.rotl(n,  8) & 0x00FF00FF |
37                                util.rotl(n, 24) & 0xFF00FF00;
38                 }
39
40                 // Else, assume array and swap all items
41                 for (var i = 0; i < n.length; i++){
42                         n[i] = util.endian(n[i]);
43                 }
44                 return n;
45
46         },
47
48         // Generate an array of any length of random bytes
49         randomBytes: function (n) {
50                 for (var bytes = []; n > 0; n--){
51                         bytes.push(Math.floor(Math.random() * 256));
52                 }
53                 return bytes;
54         },
55
56         // Convert a byte array to big-endian 32-bit words
57         bytesToWords: function (bytes) {
58                 for (var words = [], i = 0, b = 0; i < bytes.length; i++, b += 8){
59                         words[b >>> 5] |= bytes[i] << (24 - b % 32);
60                 }
61                 return words;
62         },
63
64         // Convert big-endian 32-bit words to a byte array
65         wordsToBytes: function (words) {
66                 for (var bytes = [], b = 0; b < words.length * 32; b += 8){
67                         bytes.push((words[b >>> 5] >>> (24 - b % 32)) & 0xFF);
68                 }
69                 return bytes;
70         },
71
72         // Convert a byte array to a hex string
73         bytesToHex: function (bytes) {
74                 for (var hex = [], i = 0; i < bytes.length; i++) {
75                         hex.push((bytes[i] >>> 4).toString(16));
76                         hex.push((bytes[i] & 0xF).toString(16));
77                 }
78                 return hex.join("");
79         },
80
81         // Convert a hex string to a byte array
82         hexToBytes: function (hex) {
83                 for (var bytes = [], c = 0; c < hex.length; c += 2){
84                         bytes.push(parseInt(hex.substr(c, 2), 16));
85                 }
86                 return bytes;
87         },
88
89         // Convert a byte array to a base-64 string
90         bytesToBase64: function (bytes) {
91
92                 // Use browser-native function if it exists
93                 if (typeof btoa == "function") return btoa(Binary.bytesToString(bytes));
94
95                 for(var base64 = [], i = 0; i < bytes.length; i += 3) {
96                         var triplet = (bytes[i] << 16) | (bytes[i + 1] << 8) | bytes[i + 2];
97                         for (var j = 0; j < 4; j++) {
98                                 if (i * 8 + j * 6 <= bytes.length * 8)
99                                         base64.push(base64map.charAt((triplet >>> 6 * (3 - j)) & 0x3F));
100                                 else base64.push("=");
101                         }
102                 }
103
104                 return base64.join("");
105
106         },
107
108         // Convert a base-64 string to a byte array
109         base64ToBytes: function (base64) {
110
111                 // Use browser-native function if it exists
112                 if (typeof atob == "function") return Binary.stringToBytes(atob(base64));
113
114                 // Remove non-base-64 characters
115                 base64 = base64.replace(/[^A-Z0-9+\/]/ig, "");
116
117                 for (var bytes = [], i = 0, imod4 = 0; i < base64.length; imod4 = ++i % 4) {
118                         if (imod4 == 0) continue;
119                         bytes.push(((base64map.indexOf(base64.charAt(i - 1)) & (Math.pow(2, -2 * imod4 + 8) - 1)) << (imod4 * 2)) |
120                                    (base64map.indexOf(base64.charAt(i)) >>> (6 - imod4 * 2)));
121                 }
122
123                 return bytes;
124
125         }
126
127 };
128
129 // Crypto mode namespace
130 Crypto.mode = {};
131
132 // Crypto character encodings
133 var charenc = Crypto.charenc = {};
134
135 // UTF-8 encoding
136 var UTF8 = charenc.UTF8 = {
137
138         // Convert a string to a byte array
139         stringToBytes: function (str) {
140                 return Binary.stringToBytes(unescape(encodeURIComponent(str)));
141         },
142
143         // Convert a byte array to a string
144         bytesToString: function (bytes) {
145                 return decodeURIComponent(escape(Binary.bytesToString(bytes)));
146         }
147
148 };
149
150 // Binary encoding
151 var Binary = charenc.Binary = {
152
153         // Convert a string to a byte array
154         stringToBytes: function (str) {
155                 for (var bytes = [], i = 0; i < str.length; i++){
156                         bytes.push(str.charCodeAt(i));
157                 }
158                 return bytes;
159         },
160
161         // Convert a byte array to a string
162         bytesToString: function (bytes) {
163                 for (var str = [], i = 0; i < bytes.length; i++){
164                         str.push(String.fromCharCode(bytes[i]));
165                 }
166                 return str.join("");
167         }
168
169 };
170
171 })();
172
173 /*!
174  * Crypto-JS v2.0.0
175  * http://code.google.com/p/crypto-js/
176  * Copyright (c) 2009, Jeff Mott. All rights reserved.
177  * http://code.google.com/p/crypto-js/wiki/License
178  */
179 (function(){
180
181 // Shortcuts
182 var C = Crypto,
183     util = C.util,
184     charenc = C.charenc,
185     UTF8 = charenc.UTF8,
186     Binary = charenc.Binary;
187
188 C.HMAC = function (hasher, message, key, options) {
189
190         // Convert to byte arrays
191         if (message.constructor == String) message = UTF8.stringToBytes(message);
192         if (key.constructor == String) key = UTF8.stringToBytes(key);
193         /* else, assume byte arrays already */
194
195         // Allow arbitrary length keys
196         if (key.length > hasher._blocksize * 4)
197                 key = hasher(key, { asBytes: true });
198
199         // XOR keys with pad constants
200         var okey = key.slice(0),
201             ikey = key.slice(0);
202         for (var i = 0; i < hasher._blocksize * 4; i++) {
203                 okey[i] ^= 0x5C;
204                 ikey[i] ^= 0x36;
205         }
206
207         var hmacbytes = hasher(okey.concat(hasher(ikey.concat(message), { asBytes: true })), { asBytes: true });
208
209         return options && options.asBytes ? hmacbytes :
210                options && options.asString ? Binary.bytesToString(hmacbytes) :
211                util.bytesToHex(hmacbytes);
212
213 };
214
215 })();
216
217 /*!
218  * Crypto-JS v2.0.0
219  * http://code.google.com/p/crypto-js/
220  * Copyright (c) 2009, Jeff Mott. All rights reserved.
221  * http://code.google.com/p/crypto-js/wiki/License
222  */
223 (function(){
224
225 // Shortcuts
226 var C = Crypto,
227     util = C.util,
228     charenc = C.charenc,
229     UTF8 = charenc.UTF8,
230     Binary = charenc.Binary;
231
232 // Public API
233 var SHA1 = C.SHA1 = function (message, options) {
234         var digestbytes = util.wordsToBytes(SHA1._sha1(message));
235         return options && options.asBytes ? digestbytes :
236                options && options.asString ? Binary.bytesToString(digestbytes) :
237                util.bytesToHex(digestbytes);
238 };
239
240 // The core
241 SHA1._sha1 = function (message) {
242
243         // Convert to byte array
244         if (message.constructor == String) message = UTF8.stringToBytes(message);
245         /* else, assume byte array already */
246
247         var m  = util.bytesToWords(message),
248             l  = message.length * 8,
249             w  =  [],
250             H0 =  1732584193,
251             H1 = -271733879,
252             H2 = -1732584194,
253             H3 =  271733878,
254             H4 = -1009589776;
255
256         // Padding
257         m[l >> 5] |= 0x80 << (24 - l % 32);
258         m[((l + 64 >>> 9) << 4) + 15] = l;
259
260         for (var i = 0; i < m.length; i += 16) {
261
262                 var a = H0,
263                     b = H1,
264                     c = H2,
265                     d = H3,
266                     e = H4;
267
268                 for (var j = 0; j < 80; j++) {
269
270                         if (j < 16) w[j] = m[i + j];
271                         else {
272                                 var n = w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16];
273                                 w[j] = (n << 1) | (n >>> 31);
274                         }
275
276                         var t = ((H0 << 5) | (H0 >>> 27)) + H4 + (w[j] >>> 0) + (
277                                  j < 20 ? (H1 & H2 | ~H1 & H3) + 1518500249 :
278                                  j < 40 ? (H1 ^ H2 ^ H3) + 1859775393 :
279                                  j < 60 ? (H1 & H2 | H1 & H3 | H2 & H3) - 1894007588 :
280                                           (H1 ^ H2 ^ H3) - 899497514);
281
282                         H4 =  H3;
283                         H3 =  H2;
284                         H2 = (H1 << 30) | (H1 >>> 2);
285                         H1 =  H0;
286                         H0 =  t;
287
288                 }
289
290                 H0 += a;
291                 H1 += b;
292                 H2 += c;
293                 H3 += d;
294                 H4 += e;
295
296         }
297
298         return [H0, H1, H2, H3, H4];
299
300 };
301
302 // Package private blocksize
303 SHA1._blocksize = 16;
304
305 })();
306
307
308 /**
309  * StatusNet - the distributed open-source microblogging tool
310  * Copyright (C) 2008, 2009, StatusNet, Inc.
311  *
312  * This program is free software: you can redistribute it and/or modify
313  * it under the terms of the GNU Affero General Public License as published by
314  * the Free Software Foundation, either version 3 of the License, or
315  * (at your option) any later version.
316  *
317  * This program is distributed in the hope that it will be useful,
318  * but WITHOUT ANY WARRANTY; without even the implied warranty of
319  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
320  * GNU Affero General Public License for more details.
321  *
322  * You should have received a copy of the GNU Affero General Public License
323  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
324  *
325  * @category StatusNet
326  * @package  StausBox
327  * @author   Arunoda Susiripala <arunoda.susiripala@gmail.com>
328  *
329  * @license  GNU Affero General Public License http://www.gnu.org/licenses/ 
330  * 
331  * 
332  * This code borrows some of its parts from 
333  * http://github.com/bytespider/jsOAuth.git
334  * 
335  */
336
337 function Store(prefix){
338         this.prefix=(prefix)?prefix:"";
339         //in days
340         var expiryDays=365;
341         this.setToken=function(token){
342                 this.cookie(this.prefix + 'oauth_token',token,{expires: expiryDays});
343         };
344         
345         this.setTokenSecret=function(tokenSecret){
346                 this.cookie(this.prefix + 'oauth_token_secret',tokenSecret,{expires: expiryDays});
347         };
348         
349         this.getToken=function(){
350                 return this.cookie(this.prefix + 'oauth_token');
351         };
352         
353         this.getTokenSecret=function(){
354                 return this.cookie(this.prefix + 'oauth_token_secret');
355         };
356         
357         this.cookie=function(name, value, options) {
358             if (typeof value != 'undefined') { // name and value given, set cookie
359                 options = options || {};
360                 if (value === null) {
361                     value = '';
362                     options.expires = -1;
363                 }
364                 var expires = '';
365                 if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) {
366                     var date;
367                     if (typeof options.expires == 'number') {
368                         date = new Date();
369                         date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000));
370                     } else {
371                         date = options.expires;
372                     }
373                     expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE
374                 }
375                 // CAUTION: Needed to parenthesize options.path and options.domain
376                 // in the following expressions, otherwise they evaluate to undefined
377                 // in the packed version for some reason...
378                 var path = options.path ? '; path=' + (options.path) : '';
379                 var domain = options.domain ? '; domain=' + (options.domain) : '';
380                 var secure = options.secure ? '; secure' : '';
381                 document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join('');
382             } else { // only name given, get cookie
383                 var cookieValue = undefined;
384                 if (document.cookie && document.cookie != '') {
385                     var cookies = document.cookie.split(';');
386                     for (var i = 0; i < cookies.length; i++) {
387                         //trim the cookies
388                         var cookie = cookies[i].replace(/^\s*/, "").replace(/\s*$/, "");
389                         // Does this cookie string begin with the name we want?
390                         if (cookie.substring(0, name.length + 1) == (name + '=')) {
391                             cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
392                             break;
393                         }
394                     }
395                 }
396                 return cookieValue;
397             }
398         };
399 }/**
400  * StatusNet - the distributed open-source microblogging tool
401  * Copyright (C) 2008, 2009, StatusNet, Inc.
402  *
403  * This program is free software: you can redistribute it and/or modify
404  * it under the terms of the GNU Affero General Public License as published by
405  * the Free Software Foundation, either version 3 of the License, or
406  * (at your option) any later version.
407  *
408  * This program is distributed in the hope that it will be useful,
409  * but WITHOUT ANY WARRANTY; without even the implied warranty of
410  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
411  * GNU Affero General Public License for more details.
412  *
413  * You should have received a copy of the GNU Affero General Public License
414  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
415  *
416  * @category StatusNet
417  * @package  StausBox
418  * @author   Arunoda Susiripala <arunoda.susiripala@gmail.com>
419  *
420  * @license  GNU Affero General Public License http://www.gnu.org/licenses/ 
421  * 
422  * 
423  * This code borrows some of its parts from 
424  * http://github.com/bytespider/jsOAuth.git
425  * 
426  */
427
428
429 function OAuth(tokenStore){
430         var store=tokenStore;
431         this.method="GET";
432         this.endpoint;
433         this.oauthParams={
434             'oauth_consumer_key': '',
435             'oauth_nonce': '',
436             'oauth_signature_method': 'HMAC-SHA1',
437             'oauth_timestamp': '',
438             'oauth_token': '',
439             'oauth_version': '1.0'
440         };
441         
442         this.consumerSecret;
443         
444         //public functions
445         this.init=function(consumerKey,consumerSecret,endpoint){
446                 this.oauthParams.oauth_consumer_key=consumerKey;
447                 this.consumerSecret=consumerSecret;
448                 this.endpoint=endpoint;
449                 this.oauthParams.oauth_nonce=getNonce();
450                 this.oauthParams.oauth_timestamp=getTimestamp();
451         };
452         
453         this.getRequestTokenUrl=function(){
454                 store.setToken(null);
455                 store.setTokenSecret(null);
456                 this.refreshOAuthTokens();
457                 var url=this.endpoint+"/oauth/request_token";
458                 return this.getURL(url);
459         };
460         
461         this.getAuthorizationUrl=function(){
462                 var url=this.endpoint+"/oauth/authorize";
463                 url+="?oauth_token="+store.getToken();
464                 return url;
465         };
466         
467         this.getAccessTokenUrl=function(){
468                 this.refreshOAuthTokens();
469                 var url=this.endpoint+"/oauth/access_token";
470                 return this.getURL(url);
471         };
472         
473         this.getAuthorizedMessageUrl=function(message,params,callback){
474                 //working with callback
475                 var callbackName="callback_" + Math.floor(Math.random()*10000);
476                 jQuery.globalEval("var " + callbackName +"=" + callback);
477                 if(!params){
478                         params={callback:callbackName};
479                 }
480                 else{
481                         params.callback=callbackName;
482                 }
483                 
484                 this.refreshOAuthTokens();
485                 var url=this.endpoint+message;
486                 return this.getURL(url, params);
487         };
488         
489         this.getRequestAPIUrl=function(message,params,isPost){
490                 this.refreshOAuthTokens();
491                 if(isPost) {
492                         this.method="POST";
493                 }else{
494                         this.method="GET";
495                 }
496                 var url=this.endpoint+message;
497                 var rtnUrl=this.getURL(url, params);
498                 ////console.log(rtnUrl);
499                 return rtnUrl;
500         };
501         
502         //private functions
503         var getNonce=function(key_length) {
504                 key_length = key_length || 64;
505                 
506                 var key_bytes = key_length / 8;
507                 var value = '';
508                 var key_iter = key_bytes / 4;
509                 var key_remainder = key_bytes % 4;
510                 var chars = ['20', '21', '22', '23', '24', '25', '26', '27', '28', '29', 
511                              '2A', '2B', '2C', '2D', '2E', '2F', '30', '31', '32', '33', 
512                              '34', '35', '36', '37', '38', '39', '3A', '3B', '3C', '3D', 
513                              '3E', '3F', '40', '41', '42', '43', '44', '45', '46', '47', 
514                              '48', '49', '4A', '4B', '4C', '4D', '4E', '4F', '50', '51', 
515                              '52', '53', '54', '55', '56', '57', '58', '59', '5A', '5B', 
516                              '5C', '5D', '5E', '5F', '60', '61', '62', '63', '64', '65', 
517                              '66', '67', '68', '69', '6A', '6B', '6C', '6D', '6E', '6F', 
518                              '70', '71', '72', '73', '74', '75', '76', '77', '78', '79', 
519                              '7A', '7B', '7C', '7D', '7E'];
520                 
521                 for (var i = 0; i < key_iter; i++) {
522                     value += chars[rand()] + chars[rand()] + chars[rand()]+ chars[rand()];
523                 }
524                 
525                 // handle remaing bytes
526                 for (var i = 0; i < key_remainder; i++) {
527                     value += chars[rand()];
528                 }
529                 
530                 return value;
531                 
532                 function rand() {
533                     return Math.floor(Math.random() * chars.length);
534                 }
535         };
536         
537         var getTimestamp=function() {
538                 return parseInt(+new Date / 1000); // use short form of getting a timestamp
539         };
540         
541         var lexicologicalSort=function(object) {
542                 var keys = [];
543                 for (var k in object) {
544                         keys.push(k);
545                 }
546
547                 var o = object;
548                 object = {}; // reset
549                 keys.sort();
550                 
551                 for(var k = 0; k < keys.length; k++) {
552                         object[keys[k]] = o[keys[k]];
553                 }
554         
555                 return o;       
556         };
557         
558         this.toSignatureBaseString=function(url,queryParam){
559                 var arr = [];
560                 var oauth_header_params=lexicologicalSort(this.oauthParams);
561                 var query_params=lexicologicalSort(queryParam);
562                 
563                 for (i in oauth_header_params) {
564                                 if (oauth_header_params[i] && oauth_header_params[i] != undefined) {
565                                         arr.push(OAuthUtilities.urlEncode(i) + '=' + OAuthUtilities.urlEncode(oauth_header_params[i]+'').replace(/\+/g,"%20"));
566                                 }
567                 }
568                 for (i in query_params) {
569                                 if (query_params[i] && query_params[i] != undefined) {
570                                         arr.push(OAuthUtilities.urlEncode(i) + '=' + OAuthUtilities.urlEncode(query_params[i]+'').replace(/\+/g,"%20"));
571                                 }
572                 }
573                 ////console.log(this.method);
574         return [
575             this.method, 
576             OAuthUtilities.urlEncode(url), 
577             OAuthUtilities.urlEncode(arr.sort().join('&'))
578         ].join('&');
579     };
580     
581     this.getSignature=function(url,queryParam){
582                 
583         var consumer_secret = OAuthUtilities.urlEncode(this.consumerSecret);
584                 var token_secret = OAuthUtilities.urlEncode(store.getTokenSecret() || '');
585         var passphrase = consumer_secret + '&' + token_secret;
586
587                 var signature_base = this.toSignatureBaseString(url,queryParam);
588         var signature = Crypto.HMAC(Crypto.SHA1, signature_base, consumer_secret + '&' + token_secret, {asBytes: true});
589                 
590         //console.log(signature_base);
591         //console.log(passphrase);
592         //console.log(signature);
593         
594         //console.log(Crypto.util.bytesToBase64(signature));
595         //console.log(btoa(signature));
596         
597         return Crypto.util.bytesToBase64(signature);
598         
599     };
600     
601     this.getURL=function(url,queryParam){
602         var oauth_header_params=lexicologicalSort(this.oauthParams);
603                 var query_params=lexicologicalSort(queryParam);
604                 var signature=this.getSignature(url,query_params);
605                 
606                 for(i in query_params){
607                         if(query_params[i]==undefined) continue;
608                         url+="&"+i+"="+OAuthUtilities.urlEncode("" + query_params[i]);
609                 }
610                 
611                 for(i in oauth_header_params){
612                         if(oauth_header_params[i]==undefined) continue;
613                         
614                         //using "" + string - inorder to convert integers to string too
615                         url+="&"+i+"="+ OAuthUtilities.urlEncode("" + oauth_header_params[i]);
616                 }
617                 
618                 url+="&oauth_signature="+OAuthUtilities.urlEncode(signature);
619                 return url.replace('&','?');
620     };
621     
622     this.refreshOAuthTokens=function(){
623         this.oauthParams.oauth_nonce=getNonce();
624         this.oauthParams.oauth_timestamp=getTimestamp();
625         this.oauthParams.oauth_token=store.getToken();
626     };
627         
628 }
629
630 OAuth.parseToken=function(qryString){
631         var list=qryString.split('&');
632         var map={};
633         for (index in list){
634                 var parts=list[index].split('=');
635                 map[parts[0]]=parts[1];
636         }
637         
638         return map;
639 };
640
641 function OAuthUtilities() {}
642
643 OAuthUtilities.urlEncode = function(str) {
644     // http://kevin.vanzonneveld.net
645     // +   original by: Philip Peterson
646     // +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
647     // +      input by: AJ
648     // +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
649     // +   improved by: Brett Zamir (http://brett-zamir.me)
650     // +   bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
651     // +      input by: travc
652     // +      input by: Brett Zamir (http://brett-zamir.me)
653     // +   bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
654     // +   improved by: Lars Fischer
655     // +      input by: Ratheous
656     // +      reimplemented by: Brett Zamir (http://brett-zamir.me)
657     // +   bugfixed by: Joris
658     // +      reimplemented by: Brett Zamir (http://brett-zamir.me)
659     // %          note 1: This reflects PHP 5.3/6.0+ behavior
660     // %        note 2: Please be aware that this function expects to encode into UTF-8 encoded strings, as found on
661     // %        note 2: pages served as UTF-8
662     // *     example 1: urlencode('Kevin van Zonneveld!');
663     // *     returns 1: 'Kevin+van+Zonneveld%21'
664     // *     example 2: urlencode('http://kevin.vanzonneveld.net/');
665     // *     returns 2: 'http%3A%2F%2Fkevin.vanzonneveld.net%2F'
666     // *     example 3: urlencode('http://www.google.nl/search?q=php.js&ie=utf-8&oe=utf-8&aq=t&rls=com.ubuntu:en-US:unofficial&client=firefox-a');
667     // *     returns 3: 'http%3A%2F%2Fwww.google.nl%2Fsearch%3Fq%3Dphp.js%26ie%3Dutf-8%26oe%3Dutf-8%26aq%3Dt%26rls%3Dcom.ubuntu%3Aen-US%3Aunofficial%26client%3Dfirefox-a'
668
669     str = (str+'').toString();
670     
671     // Tilde should be allowed unescaped in future versions of PHP (as reflected below), but if you want to reflect current
672     // PHP behavior, you would need to add ".replace(/~/g, '%7E');" to the following.
673     return encodeURIComponent(str).replace(/!/g, '%21').replace(/'/g, '%27').replace(/\(/g, '%28').
674                                                                     replace(/\)/g, '%29').replace(/\*/g, '%2A').replace(/%20/g, '+');
675 };
676
677 OAuthUtilities.urlDecode = function (str) {
678     // http://kevin.vanzonneveld.net
679     // +   original by: Philip Peterson
680     // +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
681     // +      input by: AJ
682     // +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
683     // +   improved by: Brett Zamir (http://brett-zamir.me)
684     // +      input by: travc
685     // +      input by: Brett Zamir (http://brett-zamir.me)
686     // +   bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
687     // +   improved by: Lars Fischer
688     // +      input by: Ratheous
689     // +   improved by: Orlando
690     // +      reimplemented by: Brett Zamir (http://brett-zamir.me)
691     // +      bugfixed by: Rob
692     // %        note 1: info on what encoding functions to use from: http://xkr.us/articles/javascript/encode-compare/
693     // %        note 2: Please be aware that this function expects to decode from UTF-8 encoded strings, as found on
694     // %        note 2: pages served as UTF-8
695     // *     example 1: urldecode('Kevin+van+Zonneveld%21');
696     // *     returns 1: 'Kevin van Zonneveld!'
697     // *     example 2: urldecode('http%3A%2F%2Fkevin.vanzonneveld.net%2F');
698     // *     returns 2: 'http://kevin.vanzonneveld.net/'
699     // *     example 3: urldecode('http%3A%2F%2Fwww.google.nl%2Fsearch%3Fq%3Dphp.js%26ie%3Dutf-8%26oe%3Dutf-8%26aq%3Dt%26rls%3Dcom.ubuntu%3Aen-US%3Aunofficial%26client%3Dfirefox-a');
700     // *     returns 3: 'http://www.google.nl/search?q=php.js&ie=utf-8&oe=utf-8&aq=t&rls=com.ubuntu:en-US:unofficial&client=firefox-a'
701     
702     return decodeURIComponent(str.replace(/\+/g, '%20'));
703 };net.status.js.Communicator=function(oauth){
704         this.oauth=oauth;
705         
706         /**
707          * @param method the endpoint of the api
708          *              eg:- /statuses/show.json
709          * @param params the array of parameters to be send to the service
710          * @param type the type of the response Object
711          * @param callback is the callback function to executed with the response
712          * @param custom the custom code to be append before the callback
713          * @param proxy whether to use Proxy method instead direct jsonp
714          * possible valiues GET | POST | null
715          * @param parentAPI the related API instance 
716          * eg:- Identi.ca or abc.status.net
717          */
718         this.requestAPI=function(method,params,type,callback,custom,proxy,parentAPI){
719                 var alteration="if("+ type +") response=net.status.js.Communicator.buildObject(response,'" + type + "',"+parentAPI+");";
720                 if(custom) alteration+=custom;
721                 if(proxy){
722                         var isPost=(proxy=="POST")?true:false;
723                         this.requestAPIWithAlteredResponseProxy
724                                 (method,params,callback,alteration,isPost);
725                 }
726                 else{
727                         this.requestAPIWithAlteredResponse(method,params,callback,alteration);
728                 }
729         };
730         
731         /**
732          * @param method api endpoint
733          * @param parametes in a Object
734          * @callback a callback function like function(response){..}
735          * @param alteration this is the codes where we can alter the response befor is gets to
736          * the callback
737          * the returning response is a variable called response
738          * you can alter it or add any code before that.
739          */
740         this.requestAPIWithAlteredResponse=function(method,params,callback,alteration){
741                 //make callback Global
742                 if(callback){
743                         var modifiedCallback=
744                                 net.status.js.Communicator.createGlobalFunctionWithAlteration(callback,alteration);
745                         
746                         if(!params)     params={callback:modifiedCallback};
747                         else params.callback=modifiedCallback;
748                 }
749                 
750                 var url=this.oauth.getRequestAPIUrl(method,params);
751                 
752                 jQuery.getScript(url);
753         };
754         
755         /**
756          * Same as requestAPIWithAlteredResponse() but using sendJSON Proxy
757          * 
758          * @param method api endpoint
759          * @param parametes in a Object
760          * @callback a callback function like function(response){..}
761          * @param alteration this is the codes where we can alter the response befor is gets to
762          * the callback
763          * the returning response is a variable called response
764          * you can alter it or add any code before that.
765          */
766         this.requestAPIWithAlteredResponseProxy=function(method,params,callback,alteration,isPost){
767                 //make callback Global
768                 var modifiedCallback="";
769                 if(callback){
770                         modifiedCallback=
771                                 net.status.js.Communicator.createGlobalFunctionWithAlteration(callback,alteration);
772                 }
773                 
774                 var url=this.oauth.getRequestAPIUrl(method,params,isPost);
775                 net.status.js.Communicator.sendJSON(url,modifiedCallback,isPost);
776         };
777
778 };
779
780
781 net.status.js.Communicator.createGlobalFunction=function(func){
782         //make callback Global
783         var callbackName="callback_" + Math.floor(Math.random()*10000);
784         jQuery.globalEval("var " + callbackName +"=" + func);
785         return callbackName;
786 };
787
788 net.status.js.Communicator.createDynamicFunction=function(script){
789         //make callback Global
790         var callbackName="callback_" + Math.floor(Math.random()*10000);
791         var func="function "+ callbackName +"(){"+script+"} ";
792         jQuery.globalEval(func);
793         return callbackName;
794 };
795
796 net.status.js.Communicator.createGlobalFunctionWithAlteration=function(callback,alteration){
797         //make callback Global
798         if(callback){
799                 var callbackName="callback_" + Math.floor(Math.random()*10000);
800                 jQuery.globalEval("var " + callbackName +"=" + callback);
801                 
802                 //creating modified callback
803                 
804                 var modifiedCallback=callbackName + "_m";
805                 var func=
806                         "function " + modifiedCallback + "(response){ " +
807                         alteration +
808                         "       " + callbackName + "(response);" +
809                         "}";
810                 
811                 jQuery.globalEval(func);
812         }
813         
814         return modifiedCallback;
815 };
816
817
818 /**
819  * @param url url to be request
820  * @callback string name of the callback tobe called
821  * 
822  */
823 net.status.js.Communicator.sendJSON=function(url,callbackName,isPost){
824         url=OAuthUtilities.urlEncode(url);
825         var callUrl="http://127.0.0.1/gsoc/statusbox/test/proxy.php?action=json&url=" + url + "&callback=" + callbackName ;
826         if(isPost) callUrl+="&isPost=1";
827         //console.log(callUrl);
828         jQuery.getScript(callUrl); 
829 };
830
831
832 //this will generate the perticular Object from the return response from the
833 //OAuth API
834 /**
835  * @param response the raw Object or Array of Objects
836  * @param type the type of the Object to build
837  * @param parentAPI the related API instance 
838  * eg:- Identi.ca or abc.status.net
839  */
840 net.status.js.Communicator.buildObject=function(response,type,parentAPI){
841         if(response instanceof Array){
842                 var users=[];
843                 for(item in response){
844                         users[item]=builtSingle(response[item],parentAPI);
845                 }
846                 return users;
847         }
848         else{
849                 return builtSingle(response,parentAPI);
850         }
851         
852         function builtSingle(data,parentAPI){
853                 var item;
854                 var addslashes=function (str) {
855                         if( typeof str != 'string') return str;
856                         str=str.replace(/\\/g,'\\\\');
857                         str=str.replace(/\'/g,'\\\'');
858                         str=str.replace(/\"/g,'\\"');
859                         str=str.replace(/\0/g,'\\0');
860                         return str;
861                 };
862
863                 eval("item=new " + type + "()");
864                 jQuery.extend(item,data);
865                 if(item.api) item.api(parentAPI);
866                 //calls the constructor();
867                 item.construct();
868                 
869                 return item;
870         }
871         
872 };
873
874 net.status.js.APIBase=function(){
875         this.method=null;
876         this.params=null;
877         this.type=null;
878         /**
879          * If the alternation in place ready() will use this. 
880          * this is javascripts which runs before the callback provided
881          */
882         this.alteration="";
883         
884         /**
885          * If the authentication needs for the request
886          */
887         this.auth=false;
888         
889         this.offlineError=null;
890         
891         this.additionalParams={};
892         
893         /**
894          * conatins GET or POST if wanted to use proxy method
895          * for request instead direct JSONP
896          * with direct JSONP you cant handle POST means no write access with the API
897          */
898         this.proxy=null;
899         
900         //this contains the cross reference to the Parent StatusNet Object
901         this.API=null;
902         
903         //this will work as an constructor
904         //this will be called at the init function of the child classes
905         //and in the create Object in the Communicator too
906         this.construct=function(){
907                 this.additionalParams={};
908                 this.auth=false;
909         };
910         
911         
912         //this is the callback handler for any method
913         this.ready=function(callback){
914                 //if oauth authentication needs
915                 if(this.auth){
916                         var altering=this.alteration;
917                         //hack to allow add cross reference with the request too
918                         this.alteration=null;
919                         this.API.communicator.requestAPI(this.method,this.getParamObject(this.params),
920                                         this.type,callback,altering,this.proxy,this.API.instance_name);
921                         //cleaning up
922                         this.proxy=null;
923                 }
924                 else{
925                         var alteration="if("+ this.type +") response=net.status.js.Communicator.buildObject(response,'" + this.type + "',"+this.API.instance_name+");";
926                         
927                         var mCallback=
928                                 net.status.js.Communicator.createGlobalFunctionWithAlteration(callback,alteration);
929                 
930                         var paramsString=net.status.js.APIBase.getParamString(this.getParamObject(this.params));
931                         //console.log(this.params);
932                         paramsString+="callback=" + mCallback;
933                         var url=SN.endpoint + this.method ;
934                         if(url.lastIndexOf("?")>=0){
935                                 url+="&" + paramsString;
936                         }else{
937                                 url+="?" + paramsString;
938                         }
939                         
940                         
941                         jQuery.getScript(url);
942                 }
943                 
944                 
945                 
946         };
947         
948         this.count=function(c){
949                 this.additionalParams.count=c;
950                 return this;
951         };
952         
953         this.since=function(c){
954                 this.additionalParams.since_id=c;
955                 return this;
956         };
957         
958         this.max=function(c){
959                 this.additionalParams.max_id=c;
960                 return this;
961         };
962         
963         this.page=function(c){
964                 this.additionalParams.page=c;
965                 return this;
966         };
967         
968         /**
969          * This will generated the param object with the supplied params
970          */
971         this.getParamObject=function(params){
972                 var rtn={};
973                 for(index in params){
974                         if(!params[index]) continue;
975                         rtn[index]=params[index];
976                 }
977                 
978                 for(index in this.additionalParams){
979                         if(!this.additionalParams[index]) continue;
980                         rtn[index]=this.additionalParams[index];
981                 }
982                 
983                 return rtn;
984         };
985         
986         this.validateOnline=function(){
987                 if(!this.API.isConnected()){
988                         throw "You must be connected in order to use this method";
989                 };
990         };
991         
992         this.api=function(api){
993                 this.API=api;
994                 return this;
995         };
996 };
997
998 net.status.js.APIBase.getParamString=function(obj){
999         var str="";
1000         for(item in obj){
1001                 str+=item + "=" + obj[item] + "&";
1002         }
1003         
1004         return str;
1005 };net.status.js.User=function(p){
1006         this.user_id=null;
1007         this.screen_name=null;
1008         this.id=null;
1009         this.API=p;
1010         
1011         this.construct=function(){
1012                 //calls the super class's contruct()
1013                 this.__proto__.construct();
1014         };
1015         
1016         
1017         this.init=function(identifier){
1018                 //this is must to do.
1019                 //do the initaition of the values
1020                 this.construct();
1021                 
1022                 if(isNaN(identifier)){
1023                         this.screen_name=identifier;
1024                 }
1025                 else{
1026                         this.user_id=identifier;
1027                 }
1028                 this.id=identifier;
1029                 
1030                 this.method="/users/show.json";
1031                 this.params={id:this.id};
1032                 this.type="net.status.js.User";
1033                 
1034         };
1035         
1036         
1037         this.favorites=function(){
1038                 this.method="/favorites.json";
1039                 this.params={id:this.screen_name};
1040                 this.type="net.status.js.Status";
1041                 return this;
1042         };
1043         
1044         this.userTimeline=function(){
1045                 this.method="/statuses/user_timeline.json";
1046                 this.params=this.getUserParams();
1047                 this.type="net.status.js.Status"; 
1048                 return this;
1049         };
1050         
1051         this.followers=function(){
1052                 this.method="/statuses/followers.json";
1053                 this.params=this.getUserParams();
1054                 this.type="net.status.js.User";
1055                 return this;
1056         };
1057         
1058         this.friends=function(){
1059                 this.method="/statuses/friends.json";
1060                 this.params=this.getUserParams();
1061                 this.type="net.status.js.User";
1062                 return this;
1063         };
1064         
1065         this.isFollowing=function(){
1066                 this.validateOnline();
1067                 
1068                 this.method="/friendships/exists.json";
1069                 this.params={user_b:this.id,user_a:net.status.js.User.current().screen_name};
1070                 this.type="null";
1071                 return this;
1072         };
1073         
1074         this.isFriend=function(){
1075                 this.validateOnline();
1076                 
1077                 this.method="/friendships/exists.json";
1078                 this.params={user_a:this.id,user_b:net.status.js.User.current().screen_name};
1079                 this.type="null";
1080                 return this;
1081         };
1082         
1083         this.isMutual=function(){
1084                 this.validateOnline();
1085                 
1086                 this.alteration=
1087                         "var isMutual=false;"+
1088                         "if(response.relationship && response.relationship.source.following && response.relationship.source.followed_by) {"+
1089                         "       isMutual=true;"+
1090                         "}"+
1091                         "response=isMutual;";
1092                 this.method="/friendships/show.json";
1093                 
1094                 if(this.screen_name){
1095                         this.params=
1096                         {source_screen_name:this.screen_name,target_screen_name:net.status.js.User.current().screen_name};
1097                 }
1098                 else if(this.user_id){
1099                         this.params=
1100                         {source_id:this.user_id,target_screen_name:net.status.js.User.current().screen_name};
1101                 }
1102                 
1103                 this.type="null";
1104                 return this;
1105         };
1106         
1107         this.block=function(){
1108                 this.validateOnline();
1109                 this.proxy='POST';
1110                 
1111                 this.method="/blocks/create.json";
1112                 this.params={id:this.id};
1113                 this.type="null";
1114                 return this;
1115         };
1116         
1117         this.unblock=function(){
1118                 this.validateOnline();
1119                 this.proxy='POST';
1120                 this.method="/blocks/destroy.json";
1121                 this.params={id:this.id};
1122                 this.type="null";
1123                 return this;
1124         };
1125         
1126         this.directMessage=this.dm=function(messageText){
1127                 return net.status.js.DirectMessage.send(this.id,messageText);
1128         };
1129         
1130         this.follow=function(){
1131                 this.validateOnline();
1132                 this.proxy='POST';
1133                 this.method="/friendships/create.json";
1134                 this.params={id:this.id};
1135                 this.type="net.status.js.User";
1136                 return this;
1137         };      
1138         
1139         this.unfollow=function(){
1140                 this.validateOnline();
1141                 this.proxy='POST';
1142                 this.method="/friendships/destroy.json";
1143                 this.params={id:this.id};
1144                 this.type="net.status.js.User";
1145                 return this;
1146         };      
1147         
1148         this.getUserParams=function(params){
1149                 var rtn= {screen_name:this.screen_name,user_id:this.user_id};
1150                 jQuery.extend(rtn,params);
1151                 return rtn;
1152         };
1153
1154 };
1155
1156 //inheritance
1157 net.status.js.User.prototype=new net.status.js.APIBase();
1158
1159 net.status.js.User.find=function(identifier){
1160         if(!identifier) throw "Please enter an ID";
1161         var user=new net.status.js.User(this.parent);
1162         user.init(identifier);
1163         return user;
1164 };
1165
1166 //supports only screen names
1167 //not yet user_id's
1168 net.status.js.User.findAll=function(identifiers){
1169         console.error("Not Implemented Yet! Finding a API endpoing");
1170 };
1171
1172 net.status.js.User.current=function(){
1173         var curr=this.parent.currentUser;
1174         //curr.api(this.parent);
1175         return curr;
1176 };
1177
1178 net.status.js.CurrentUser=function(){
1179         this.directMessages=this.dms=this.receivedMessages=function(){
1180                 this.validateOnline();
1181                 this.proxy='POST';
1182                 this.method="/direct_messages.json";
1183                 this.type=null;
1184                 return this;
1185         };
1186         
1187         
1188         this.sentMessages=function(){
1189                 this.validateOnline();
1190                 this.proxy='POST';
1191                 this.method="/direct_messages/sent.json";
1192                 this.type=null;
1193                 return this;
1194         };
1195         
1196         this.homeTimeline=function(){
1197                 this.validateOnline();
1198                 this.method="/statuses/home_timeline.json";
1199                 this.type="net.status.js.Status";
1200                 return this;
1201         };
1202         
1203         this.mentions=function(){
1204                 this.validateOnline();
1205                 this.method="/statuses/mentions.json";
1206                 this.type="net.status.js.Status";
1207                 return this;
1208         };
1209         
1210         this.retweeting=function(){
1211                 this.validateOnline();
1212                 this.method="/statuses/retweeted_by_me.json";
1213                 this.type="net.status.js.Status";
1214                 return this;
1215         };
1216         
1217         this.retweets=function(){
1218                 this.validateOnline();
1219                 this.method="/statuses/retweeted_to_me.json";
1220                 this.type="net.status.js.Status";
1221                 return this;
1222         };
1223         
1224         this.retweeted=function(){
1225                 this.validateOnline();
1226                 this.method="/statuses/retweeted_of_me.json";
1227                 this.type=null;
1228                 return this;
1229         };
1230         
1231         this.blocks=function(){
1232                 this.validateOnline();
1233                 this.method="/blocks/blocking.json";
1234                 this.type="net.status.js.User";
1235                 return this;
1236         };
1237         
1238         this.logout=function(){
1239                 return this.parent.logout();
1240         };
1241
1242         
1243 };
1244
1245 net.status.js.CurrentUser.prototype=new net.status.js.User();net.status.js.Status=function(){
1246         this.id=null;
1247         
1248         this.init=function(_id){
1249                 this.id=_id;
1250                 this.method="/statuses/show.json";
1251                 this.params={id:this.id};
1252                 this.type="net.status.js.Status";
1253                 return this;
1254         };
1255         
1256         this.retweet=function(){
1257                 return this.retweet(this.id);
1258         };
1259         
1260         this.favorite=function(){
1261                 return this.favorite(this.id);
1262         };
1263         
1264         this.unfavorite=function(){
1265                 return this.unfavorite(this.id);
1266         };
1267         
1268         this.reply=function(message){
1269                 return this.reply(message,this.id);
1270         };
1271         
1272         this.destroy=function(){
1273                 this.proxy="POST";
1274                 this.validateOnline();
1275                 this.method="/statuses/destroy.json";
1276                 this.params={id:this.id};
1277                 this.type="net.status.js.Status";
1278                 
1279                 return this;
1280         };
1281         
1282         this.retweets=function(){
1283                 this.validateOnline();
1284                 this.method="/statuses/retweets.json";
1285                 this.params={id:this.id};
1286                 this.type="net.status.js.Status";
1287                 
1288                 return this;
1289         };
1290         
1291         this.retweeters=function(){
1292                 this.validateOnline();
1293                 this.method="/statuses/"+ this.id +"/retweeted_by.json";
1294                 this.params=null;
1295                 this.type="net.status.js.User";
1296                 
1297                 return this;
1298         };
1299         
1300         this.inReplyTo=function(){
1301                 return net.status.js.User.find(this.in_reply_to_user_id);
1302         };
1303 };
1304
1305 //inheritance
1306 net.status.js.Status.prototype=new net.status.js.APIBase();
1307
1308 net.status.js.Status.find=function(id){
1309         var status=new net.status.js.Status();
1310         status.api(this.parent);
1311         status.init(id);
1312         return status;
1313 };
1314
1315 /**
1316  * 
1317  * @param status 
1318  * @param options optional parameter object
1319  */
1320 net.status.js.Status.update=function(_status,options){
1321         var api=new net.status.js.APIBase();
1322         api.api(this.parent);
1323         //api.validateOnline();
1324         api.proxy="POST";
1325         api.method="/statuses/update.json";
1326         var params={status:_status};
1327         jQuery.extend(params,options);
1328         api.params=params;
1329         api.type="net.status.js.Status";
1330         
1331         return api;
1332 };
1333
1334 net.status.js.Status.publicTimeline=function(){
1335         var api=new net.status.js.APIBase();
1336         api.api(this.parent);
1337         api.method="/statuses/public_timeline.json";
1338         api.params=null;
1339         api.type="net.status.js.Status";
1340         
1341         return api;
1342 };
1343
1344 net.status.js.Status.retweet=function(_id){
1345         var api=new net.status.js.APIBase();
1346         api.api(this.parent);
1347         api.validateOnline();
1348         api.proxy="POST";
1349         api.method="/statuses/retweet.json";
1350         api.params={id:_id};
1351         api.type="net.status.js.Status";
1352         
1353         return api;
1354 };
1355
1356 net.status.js.Status.favorite=function(_id){
1357         var api=new net.status.js.APIBase();
1358         api.api(this.parent);
1359         api.validateOnline();
1360         api.proxy="POST";
1361         api.method="/favorites/create/"+_id+".json";
1362         api.type="net.status.js.Status";
1363         
1364         return api;
1365 };
1366
1367 net.status.js.Status.unfavorite=function(_id){
1368         var api=new net.status.js.APIBase();
1369         api.api(this.parent);
1370         api.validateOnline();
1371         api.proxy="POST";
1372         api.method="/favorites/destroy/"+_id+".json";
1373         api.type="net.status.js.Status";
1374         
1375         return api;
1376 };
1377
1378 net.status.js.Status.reply=function(message,_id){
1379         return net.status.js.Status.update(message, {in_reply_to_status_id:_id});
1380 };
1381
1382 net.status.js.DirectMessage=function(){
1383         this.destroy=function(){
1384                 this.validateOnline();
1385                 this.proxy="POST";
1386                 this.method="/direct_messages/destroy/"+ this.id +".format";
1387                 this.type="net.status.js.DirectMessage";
1388                 
1389                 return this;
1390         };
1391 };
1392
1393 //inheritance
1394 net.status.js.DirectMessage.prototype=new net.status.js.APIBase();
1395
1396 net.status.js.DirectMessage.send=function(toUser,messageText){
1397         var api=new net.status.js.APIBase();
1398         api.validateOnline();
1399         api.proxy='POST';
1400         api.method="/direct_messages/new.json";
1401         api.params={user:toUser,text:messageText};
1402         api.type="net.status.js.DirectMessage";
1403         return api;
1404 };net.status.js.Search=function(api){
1405         this.q="";
1406         this.API=api;
1407         this.additionalParams={};
1408         this.next=function(){
1409                 if(!this.next_page) searchEnd();
1410                 var search=new net.status.js.Search(this.API);
1411                 search.method="/search.json" + this.next_page;
1412                 //search.params={page:(this.page+1)};
1413                 search.type="net.status.js.Search";
1414                 search.auth=false;
1415                 return search;
1416         };
1417         
1418         this.previous=function(){
1419                 if(!this.previous_page) searchEnd();
1420                 
1421                 var search=new net.status.js.Search(this.API);
1422                 search.method="/search.json" + this.previous_page;
1423                 //search.params={page:(this.page-1),max_id:this.max_id,q:this.query};
1424                 search.type="net.status.js.Search";
1425                 search.auth=false;
1426                 return search;
1427         };
1428         
1429         
1430         this.refresh=function(){
1431                 var search=new net.status.js.Search(this.API);
1432                 search.method="/search.json" + this.refresh_url;
1433                 //search.params={since_id:this.max_id,q:this.query};
1434                 search.type="net.status.js.Search";
1435                 search.auth=false;
1436                 return search;
1437         };
1438         
1439         this.rpp=function(rpp){
1440                 this.additionalParams.rpp=rpp;
1441                 return this;
1442         };
1443         
1444         var searchEnd=function(){
1445                 throw "There is no such search page to access";
1446         };
1447         
1448         
1449 };
1450
1451 net.status.js.Search.prototype=new net.status.js.APIBase();
1452
1453 net.status.js.Search.query=function(_q){
1454         var search=new net.status.js.Search(this.parent);
1455         search.q=_q;
1456         search.method="/search.json";
1457         search.type="net.status.js.Search";
1458         search.params={q:_q};
1459         search.auth=false;
1460         return search;
1461 };
1462 /**
1463  * StatusNet - the distributed open-source microblogging tool
1464  * Copyright (C) 2008, 2009, StatusNet, Inc.
1465  *
1466  * This program is free software: you can redistribute it and/or modify
1467  * it under the terms of the GNU Affero General Public License as published by
1468  * the Free Software Foundation, either version 3 of the License, or
1469  * (at your option) any later version.
1470  *
1471  * This program is distributed in the hope that it will be useful,
1472  * but WITHOUT ANY WARRANTY; without even the implied warranty of
1473  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1474  * GNU Affero General Public License for more details.
1475  *
1476  * You should have received a copy of the GNU Affero General Public License
1477  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
1478  *
1479  * @category StatusNet
1480  * @package  StausBox
1481  * @author   Arunoda Susiripala <arunoda.susiripala@gmail.com>
1482  *
1483  * @license  GNU Affero General Public License http://www.gnu.org/licenses/ 
1484  * 
1485  * 
1486  * This code borrows some of its parts from 
1487  * http://github.com/bytespider/jsOAuth.git
1488  * 
1489  */
1490 net.status.js.StatusNet=function(instance_name){
1491         this.oauth=null;
1492         this.store=null;
1493         this.endpoint='http://me.arunoda.com/api';
1494         this.currentUser=null;
1495         var popupWindow=null;
1496         
1497         /**
1498          * This is very important.
1499          * This field should be as the name of the instance of this class
1500          * this used to set cross reference to the APIBase derivatives just after 
1501          * they are created when using the JSON Callback
1502          */
1503         this.instance_name=instance_name;
1504         
1505         this.init=function(consumerKey,consumerSecret){
1506                 this.store=new Store(this.instance_name);
1507                 this.oauth=new OAuth(this.store);
1508                 this.oauth.init(consumerKey, consumerSecret, this.endpoint);
1509                 this.communicator=new net.status.js.Communicator(this.oauth);
1510                 
1511                 //creating references for the API
1512                 this.User=net.status.js.User;
1513                 this.CurrentUser=net.status.js.CurrentUser;
1514                 this.Status=net.status.js.Status;
1515                 this.DirectMessage=net.status.js.DirectMessage;
1516                 this.Search=net.status.js.Search;
1517                 
1518                 
1519                 //referenceing this inside the parent for cross referencing
1520                 //capabilities
1521                 this.User.parent=this;
1522                 this.CurrentUser.parent=this;
1523                 this.Status.parent=this;
1524                 this.DirectMessage.parent=this;
1525                 this.Search.parent=this;
1526                 
1527                 
1528                 //special handling for returning from Authorization
1529                 //below codes are runs in the popup window
1530                 if(location.href.search('oauth_token')>0){
1531                         var url=this.oauth.getAccessTokenUrl();
1532                         var encoded=OAuthUtilities.urlEncode(url);
1533                                         
1534                         net.status.js.Communicator.sendJSON(encoded,this.instance_name+".handleInitCallback");
1535                         //next part will be handle by handleInitCallback()
1536                 }
1537                 else{
1538                         //registering events
1539                         this.registerEvents();
1540                 }
1541                 
1542                 
1543         };
1544         
1545         this.handleInitCallback=function(response){
1546                 var map=OAuth.parseToken(response);
1547                 var tokenStore=this.store;
1548                 tokenStore.setToken(map.oauth_token);
1549                 tokenStore.setTokenSecret(map.oauth_token_secret);
1550
1551                 window.opener.SN.triggerEvent("oauthVerified");
1552                 window.close();
1553         };
1554         
1555         //public methods
1556         
1557         this.connect=function(){
1558                 //popup handling
1559                 popupWindow=popup("",500,500);
1560                 popupWindow.document.write("wait...");
1561                 popupWindow.document.close();
1562                 
1563                 //working with request Token
1564                 var url=this.oauth.getRequestTokenUrl();
1565                 var encoded=OAuthUtilities.urlEncode(url);
1566                 var tokenStore=this.store;
1567                 var oauth=this.oauth;
1568                 
1569                 net.status.js.Communicator.sendJSON(encoded,this.instance_name+'.handleConnectCallback');
1570                 //next part will be handle by handleConnectCallback()
1571         };
1572         
1573         this.handleConnectCallback=function(response){
1574                 var map=OAuth.parseToken(response);
1575                 var tokenStore=this.store;
1576                 tokenStore.setToken(map.oauth_token);
1577                 tokenStore.setTokenSecret(map.oauth_token_secret);
1578                 
1579                 //handles authorization
1580                 var authUrl=this.oauth.getAuthorizationUrl();
1581                 popupWindow.location.href=authUrl;
1582         };
1583         
1584         
1585         this.ready=function(callback){
1586                 //does not function for the callback from oauth
1587                 if(location.href.search('oauth_token')>0){
1588                         return;
1589                 }
1590                 this.loadUser(callback);
1591         };
1592         
1593         var loadUserCallback=null;
1594         this.loadUser=function(callback){
1595                 loadUserCallback=callback;
1596                 if(!this.store.getToken() || !this.store.getTokenSecret()){
1597                         this.currentUser=null;
1598                         //jQuery.ready(loadUserCallback(SN));
1599                         jQuery(document).ready(function(){
1600                                 loadUserCallback();
1601                         });
1602                         
1603                 }
1604                 else{
1605                         var url=SN.oauth.getRequestAPIUrl('/account/verify_credentials.json',null);
1606                         net.status.js.Communicator.sendJSON(url,this.instance_name+'.handleLoadUserCallback');
1607                         //next part of the algo will be handle by handleLoadUserCallback
1608                 }
1609                 
1610                 
1611         };
1612         
1613         this.handleLoadUserCallback=function(response){
1614                 if(response.screen_name){
1615                         //saving the current user to the API
1616                         this.currentUser=net.status.js.Communicator.buildObject
1617                                 (response,this.instance_name+".CurrentUser",this);
1618                         this.triggerEvent('loggedIn');
1619                         jQuery(document).ready(function(){
1620                                 loadUserCallback();
1621                         });
1622                 }
1623                 else{
1624                         this.currentUser=null;
1625                         jQuery(document).ready(function(){
1626                                 loadUserCallback();
1627                         });
1628                 }
1629         };
1630         
1631         this.isConnected=function(){
1632                 return (this.currentUser)?true:false;
1633         };
1634         
1635         this.logout=function(){
1636                 //@todo trigger a event for this.
1637                 this.store.setToken(null);
1638                 this.store.setTokenSecret(null);
1639                 this.currentUser=null;
1640                 
1641                 this.triggerEvent("loggedOut");
1642                 return true;
1643         };
1644         
1645         this.registerEvents=function(){
1646                 //on oauthVerified
1647                 /*
1648                  * loads the User when he is authenticated with the popup
1649                  * to the Current Page
1650                  */
1651                 var func=
1652                         net.status.js.Communicator.createDynamicFunction(
1653                                         this.instance_name+".loadUser(function(){"+
1654                                                 ""+
1655                                         "});"           
1656                         );
1657                 this.registerEvent("oauthVerified",func);
1658         };
1659         
1660         
1661         var popup=function(url, width, height) {
1662                 var top = screen.height / 2 - height / 2;
1663                 var left = screen.width / 2 - width / 2;
1664
1665                 var thewindow=window
1666                                 .open(
1667                                                 url,
1668                                                 'Login',
1669                                                 'left=' + left + ',scrollbars=no,menubar=no,height=600,width=800,resizable=yes,toolbar=no,location=no,status=no');
1670                 return thewindow;
1671         };
1672         
1673 }
1674 net.status.js.EventManager=function(){
1675         this.events=[];
1676         
1677         this.registerEvent=function(eventName,callback){
1678                 if(!this.events[eventName]){
1679                         this.events[eventName]=[];
1680                 }
1681                 
1682                 this.events[eventName][this.events[eventName].length]=callback;
1683                 
1684         };
1685         
1686         this.triggerEvent=function(eventName){
1687                 var events=this.events[eventName];
1688                 if(events){
1689                         for(id in events){
1690                                 var func=events[id];
1691                                 if(typeof func == "string"){
1692                                         eval(func+"()");
1693                                 }
1694                                 else{
1695                                         func();
1696                                 }
1697                         }
1698                 }
1699         };
1700 };
1701
1702 //extending
1703 net.status.js.StatusNet.prototype=new net.status.js.EventManager();
1704
1705 var SN=new net.status.js.StatusNet("SN");