Annotation of embedaddon/coova-chilli/www/ChilliLibrary.js, revision 1.1

1.1     ! misho       1: /**
        !             2:  *   ChilliLibrary.js
        !             3:  *   V2.0
        !             4:  *
        !             5:  *   This Javascript library can be used to create HTML/JS browser
        !             6:  *   based smart clients (BBSM) for the CoovaChilli access controller
        !             7:  *   Coova Chilli rev 81 or higher is required
        !             8:  *   
        !             9:  *   This library creates four global objects :
        !            10:  *
        !            11:  *    - chilliController  Expose session/client state and 
        !            12:  *                        connect()/disconnect() methods the to BBSM.
        !            13:  *
        !            14:  *    - chilliJSON        INTERNAL (should not be called from the BBSM).
        !            15:  *                        Issues a command to the chilli daemon by adding a new <SCRIPT>
        !            16:  *                        tag to the HTML DOM (this hack enables cross server requests). 
        !            17:  *                        
        !            18:  *    - chilliClock       Can be used by BBSMs to display a count down.
        !            19:  *                        Will sync with chilliController for smooth UI display (not yet implemented)
        !            20:  *
        !            21:  *    - chilliLibrary     Expose API and library versions
        !            22:  *
        !            23:  *  For more information http://coova.org/wiki/index.php/CoovaChilli/JSON
        !            24:  *
        !            25:  *  TODO :
        !            26:  *   - Fine tune level of debug messages
        !            27:  *   - Define error code when invoking onError
        !            28:  *   - Retry mechanism after a JSON request fails
        !            29:  *   - Delay clock tick when there is already an ongoing request
        !            30:  *   - Use a true JSON parser to validate what we received
        !            31:  *   - Use idleTime and idleTimeout to re-schedule autofresh after
        !            32:  *     a likely idle termination by chilli
        !            33:  *   - check that the library can be compiled as a Flash swf library
        !            34:  *     and used from Flash BBSMs with the same API.
        !            35:  *
        !            36:  *   Copyright (C) Y.Deltroo 2007
        !            37:  *   Distributed under the BSD License
        !            38:  *
        !            39:  *   This file also contains third party code :
        !            40:  *   - MD5, distributed under the BSD license
        !            41:  *     http://pajhome.org.uk/crypt/md5
        !            42:  *
        !            43:  */
        !            44: 
        !            45: var chilliLibrary = { revision:'85' , apiVersion:'2.0' } ;
        !            46: 
        !            47: 
        !            48: /**
        !            49:  *   Global chilliController object
        !            50:  *
        !            51:  *   CONFIGUARION PROPERTIES
        !            52:  *   -----------------------
        !            53:  *    ident (String) 
        !            54:  *      Hex encoded string (used for client side CHAP-Password calculations) 
        !            55:  *               
        !            56:  *    interval (Number)
        !            57:  *       Poll the gateway every interval, in seconds
        !            58:  *
        !            59:  *    host (String)
        !            60:  *       IP address of the controller (String)
        !            61:  *
        !            62:  *    port (Number)
        !            63:  *        UAM port to direct request to on the gateway
        !            64:  *
        !            65:  *    ssl (Boolean)
        !            66:  *       Shall we use HTTP or HTTPS to communicate with the chilli controller 
        !            67:  *
        !            68:  *    uamService : String
        !            69:  *        !!! EXPERIMENTAL FEATURE !!!
        !            70:  *        URL to external uamService script (used for external MD5 calculation when portal/chilli trust is required)
        !            71:  *        This remote script runs on a SSL enable web server, and knows UAM SECRET.
        !            72:  *        The chilliController javascript object will send the password over SSL (and challenge for CHAP) 
        !            73:  *        UAM SERVICE should reply with a JSON response containing
        !            74:  *           - CHAP logon : CHAP-Password X0Red with UAM SECRET
        !            75:  *           - PAP  logon : Password XORed with UAM SECRET
        !            76:  *
        !            77:  *   For more information http://coova.org/wiki/index.php/CoovaChilli/JSON
        !            78:  *
        !            79:  */
        !            80: 
        !            81: var chilliController = { interval:30 , host:"192.168.182.1" , port:3990 , ident:'00' , ssl:false , uamService: '' };
        !            82: 
        !            83: /* Define clientState numerical code constants  */
        !            84: chilliController.stateCodes = { UNKNOWN:-1 , NOT_AUTH:0 , AUTH:1 , AUTH_PENDING:2 , AUTH_SPLASH:3 } ;
        !            85: 
        !            86: /* Initializing session and accounting members, objet properties */
        !            87: chilliController.session     = {} ;
        !            88: chilliController.accounting  = {} ;
        !            89: chilliController.redir       = {} ;
        !            90: 
        !            91: chilliController.location   = { name: '' } ;
        !            92: chilliController.challenge       = '' ;
        !            93: chilliController.message         = '' ;
        !            94: chilliController.clientState     = chilliController.stateCodes.UNKNOWN ;
        !            95: chilliController.command         = '' ;
        !            96: chilliController.autorefreshTimer = 0  ;
        !            97: 
        !            98: /* This method returns the root URL for commands */
        !            99: chilliController.urlRoot = function () {
        !           100:        var protocol = ( chilliController.ssl ) ? "https" : "http" ;
        !           101:        var urlRoot = protocol + "://" + chilliController.host + ":" + chilliController.port.toString() + "/json/" ;
        !           102:        return urlRoot;
        !           103: };
        !           104: 
        !           105: /* Default event handlers */
        !           106: chilliController.onUpdate = function ( cmd ) {
        !           107:        log('>> Default onUpdate handler. <<\n>> You should write your own. <<\n>> cmd = ' + cmd + ' <<' );
        !           108: };
        !           109: 
        !           110: chilliController.onError = function ( str ) {
        !           111:        log ( '>> Default Error Handler<<\n>> You should write your own  <<\n>> ' + str + ' <<' );
        !           112: };
        !           113: 
        !           114: 
        !           115: chilliController.formatTime = function ( t , zeroReturn ) {
        !           116: 
        !           117:     if ( typeof(t) == 'undefined' ) {
        !           118:        return "Not available";
        !           119:     }
        !           120: 
        !           121:     t = parseInt ( t , 10 ) ;
        !           122:     if ( (typeof (zeroReturn) !='undefined') && ( t === 0 ) ) {
        !           123:        return zeroReturn;
        !           124:     }
        !           125: 
        !           126:     var h = Math.floor( t/3600 ) ;
        !           127:     var m = Math.floor( (t - 3600*h)/60 ) ;
        !           128:     var s = t % 60  ;
        !           129: 
        !           130:     var s_str = s.toString();
        !           131:     if (s < 10 ) { s_str = '0' + s_str;   }
        !           132: 
        !           133:     var m_str = m.toString();
        !           134:     if (m < 10 ) { m_str= '0' + m_str;    }
        !           135: 
        !           136:     var h_str = h.toString();
        !           137:     if (h < 10 ) { h_str= '0' + h_str;    }
        !           138: 
        !           139: 
        !           140:     if      ( t < 60 )   { return s_str + 's' ; }
        !           141:     else if ( t < 3600 ) { return m_str + 'm' + s_str + 's' ; }
        !           142:     else                 { return h_str + 'h' + m_str + 'm' + s_str + 's'; }
        !           143: 
        !           144: };
        !           145: 
        !           146: chilliController.formatBytes = function ( b , zeroReturn ) {
        !           147: 
        !           148:     if ( typeof(b) == 'undefined' ) {
        !           149:         b = 0;
        !           150:     } else {
        !           151:         b = parseInt ( b , 10 ) ;
        !           152:     }
        !           153: 
        !           154:     if ( (typeof (zeroReturn) !='undefined') && ( b === 0 ) ) {
        !           155:        return zeroReturn;
        !           156:     }
        !           157: 
        !           158:     var kb = Math.round(b  / 10) / 100;
        !           159:     if (kb < 1) return b  + ' Bytes';
        !           160: 
        !           161:     var mb = Math.round(kb / 10) / 100;
        !           162:     if (mb < 1)  return kb + ' Kilobytes';
        !           163: 
        !           164:     var gb = Math.round(mb / 10) / 100;
        !           165:     if (gb < 1)  return mb + ' Megabytes';
        !           166: 
        !           167:     return gb + ' Gigabytes';
        !           168: };
        !           169: 
        !           170: 
        !           171: /**
        !           172:  *   Global chilliController object
        !           173:  *
        !           174:  *   PUBLIC METHODS
        !           175:  *   --------------
        !           176:  *     logon ( username, password ) :
        !           177:  *           Attempt a CHAP logon with username/password
        !           178:  *           issues a /logon command to chilli daemon
        !           179:  *
        !           180:  *     logoff () :
        !           181:  *           Disconnect the current user by issuing a
        !           182:  *           /logoff command to the chilli daemon
        !           183:  *
        !           184:  *     refresh () :
        !           185:  *           Issues a /status command to chilli daemon to refresh 
        !           186:  *           the local chilliController object state/session data
        !           187:  *
        !           188:  */
        !           189:  
        !           190: chilliController.logon = function ( username , password )  {
        !           191: 
        !           192:        if ( typeof(username) !== 'string') {
        !           193:                chilliController.onError( 1 , "username missing (or incorrect type)" ) ;
        !           194:        }
        !           195:        
        !           196:        if ( typeof(password) !== 'string') {
        !           197:                chilliController.onError( 2 , "password missing (or incorrect type)" ) ;
        !           198:        }
        !           199: 
        !           200:        log ( 'chilliController.logon( "' + username + '" , "' + password + ' " )' );
        !           201: 
        !           202:        chilliController.temp = { 'username': username , 'password': password };
        !           203:        chilliController.command = 'logon';
        !           204: 
        !           205:        log ('chilliController.logon: asking for a new challenge ' );
        !           206:        chilliJSON.onError        = chilliController.onError    ;
        !           207:        chilliJSON.onJSONReady    = chilliController.logonStep2 ;
        !           208:        chilliController.clientState = chilliController.AUTH_PENDING ; 
        !           209:        chilliJSON.get( chilliController.urlRoot() + 'status'  ) ;
        !           210: };
        !           211: 
        !           212: 
        !           213: /**
        !           214:  *   Second part of the logon process invoked after
        !           215:  *   the just requested challenge has been received
        !           216:  */
        !           217: chilliController.logonStep2 = function ( resp ) {
        !           218: 
        !           219:        log('Entering logonStep 2');
        !           220: 
        !           221:        if ( typeof (resp.challenge) != 'string' ) {
        !           222:                log('logonStep2: cannot find a challenge. Aborting.');
        !           223:                return chilliController.onError('Cannot get challenge');
        !           224:        }
        !           225: 
        !           226:        if ( resp.clientSate === chilliController.stateCodes.AUTH ) {
        !           227:                log('logonStep2: Already connected. Aborting.');
        !           228:                return chilliController.onError('Already connected.');
        !           229:        }
        !           230: 
        !           231:        var challenge = resp.challenge;
        !           232: 
        !           233:        var username = chilliController.temp.username ; 
        !           234:        var password = chilliController.temp.password ;
        !           235: 
        !           236:        log ('chilliController.logonStep2: Got challenge = ' + challenge );
        !           237: 
        !           238:        if ( chilliController.uamService ) { /* MD5 CHAP will be calculated by uamService */
        !           239: 
        !           240:                log ('chilliController.logonStep2: Logon using uamService (external MD5 CHAP)');
        !           241: 
        !           242:                // Build command URL
        !           243:                var url = chilliController.uamService + '?username=' + escape(username) +'&password=' + escape(password) +'&challenge=' + challenge ;
        !           244: 
        !           245:                if (chilliController.queryObj && chilliController.queryObj['userurl'] ) {
        !           246:                    url += '&userurl='+chilliController.queryObj['userurl'] ;
        !           247:                }
        !           248: 
        !           249:                // Make uamService request
        !           250:                chilliJSON.onError     = chilliController.onError     ;
        !           251:                chilliJSON.onJSONReady = chilliController.logonStep3 ;
        !           252: 
        !           253:                chilliController.clientState = chilliController.AUTH_PENDING ; 
        !           254:                chilliJSON.get( url ) ;
        !           255:        }
        !           256:        else {
        !           257:                /* TODO: Should check if challenge has expired and possibly get a new one */
        !           258:                /*       OR always call status first to get a fresh challenge             */
        !           259: 
        !           260: 
        !           261:                /* Calculate MD5 CHAP at the client side */
        !           262:                var myMD5 = new ChilliMD5();
        !           263:                var chappassword = myMD5.chap ( chilliController.ident , password , challenge );
        !           264:                log ( 'chilliController.logonStep2: Calculating CHAP-Password = ' + chappassword );
        !           265: 
        !           266:                /* Prepare chilliJSON for logon request */
        !           267:                chilliJSON.onError     = chilliController.onError     ;
        !           268:                chilliJSON.onJSONReady = chilliController.processReply ;
        !           269:                chilliController.clientState = chilliController.stateCodes.AUTH_PENDING ; 
        !           270:        
        !           271:                /* Build /logon command URL */
        !           272:                var logonUrl = chilliController.urlRoot() + 'logon?username=' + escape(username) + '&response='  + chappassword;
        !           273:                if (chilliController.queryObj && chilliController.queryObj['userurl'] ) {
        !           274:                    logonUrl += '&userurl='+chilliController.queryObj['userurl'] ;
        !           275:                }
        !           276:                chilliJSON.get ( logonUrl ) ;
        !           277:        }
        !           278: 
        !           279: }; 
        !           280: 
        !           281: /**
        !           282:  *   Third part of the logon process invoked after
        !           283:  *   getting a uamService response
        !           284:  */
        !           285: chilliController.logonStep3 = function ( resp ) {
        !           286:        log('Entering logonStep 3');
        !           287: 
        !           288:        var username = chilliController.temp.username ; 
        !           289: 
        !           290:        if ( typeof (resp.response) == 'string' ) {
        !           291:                chilliJSON.onError     = chilliController.onError     ;
        !           292:                chilliJSON.onJSONReady = chilliController.processReply ;
        !           293:                chilliController.clientState = chilliController.stateCodes.AUTH_PENDING ; 
        !           294:        
        !           295:                /* Build /logon command URL */
        !           296:                var logonUrl = chilliController.urlRoot() + 'logon?username=' + escape(username) + '&response='  + resp.response;
        !           297:                if (chilliController.queryObj && chilliController.queryObj['userurl'] ) {
        !           298:                    logonUrl += '&userurl='+chilliController.queryObj['userurl'] ;
        !           299:                }
        !           300:                chilliJSON.get ( logonUrl ) ;
        !           301:        }
        !           302: }
        !           303: 
        !           304: chilliController.refresh = function ( ) {
        !           305: 
        !           306:        if ( chilliController.autorefreshTimer ) {
        !           307:                chilliController.command = 'autorefresh' ;
        !           308:        }
        !           309:        else {
        !           310:                chilliController.command = 'refresh' ;
        !           311:        }
        !           312: 
        !           313:        chilliJSON.onError     = chilliController.onError        ;
        !           314:        chilliJSON.onJSONReady = chilliController.processReply   ;
        !           315:        chilliJSON.get( chilliController.urlRoot() + 'status'  ) ;
        !           316: };
        !           317: 
        !           318: chilliController.logoff = function () {
        !           319: 
        !           320:        chilliController.command  = 'logoff'                      ;
        !           321:        chilliJSON.onError        = chilliController.onError      ;
        !           322:        chilliJSON.onJSONReady    = chilliController.processReply ;
        !           323:        chilliJSON.get( chilliController.urlRoot() + 'logoff' );
        !           324: };
        !           325: 
        !           326: /* *
        !           327:  *
        !           328:  * This functions does some check/type processing on the JSON resp
        !           329:  * and updates the corresponding chilliController members
        !           330:  *
        !           331:  */
        !           332: chilliController.processReply = function ( resp ) {
        !           333: 
        !           334:        if ( typeof (resp.message)  == 'string' ) {
        !           335: 
        !           336:                /* The following trick will replace HTML entities with the corresponding
        !           337:                  * character. This will not work in Flash (no innerHTML) 
        !           338:                  */
        !           339: 
        !           340:                var fakediv = document.createElement('div');
        !           341:                fakediv.innerHTML = resp.message ;
        !           342:                chilliController.message = fakediv.innerHTML  ;
        !           343:        }
        !           344: 
        !           345:        if ( typeof (resp.challenge) == 'string' ) {
        !           346:                chilliController.challenge = resp.challenge ;
        !           347:        }
        !           348: 
        !           349:        if ( typeof ( resp.location ) == 'object' ) {
        !           350:                chilliController.location =  resp.location ;
        !           351:        }
        !           352: 
        !           353:        if ( typeof ( resp.accounting ) == 'object' ) {
        !           354:                chilliController.accounting = resp.accounting ;
        !           355:        }
        !           356: 
        !           357:        if (  (typeof ( resp.redir ) == 'object') ) {
        !           358:                chilliController.redir = resp.redir ;
        !           359:        }               
        !           360:        
        !           361:        /* Update the session member only the first time after AUTH */
        !           362:        if (  (typeof ( resp.session ) == 'object') &&
        !           363:              ( chilliController.session==null || (
        !           364:                 ( chilliController.clientState !== chilliController.stateCodes.AUTH  )  &&
        !           365:                 ( resp.clientState === chilliController.stateCodes.AUTH  )))) {
        !           366: 
        !           367:                chilliController.session = resp.session ;
        !           368: 
        !           369:                if ( resp.session.startTime ) {
        !           370:                        chilliController.session.startTime = new Date();
        !           371:                        chilliController.session.startTime.setTime(resp.session.startTime);
        !           372:                }
        !           373:        }
        !           374: 
        !           375:        /* Update clientState */
        !           376:        if (  ( resp.clientState === chilliController.stateCodes.NOT_AUTH     ) ||
        !           377:               ( resp.clientState === chilliController.stateCodes.AUTH         ) ||
        !           378:               ( resp.clientState === chilliController.stateCodes.AUTH_SPLASH  ) ||
        !           379:              ( resp.clientState === chilliController.stateCodes.AUTH_PENDING ) ) {
        !           380: 
        !           381:                chilliController.clientState = resp.clientState ;
        !           382:        }
        !           383:        else {
        !           384:                chilliController.onError("Unknown clientState found in JSON reply");
        !           385:        }
        !           386: 
        !           387: 
        !           388:        /* Launch or stop the autorefresh timer if required */
        !           389:        if ( chilliController.clientState === chilliController.stateCodes.AUTH  ) {
        !           390: 
        !           391:              if ( !chilliController.autorefreshTimer ) {
        !           392:                        chilliController.autorefreshTimer = setInterval ('chilliController.refresh()' , 1000*chilliController.interval);
        !           393:             }
        !           394:        } 
        !           395:        else if ( chilliController.clientState  === chilliController.stateCodes.NOT_AUTH ) {
        !           396:                clearInterval ( chilliController.autorefreshTimer ) ;
        !           397:                 chilliController.autorefreshTimer = 0 ;
        !           398:        }
        !           399: 
        !           400:        /* Lastly... call the event handler  */
        !           401:        log ('chilliController.processReply: Calling onUpdate. clienState = ' + chilliController.clientState);
        !           402:        chilliController.onUpdate( chilliController.command );
        !           403: };
        !           404: 
        !           405: 
        !           406: 
        !           407: /** 
        !           408:  *  chilliJSON object  
        !           409:  *
        !           410:  *  This private objet implements the cross domain hack
        !           411:  *  If no answer is received before timeout, then an error is raised.
        !           412:  *
        !           413:  */
        !           414: 
        !           415: var chilliJSON = { timeout:25000 , timer:0 , node:0 , timestamp:0 };
        !           416: 
        !           417: chilliJSON.expired   = function () {
        !           418: 
        !           419:                if ( chilliJSON.node.text ) {
        !           420:                        log ('chilliJSON: reply content \n' + chilliJSON.node.text );
        !           421:                }
        !           422:                else {
        !           423:                        log ('chilliJSON: request timed out (or reply is not valid JS)');
        !           424:                }
        !           425: 
        !           426:                clearInterval ( chilliJSON.timer ) ;
        !           427:                chilliJSON.timer = 0 ;
        !           428: 
        !           429:                /* remove the <SCRIPT> tag node that we have created */
        !           430:                if ( typeof (chilliJSON.node) !== 'number' ) {
        !           431:                        document.getElementsByTagName('head')[0].removeChild ( chilliJSON.node );
        !           432:                }
        !           433:                chilliJSON.node = 0;
        !           434: 
        !           435:                /* TODO: Implement some kind of retry mechanism here ... */
        !           436: 
        !           437:                chilliJSON.onError('JSON request timed out (or reply is not valid)');
        !           438: };
        !           439: 
        !           440: chilliJSON.reply = function  ( raw ) {
        !           441: 
        !           442:                clearInterval ( chilliJSON.timer ) ;
        !           443:                chilliJSON.timer = 0 ;
        !           444: 
        !           445:                var now = new Date()    ;
        !           446:                var end = now.getTime() ;
        !           447:                 
        !           448:                if ( chilliJSON.timestamp ) {
        !           449:                        log ( 'chilliJSON: JSON reply received in ' + ( end - chilliJSON.timestamp ) + ' ms\n' + dumpObject(raw) );
        !           450:                }
        !           451: 
        !           452:                if ( typeof (chilliJSON.node) !== 'number' ) {
        !           453:                        document.getElementsByTagName('head')[0].removeChild ( chilliJSON.node );
        !           454:                }
        !           455:                chilliJSON.node = 0;
        !           456: 
        !           457:                /* TODO: We should parse raw JSON as an extra security measure */
        !           458:                                
        !           459:                chilliJSON.onJSONReady( raw ) ;
        !           460: } ;
        !           461: 
        !           462: chilliJSON.get = function ( gUrl ) {
        !           463: 
        !           464:                if ( typeof(gUrl) == "string" ) {
        !           465:                        chilliJSON.url = gUrl ;
        !           466:                }
        !           467:                else {
        !           468:                        log ( "chilliJSON:error:Incorrect url passed to chilliJSON.get():" + gUrl );
        !           469:                        chilliJSON.onError ( "Incorrect url passed to chilliJSON.get() " );
        !           470:                        return ;
        !           471:                }
        !           472: 
        !           473:                if ( chilliJSON.timer ) {
        !           474:                        log('logon:   There is already a request running. Return without launching a new request.');
        !           475:                        return ;
        !           476:                }
        !           477: 
        !           478:        
        !           479:                var scriptElement  = document.createElement('script');
        !           480:                scriptElement.type = 'text/javascript';
        !           481: 
        !           482:                var c ;
        !           483:                if ( this.url.indexOf('?') === -1 ) { 
        !           484:                        c = '?' ;
        !           485:                }
        !           486:                else {
        !           487:                        c = '&' ;
        !           488:                }
        !           489: 
        !           490:                scriptElement.src = chilliJSON.url + c + 'callback=chilliJSON.reply' ;
        !           491:                scriptElement.src += '&'+Math.random(); // prevent caching in Safari
        !           492:                
        !           493:                /* Adding the node that will trigger the HTTP request to the DOM tree */
        !           494:                chilliJSON.node = document.getElementsByTagName('head')[0].appendChild(scriptElement);
        !           495: 
        !           496:                /* Using interval instead of timeout to support Flash 5,6,7 */
        !           497:                chilliJSON.timer     = setInterval ( 'chilliJSON.expired()' , chilliJSON.timeout ) ; 
        !           498:                var now              = new Date();
        !           499:                chilliJSON.timestamp = now.getTime() ;
        !           500: 
        !           501:                log ('chilliJSON: getting ' + chilliJSON.url + ' . Waiting for reply ...');
        !           502: 
        !           503: }; // end chilliJSON.get = function ( url )
        !           504: 
        !           505: 
        !           506: /** 
        !           507:  *  chilliClock object  
        !           508:  *
        !           509:  *  Can be used by BBSMs to display a count down.
        !           510:  *
        !           511:  *  Will sync with chilliController and modulate the delay to call onTick
        !           512:  *  This will avoid ugly sequence of short updates in the IO
        !           513:  *  (not yet implemented)
        !           514:  *
        !           515:  */
        !           516: 
        !           517: var chilliClock = { isStarted : 0 };
        !           518: 
        !           519: chilliClock.onTick = function () {
        !           520:        log ("You should define your own onTick() handler on this clock object. Clock value = " + this.value );
        !           521: };
        !           522:  
        !           523: chilliClock.increment = function () {
        !           524: 
        !           525:        chilliClock.value  =  chilliClock.value + 1 ;
        !           526:        chilliClock.onTick( chilliClock.value ) ;
        !           527: };
        !           528: 
        !           529: chilliClock.resync = function ( newval ) {
        !           530:        clearInterval ( chilliClock.isStarted )    ;
        !           531:        chilliClock.value     = parseInt( newval , 10 ) ;
        !           532:        chilliClock.isStarted = setInterval ( 'chilliClock.increment()' , 1000 );
        !           533: };
        !           534: 
        !           535: chilliClock.start = function ( newval ) {
        !           536: 
        !           537:        if ( typeof (newval) !== 'Number' ) {
        !           538:                chilliClock.resync ( 0 ) ;
        !           539:        }
        !           540:        else {
        !           541:                chilliClock.resync ( newval ) ;
        !           542:        }
        !           543: };
        !           544: 
        !           545: chilliClock.stop = function () {
        !           546:        clearInterval ( chilliClock.isStarted )  ;
        !           547:        chilliClock.isStarted = 0 ;
        !           548: };
        !           549: 
        !           550: 
        !           551: function getel(e) {
        !           552:        if (document.getElementById) {
        !           553:                return document.getElementById(e);
        !           554:        } else if (document.all){
        !           555:                return document.all[e];
        !           556:        }
        !           557: }
        !           558: 
        !           559: function log( msg , messageLevel ) {
        !           560:        if (!chilliController.debug) return;
        !           561:        if ( typeof(trace)=="function") {
        !           562:                // ActionScript trace
        !           563:                trace ( msg );
        !           564:        }
        !           565:        else if ( typeof(console)=="object") {
        !           566:                // FireBug console
        !           567:                console.debug ( msg );
        !           568:        }
        !           569: 
        !           570:        if ( getel('debugarea') ) {
        !           571:                var e = getel('debugarea') ;
        !           572:                e.value = e.value + '\n' + msg;
        !           573:                e.scrollTop = e.scrollHeight - e.clientHeight;
        !           574:        }
        !           575: }
        !           576: 
        !           577: /* Transform an object to a text representation */
        !           578: function dumpObject ( obj ) {
        !           579: 
        !           580:        var str = '' ;
        !           581: 
        !           582:        for (var key in obj ) {
        !           583:                str = str + "    " + key + " = " + obj[key] + "\n" ;
        !           584:                if ( typeof ( obj[key] ) == "object" ) {
        !           585:                        for ( var key2 in obj[key] ) {
        !           586:                                str = str + "      " + key2 + " = "  + obj[key][key2] + "\n" ;
        !           587:                        }
        !           588:                }
        !           589:        }
        !           590: 
        !           591:        return str;
        !           592: }
        !           593: 
        !           594: /*
        !           595:  * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
        !           596:  * Digest Algorithm, as defined in RFC 1321.
        !           597:  * Version 2.1 Copyright (C) Paul Johnston 1999 - 2002.
        !           598:  * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
        !           599:  * Distributed under the BSD License
        !           600:  * See http://pajhome.org.uk/crypt/md5 for more info.
        !           601:  *
        !           602:  * added by Y.DELTROO
        !           603:  *   - new functions: chap(), hex2binl() and str2hex() 
        !           604:  *   - modifications to comply with the jslint test, http://www.jslint.com/
        !           605:  *
        !           606:  * Copyright (c) 2007
        !           607:  * Distributed under the BSD License
        !           608:  *
        !           609:  */
        !           610: 
        !           611: 
        !           612: function ChilliMD5() {
        !           613: 
        !           614:        var hexcase = 0;  /* hex output format. 0 - lowercase; 1 - uppercase        */
        !           615:        var b64pad  = ""; /* base-64 pad character. "=" for strict RFC compliance   */
        !           616:        var chrsz   = 8;  /* bits per input character. 8 - ASCII; 16 - Unicode      */
        !           617: 
        !           618:        this.hex_md5 = function (s){
        !           619:                return binl2hex(core_md5(str2binl(s), s.length * chrsz));
        !           620:        };
        !           621: 
        !           622:        this.chap = function ( hex_ident , str_password , hex_chal ) {
        !           623: 
        !           624:                //  Convert everything to hex encoded strings
        !           625:                var hex_password =  str2hex ( str_password );
        !           626: 
        !           627:                // concatenate hex encoded strings
        !           628:                var hex   = hex_ident + hex_password + hex_chal;
        !           629: 
        !           630:                // Convert concatenated hex encoded string to its binary representation
        !           631:                var bin   = hex2binl ( hex ) ;
        !           632: 
        !           633:                // Calculate MD5 on binary representation
        !           634:                var md5 = core_md5( bin , hex.length * 4 ) ; 
        !           635: 
        !           636:                return binl2hex( md5 );
        !           637:        };
        !           638: 
        !           639:        function core_md5(x, len) {
        !           640:          x[len >> 5] |= 0x80 << ((len) % 32);
        !           641:          x[(((len + 64) >>> 9) << 4) + 14] = len;
        !           642: 
        !           643:          var a =  1732584193;
        !           644:          var b = -271733879;
        !           645:          var c = -1732584194;
        !           646:          var d =  271733878;
        !           647: 
        !           648:          for(var i = 0; i < x.length; i += 16) {
        !           649:                var olda = a;
        !           650:                var oldb = b;
        !           651:                var oldc = c;
        !           652:                var oldd = d;
        !           653: 
        !           654:                a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936);
        !           655:                d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586);
        !           656:                c = md5_ff(c, d, a, b, x[i+ 2], 17,  606105819);
        !           657:                b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330);
        !           658:                a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897);
        !           659:                d = md5_ff(d, a, b, c, x[i+ 5], 12,  1200080426);
        !           660:                c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341);
        !           661:                b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983);
        !           662:                a = md5_ff(a, b, c, d, x[i+ 8], 7 ,  1770035416);
        !           663:                d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417);
        !           664:                c = md5_ff(c, d, a, b, x[i+10], 17, -42063);
        !           665:                b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162);
        !           666:                a = md5_ff(a, b, c, d, x[i+12], 7 ,  1804603682);
        !           667:                d = md5_ff(d, a, b, c, x[i+13], 12, -40341101);
        !           668:                c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290);
        !           669:                b = md5_ff(b, c, d, a, x[i+15], 22,  1236535329);
        !           670: 
        !           671:                a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);
        !           672:                d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);
        !           673:                c = md5_gg(c, d, a, b, x[i+11], 14,  643717713);
        !           674:                b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302);
        !           675:                a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691);
        !           676:                d = md5_gg(d, a, b, c, x[i+10], 9 ,  38016083);
        !           677:                c = md5_gg(c, d, a, b, x[i+15], 14, -660478335);
        !           678:                b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848);
        !           679:                a = md5_gg(a, b, c, d, x[i+ 9], 5 ,  568446438);
        !           680:                d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690);
        !           681:                c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961);
        !           682:                b = md5_gg(b, c, d, a, x[i+ 8], 20,  1163531501);
        !           683:                a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467);
        !           684:                d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784);
        !           685:                c = md5_gg(c, d, a, b, x[i+ 7], 14,  1735328473);
        !           686:                b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734);
        !           687: 
        !           688:                a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);
        !           689:                d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463);
        !           690:                c = md5_hh(c, d, a, b, x[i+11], 16,  1839030562);
        !           691:                b = md5_hh(b, c, d, a, x[i+14], 23, -35309556);
        !           692:                a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060);
        !           693:                d = md5_hh(d, a, b, c, x[i+ 4], 11,  1272893353);
        !           694:                c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632);
        !           695:                b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640);
        !           696:                a = md5_hh(a, b, c, d, x[i+13], 4 ,  681279174);
        !           697:                d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222);
        !           698:                c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979);
        !           699:                b = md5_hh(b, c, d, a, x[i+ 6], 23,  76029189);
        !           700:                a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487);
        !           701:                d = md5_hh(d, a, b, c, x[i+12], 11, -421815835);
        !           702:                c = md5_hh(c, d, a, b, x[i+15], 16,  530742520);
        !           703:                b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);
        !           704: 
        !           705:                a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);
        !           706:                d = md5_ii(d, a, b, c, x[i+ 7], 10,  1126891415);
        !           707:                c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905);
        !           708:                b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055);
        !           709:                a = md5_ii(a, b, c, d, x[i+12], 6 ,  1700485571);
        !           710:                d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606);
        !           711:                c = md5_ii(c, d, a, b, x[i+10], 15, -1051523);
        !           712:                b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799);
        !           713:                a = md5_ii(a, b, c, d, x[i+ 8], 6 ,  1873313359);
        !           714:                d = md5_ii(d, a, b, c, x[i+15], 10, -30611744);
        !           715:                c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380);
        !           716:                b = md5_ii(b, c, d, a, x[i+13], 21,  1309151649);
        !           717:                a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070);
        !           718:                d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379);
        !           719:                c = md5_ii(c, d, a, b, x[i+ 2], 15,  718787259);
        !           720:                b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551);
        !           721: 
        !           722:                a = safe_add(a, olda);
        !           723:                b = safe_add(b, oldb);
        !           724:                c = safe_add(c, oldc);
        !           725:                d = safe_add(d, oldd);
        !           726:          }
        !           727:          return [ a, b, c, d ];
        !           728: 
        !           729:        }
        !           730: 
        !           731:        function md5_cmn(q, a, b, x, s, t) {
        !           732:          return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b);
        !           733:        }
        !           734: 
        !           735:        function md5_ff(a, b, c, d, x, s, t) {
        !           736:          return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
        !           737:        }
        !           738: 
        !           739:        function md5_gg(a, b, c, d, x, s, t) {
        !           740:          return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
        !           741:        }
        !           742: 
        !           743:        function md5_hh(a, b, c, d, x, s, t) {
        !           744:          return md5_cmn(b ^ c ^ d, a, b, x, s, t);
        !           745:        }
        !           746: 
        !           747:        function md5_ii(a, b, c, d, x, s, t) {
        !           748:          return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
        !           749:        }
        !           750: 
        !           751:        function safe_add(x, y) {
        !           752:          var lsw = (x & 0xFFFF) + (y & 0xFFFF);
        !           753:          var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
        !           754:          return (msw << 16) | (lsw & 0xFFFF);
        !           755:        }
        !           756:        function bit_rol(num, cnt) {
        !           757:          return (num << cnt) | (num >>> (32 - cnt));
        !           758:        }
        !           759: 
        !           760:        function str2binl(str) {
        !           761:          var bin = [] ;
        !           762:          var mask = (1 << chrsz) - 1;
        !           763:          for (var i = 0; i < str.length * chrsz; i += chrsz) {
        !           764:                bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (i%32);
        !           765:          }
        !           766:          return bin;
        !           767:        }
        !           768: 
        !           769:        function binl2hex(binarray) {
        !           770:          var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
        !           771:          var str = "";
        !           772:          for (var i = 0; i < binarray.length * 4; i++) {
        !           773:                str += hex_tab.charAt((binarray[i>>2] >> ((i%4)*8+4)) & 0xF) +
        !           774:                           hex_tab.charAt((binarray[i>>2] >> ((i%4)*8  )) & 0xF);
        !           775:          }
        !           776:          return str;
        !           777:        }
        !           778: 
        !           779:        function str2hex ( str ) {
        !           780:                var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
        !           781:                var hex = '';
        !           782:                var val ;
        !           783:                for ( var i=0 ; i<str.length ; i++) {
        !           784:                        /* TODO: adapt this if chrz=16   */
        !           785:                        val = str.charCodeAt(i);
        !           786:                        hex = hex + hex_tab.charAt( val/16 );
        !           787:                        hex = hex + hex_tab.charAt( val%16 );
        !           788:                }
        !           789:                return hex;
        !           790:        }
        !           791: 
        !           792:        function hex2binl ( hex ) {
        !           793:                /*  Clean-up hex encoded input string */
        !           794:                hex = hex.toLowerCase() ;
        !           795:                hex = hex.replace( / /g , "");
        !           796: 
        !           797:                var bin =[] ;
        !           798: 
        !           799:                /* Transfrom to array of integers (binary representation) */ 
        !           800:                for ( i=0 ; i < hex.length*4   ; i=i+8 )  {
        !           801:                        octet =  parseInt( hex.substr( i/4 , 2) , 16) ;
        !           802:                        bin[i>>5] |= ( octet & 255 ) << (i%32);
        !           803:                }
        !           804:                return bin;
        !           805:        }
        !           806:        
        !           807: } // end of ChilliMD5 constructor

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>