Don't set ol-host cookie if value not passed in
[bookreader.git] / BookReaderIA / datanode / BookReaderJSIA.php
1 <?
2 /*
3 Copyright(c)2008 Internet Archive. Software license AGPL version 3.
4
5 This file is part of BookReader.
6
7     BookReader is free software: you can redistribute it and/or modify
8     it under the terms of the GNU Affero General Public License as published by
9     the Free Software Foundation, either version 3 of the License, or
10     (at your option) any later version.
11
12     BookReader is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     GNU Affero General Public License for more details.
16
17     You should have received a copy of the GNU Affero General Public License
18     along with BookReader.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 header('Content-Type: application/javascript');
22
23 $id = $_REQUEST['id'];
24 $itemPath = $_REQUEST['itemPath'];
25 $subPrefix = $_REQUEST['subPrefix'];
26 $server = $_REQUEST['server'];
27
28 // $$$mang this code has been refactored into BookReaderMeta.inc.php for use e.g. by
29 //         BookReaderPreview.php and BookReaderImages.php.  The code below should be
30 //         taken out and replaced by calls into BookReaderMeta
31
32 // Check if we're on a dev vhost and point to JSIA in the user's public_html on the datanode
33
34 // $$$ TODO consolidate this logic
35 if (strpos($_SERVER["REQUEST_URI"], "/~mang") === 0) { // Serving out of home dir
36     $server .= ':80/~mang';
37 } else if (strpos($_SERVER["REQUEST_URI"], "/~rkumar") === 0) { // Serving out of home dir
38     $server .= ':80/~rkumar';
39 } else if (strpos($_SERVER["REQUEST_URI"], "/~testflip") === 0) { // Serving out of home dir
40     $server .= ':80/~testflip';
41 }
42
43 if (! $subPrefix) {
44     $subPrefix = $id;
45 }
46 $subItemPath = $itemPath . '/' . $subPrefix;
47
48 if ("" == $id) {
49     BRFatal("No identifier specified!");
50 }
51
52 if ("" == $itemPath) {
53     BRFatal("No itemPath specified!");
54 }
55
56 if ("" == $server) {
57     BRFatal("No server specified!");
58 }
59
60 if (!preg_match("|^/\d+/items/{$id}$|", $itemPath)) {
61     BRFatal("Bad id!");
62 }
63
64 // XXX check here that subitem is okay
65
66 $filesDataFile = "$itemPath/${id}_files.xml";
67
68 if (file_exists($filesDataFile)) {
69     $filesData = simplexml_load_file("$itemPath/${id}_files.xml");
70 } else {
71     BRfatal("File metadata not found!");
72 }
73
74 $imageStackInfo = findImageStack($subPrefix, $filesData);
75 if ($imageStackInfo['imageFormat'] == 'unknown') {
76     BRfatal('Couldn\'t find image stack');
77 }
78
79 $imageFormat = $imageStackInfo['imageFormat'];
80 $archiveFormat = $imageStackInfo['archiveFormat'];
81 $imageStackFile = $itemPath . "/" . $imageStackInfo['imageStackFile'];
82
83 if ("unknown" == $imageFormat) {
84   BRfatal("Unknown image format");
85 }
86
87 if ("unknown" == $archiveFormat) {
88   BRfatal("Unknown archive format");
89 }
90
91
92 $scanDataFile = "${subItemPath}_scandata.xml";
93 $scanDataZip  = "$itemPath/scandata.zip";
94 if (file_exists($scanDataFile)) {
95     $scanData = simplexml_load_file($scanDataFile);
96 } else if (file_exists($scanDataZip)) {
97     $cmd  = 'unzip -p ' . escapeshellarg($scanDataZip) . ' scandata.xml';
98     exec($cmd, $output, $retval);
99     if ($retval != 0) BRFatal("Could not unzip ScanData!");
100     
101     $dump = join("\n", $output);
102     $scanData = simplexml_load_string($dump);
103 } else if (file_exists("$itemPath/scandata.xml")) {
104     // For e.g. Scribe v.0 books!
105     $scanData = simplexml_load_file("$itemPath/scandata.xml");
106 } else {
107     BRFatal("ScanData file not found!");
108 }
109
110 $metaDataFile = "$itemPath/{$id}_meta.xml";
111 if (!file_exists($metaDataFile)) {
112     BRFatal("MetaData file not found!");
113 }
114
115
116 $metaData = simplexml_load_file($metaDataFile);
117
118 //$firstLeaf = $scanData->pageData->page[0]['leafNum'];
119 ?>
120
121 // Error reporting - this helps us fix errors quickly
122 function logError(description,page,line) {
123     if (typeof(archive_analytics) != 'undefined') {
124         var values = {
125             'bookreader': 'error',
126             'description': description,
127             'page': page,
128             'line': line,
129             'itemid': '<?echo $id;?>',
130             'subPrefix': '<?echo $subPrefix;?>',
131             'server': '<?echo $server;?>',
132             'bookPath': '<?echo $subItemPath;?>'
133         };
134
135         // if no referrer set '-' as referrer
136         if (document.referrer == '') {
137             values['referrer'] = '-';
138         } else {
139             values['referrer'] = document.referrer;
140         }
141         
142         if (typeof(br) != 'undefined') {
143             values['itemid'] = br.bookId;
144             values['subPrefix'] = br.subPrefix;
145             values['server'] = br.server;
146             values['bookPath'] = br.bookPath;
147         }
148         
149         var qs = archive_analytics.format_bug(values);
150
151         var error_img = new Image(100,25);
152         error_img.src = archive_analytics.img_src + "?" + qs;
153     }
154
155     return false; // allow browser error handling so user sees there was a problem
156 }
157 window.onerror=logError;
158
159 br = new BookReader();
160
161 <?
162 /* Output title leaf if marked */
163 $titleLeaf = '';
164 foreach ($scanData->pageData->page as $page) {
165     if (("Title Page" == $page->pageType) || ("Title" == $page->pageType)) {
166         $titleLeaf = "{$page['leafNum']}";
167         break;
168     }
169 }
170     
171 if ('' != $titleLeaf) {
172     printf("br.titleLeaf = %d;\n", $titleLeaf);
173 }
174 ?>
175
176 br.getPageWidth = function(index) {
177     return this.pageW[index];
178 }
179
180 br.getPageHeight = function(index) {
181     return this.pageH[index];
182 }
183
184 // Returns true if page image is available rotated
185 br.canRotatePage = function(index) {
186     return 'jp2' == this.imageFormat; // Assume single format for now
187 }
188
189 // reduce defaults to 1 (no reduction)
190 // rotate defaults to 0 (no rotation)
191 br.getPageURI = function(index, reduce, rotate) {
192     var _reduce;
193     var _rotate;
194
195     if ('undefined' == typeof(reduce)) {
196         _reduce = 1;
197     } else {
198         _reduce = reduce;
199     }
200     if ('undefined' == typeof(rotate)) {
201         _rotate = 0;
202     } else {
203         _rotate = rotate;
204     }
205     
206     var file = this._getPageFile(index);
207         
208     // $$$ add more image stack formats here
209     return 'http://'+this.server+'/BookReader/BookReaderImages.php?zip='+this.zip+'&file='+file+'&scale='+_reduce+'&rotate='+_rotate;
210 }
211
212 // Get a rectangular region out of a page
213 br.getRegionURI = function(index, reduce, rotate, sourceX, sourceY, sourceWidth, sourceHeight) {
214
215     // Map function arguments to the url keys
216     var urlKeys = ['n', 'r', 'rot', 'x', 'y', 'w', 'h'];
217     var page = '';
218     for (var i = 0; i < arguments.length; i++) {
219         if ('undefined' != typeof(arguments[i])) {
220             if (i > 0 ) {
221                 page += '_';
222             }
223             page += urlKeys[i] + arguments[i];
224         }
225     }
226     
227     var itemPath = this.bookPath.replace(new RegExp('/'+this.subPrefix+'$'), ''); // remove trailing subPrefix
228     
229     return 'http://'+this.server+'/BookReader/BookReaderImages.php?id=' + this.bookId + '&itemPath=' + itemPath + '&server=' + this.server + '&subPrefix=' + this.subPrefix + '&page=' +page + '.jpg';
230 }
231
232 br._getPageFile = function(index) {
233     var leafStr = '0000';
234     var imgStr = this.leafMap[index].toString();
235     var re = new RegExp("0{"+imgStr.length+"}$");
236     
237     var insideZipPrefix = this.subPrefix.match('[^/]+$');
238     var file = insideZipPrefix + '_' + this.imageFormat + '/' + insideZipPrefix + '_' + leafStr.replace(re, imgStr) + '.' + this.imageFormat;
239     
240     return file;
241 }
242
243 br.getPageSide = function(index) {
244     //assume the book starts with a cover (right-hand leaf)
245     //we should really get handside from scandata.xml
246     
247     <? // Use special function if we should infer the page sides based off the title page index
248     if (preg_match('/goog$/', $id) && ('' != $titleLeaf)) {
249     ?>
250     // assume page side based on title pagex
251     var titleIndex = br.leafNumToIndex(br.titleLeaf);
252     // assume title page is RHS
253     var delta = titleIndex - index;
254     if (0 == (delta & 0x1)) {
255         // even delta
256         return 'R';
257     } else {
258         return 'L';
259     }
260     <?
261     }
262     ?>
263     
264     // $$$ we should get this from scandata instead of assuming the accessible
265     //     leafs are contiguous
266     if ('rl' != this.pageProgression) {
267         // If pageProgression is not set RTL we assume it is LTR
268         if (0 == (index & 0x1)) {
269             // Even-numbered page
270             return 'R';
271         } else {
272             // Odd-numbered page
273             return 'L';
274         }
275     } else {
276         // RTL
277         if (0 == (index & 0x1)) {
278             return 'L';
279         } else {
280             return 'R';
281         }
282     }
283 }
284
285 br.getPageNum = function(index) {
286     var pageNum = this.pageNums[index];
287     if (pageNum) {
288         return pageNum;
289     } else {
290         return 'n' + index;
291     }
292 }
293
294 // Single images in the Internet Archive scandata.xml metadata are (somewhat incorrectly)
295 // given a "leaf" number.  Some of these images from the scanning process should not
296 // be displayed in the BookReader (for example colour calibration cards).  Since some
297 // of the scanned images will not be displayed in the BookReader (those marked with
298 // addToAccessFormats false in the scandata.xml) leaf numbers and BookReader page
299 // indexes are generally not the same.  This function returns the BookReader page
300 // index given a scanned leaf number.
301 //
302 // This function is used, for example, to map between search results (that use the
303 // leaf numbers) and the displayed pages in the BookReader.
304 br.leafNumToIndex = function(leafNum) {
305     for (var index = 0; index < this.leafMap.length; index++) {
306         if (this.leafMap[index] == leafNum) {
307             return index;
308         }
309     }
310     
311     return null;
312 }
313
314 // This function returns the left and right indices for the user-visible
315 // spread that contains the given index.  The return values may be
316 // null if there is no facing page or the index is invalid.
317 br.getSpreadIndices = function(pindex) {
318     // $$$ we could make a separate function for the RTL case and
319     //      only bind it if necessary instead of always checking
320     // $$$ we currently assume there are no gaps
321     
322     var spreadIndices = [null, null]; 
323     if ('rl' == this.pageProgression) {
324         // Right to Left
325         if (this.getPageSide(pindex) == 'R') {
326             spreadIndices[1] = pindex;
327             spreadIndices[0] = pindex + 1;
328         } else {
329             // Given index was LHS
330             spreadIndices[0] = pindex;
331             spreadIndices[1] = pindex - 1;
332         }
333     } else {
334         // Left to right
335         if (this.getPageSide(pindex) == 'L') {
336             spreadIndices[0] = pindex;
337             spreadIndices[1] = pindex + 1;
338         } else {
339             // Given index was RHS
340             spreadIndices[1] = pindex;
341             spreadIndices[0] = pindex - 1;
342         }
343     }
344     
345     //console.log("   index %d mapped to spread %d,%d", pindex, spreadIndices[0], spreadIndices[1]);
346     
347     return spreadIndices;
348 }
349
350 // Remove the page number assertions for all but the highest index page with
351 // a given assertion.  Ensures there is only a single page "{pagenum}"
352 // e.g. the last page asserted as page 5 retains that assertion.
353 br.uniquifyPageNums = function() {
354     var seen = {};
355     
356     for (var i = br.pageNums.length - 1; i--; i >= 0) {
357         var pageNum = br.pageNums[i];
358         if ( !seen[pageNum] ) {
359             seen[pageNum] = true;
360         } else {
361             br.pageNums[i] = null;
362         }
363     }
364
365 }
366
367 br.cleanupMetadata = function() {
368     br.uniquifyPageNums();
369 }
370
371 // getEmbedURL
372 //________
373 // Returns a URL for an embedded version of the current book
374 br.getEmbedURL = function(viewParams) {
375     // We could generate a URL hash fragment here but for now we just leave at defaults
376     var url = 'http://' + window.location.host + '/stream/'+this.bookId;
377     if (this.subPrefix != this.bookId) { // Only include if needed
378         url += '/' + this.subPrefix;
379     }
380     url += '?ui=embed';
381     if (typeof(viewParams) != 'undefined') {
382         url += '#' + this.fragmentFromParams(viewParams);
383     }
384     return url;
385 }
386
387 // getEmbedCode
388 //________
389 // Returns the embed code HTML fragment suitable for copy and paste
390 br.getEmbedCode = function(frameWidth, frameHeight, viewParams) {
391     return "<iframe src='" + this.getEmbedURL(viewParams) + "' width='" + frameWidth + "' height='" + frameHeight + "' frameborder='0' ></iframe>";
392 }
393
394 // getOpenLibraryRecord
395 br.getOpenLibraryRecord = function(callback) {
396     // Try looking up by ocaid first, then by source_record
397     
398     var self = this; // closure
399     
400     var jsonURL = self.olHost + '/query.json?type=/type/edition&*=&ocaid=' + self.bookId;
401     $.ajax({
402         url: jsonURL,
403         success: function(data) {
404             if (data && data.length > 0) {
405                 callback(self, data[0]);
406             } else {
407                 // try sourceid
408                 jsonURL = self.olHost + '/query.json?type=/type/edition&*=&source_records=ia:' + self.bookId;
409                 $.ajax({
410                     url: jsonURL,
411                     success: function(data) {
412                         if (data && data.length > 0) {
413                             callback(self, data[0]);
414                         }
415                     },
416                     dataType: 'jsonp'
417                 });
418             }
419         },
420         dataType: 'jsonp'
421     });
422 }
423
424 br.buildInfoDiv = function(jInfoDiv) {
425     // $$$ it might make more sense to have a URL on openlibrary.org that returns this info
426
427     var escapedTitle = BookReader.util.escapeHTML(this.bookTitle);
428     var domainRe = /(\w+\.(com|org))/;
429     var domainMatch = domainRe.exec(this.bookUrl);
430     var domain = this.bookUrl;
431     if (domainMatch) {
432         domain = domainMatch[1];
433     }
434        
435     // $$$ cover looks weird before it loads
436     jInfoDiv.find('.BRfloatCover').append([
437                     '<div style="height: 140px; min-width: 80px; padding: 0; margin: 0;"><a href="', this.bookUrl, '"><img src="http://www.archive.org/download/', this.bookId, '/page/cover_t.jpg" alt="' + escapedTitle + '" height="140px" /></a></div>'].join('')
438     );
439
440     jInfoDiv.find('.BRfloatMeta').append([
441                     // $$$ description
442                     //'<p>Published ', this.bookPublished,
443                     //, <a href="Open Library Publisher Page">Publisher name</a>',
444                     //'</p>',
445                     //'<p>Written in <a href="Open Library Language page">Language</a></p>',
446                     '<h3>Other Formats</h3>',
447                     '<ul class="links">',
448                         '<li><a href="http://www.archive.org/download/', this.bookId, '/', this.subPrefix, '.pdf">PDF</a><span>|</span></li>',
449                         '<li><a href="http://www.archive.org/download/', this.bookId, '/', this.subPrefix, '_djvu.txt">Plain Text</a><span>|</span></li>',
450                         '<li><a href="http://www.archive.org/download/', this.bookId, '/', this.subPrefix, '_daisy.zip">DAISY</a><span>|</span></li>',
451                         '<li><a href="http://www.archive.org/download/', this.bookId, '/', this.subPrefix, '.epub">ePub</a><span>|</span></li>',
452                         '<li><a href="https://www.amazon.com/gp/digital/fiona/web-to-kindle?clientid=IA&itemid=', this.bookId, '&docid=', this.subPrefix, '">Send to Kindle</a></li>',
453                     '</ul>',
454                     '<p class="moreInfo"><span></span>More information on <a href="'+ this.bookUrl + '">' + domain + '</a>  </p>'].join('\n'));
455                     
456     jInfoDiv.find('.BRfloatFoot').append([
457                 '<span>|</span>',                
458                 '<a href="http://openlibrary.org/contact" class="problem">Report a problem</a>',
459     ].join('\n'));
460                 
461     if (domain == 'archive.org') {
462         jInfoDiv.find('.BRfloatMeta p.moreInfo span').css(
463             {'background': 'url(http://www.archive.org/favicon.ico) no-repeat', 'width': 22, 'height': 18 }
464         );
465     }
466     
467     jInfoDiv.find('.BRfloatTitle a').attr({'href': this.bookUrl, 'alt': this.bookTitle}).text(this.bookTitle);
468     var bookPath = (window.location + '').replace('#','%23');
469     jInfoDiv.find('a.problem').attr('href','http://openlibrary.org/contact?path=' + bookPath);
470
471 }
472
473 br.pageW =  [
474             <?
475             $i=0;
476             foreach ($scanData->pageData->page as $page) {
477                 if (shouldAddPage($page)) {
478                     if(0 != $i) echo ",";   //stupid IE
479                     echo "{$page->cropBox->w}";
480                     $i++;
481                 }
482             }
483             ?>
484             ];
485
486 br.pageH =  [
487             <?
488             $totalHeight = 0;
489             $i=0;            
490             foreach ($scanData->pageData->page as $page) {
491                 if (shouldAddPage($page)) {
492                     if(0 != $i) echo ",";   //stupid IE                
493                     echo "{$page->cropBox->h}";
494                     $totalHeight += intval($page->cropBox->h/4) + 10;
495                     $i++;
496                 }
497             }
498             ?>
499             ];
500 br.leafMap = [
501             <?
502             $i=0;
503             foreach ($scanData->pageData->page as $page) {
504                 if (shouldAddPage($page)) {
505                     if(0 != $i) echo ",";   //stupid IE
506                     echo "{$page['leafNum']}";
507                     $i++;
508                 }
509             }
510             ?>    
511             ];
512
513 br.pageNums = [
514             <?
515             $i=0;
516             foreach ($scanData->pageData->page as $page) {
517                 if (shouldAddPage($page)) {
518                     if(0 != $i) echo ",";   //stupid IE                
519                     if (array_key_exists('pageNumber', $page) && ('' != $page->pageNumber)) {
520                         echo "'{$page->pageNumber}'";
521                     } else {
522                         echo "null";
523                     }
524                     $i++;
525                 }
526             }
527             ?>    
528             ];
529             
530       
531 br.numLeafs = br.pageW.length;
532
533 br.bookId   = '<?echo $id;?>';
534 br.zip      = '<?echo $imageStackFile;?>';
535 br.subPrefix = '<?echo $subPrefix;?>';
536 br.server   = '<?echo $server;?>';
537 br.bookTitle= '<?echo preg_replace("/\'/", "\\'", $metaData->title);?>';
538 br.bookPath = '<?echo $subItemPath;?>';
539 br.bookUrl  = '<?echo "http://www.archive.org/details/$id";?>';
540 br.imageFormat = '<?echo $imageFormat;?>';
541 br.archiveFormat = '<?echo $archiveFormat;?>';
542
543 <?
544
545 # Load some values from meta.xml
546 if ('' != $metaData->{'page-progression'}) {
547   echo "br.pageProgression = '" . $metaData->{"page-progression"} . "';\n";
548 } else {
549   // Assume page progression is Left To Right
550   echo "br.pageProgression = 'lr';\n";
551 }
552
553 $useOLAuth = false;
554 $protected = false;
555 foreach ($metaData->xpath('//collection') as $collection) {
556     if('browserlending' == $collection) {
557         $useOLAuth = true;
558         $protected = true;
559     }
560 }
561
562 echo "br.olHost = 'http://openlibrary.org';\n";
563 #echo "br.olHost = 'http://mang-dev.us.archive.org:8080';\n";
564
565 if ($useOLAuth) {
566     echo "br.olAuth = true;\n";
567 } else {
568     echo "br.olAuth = false;\n";
569 }
570
571 if ($protected) {
572     echo "br.protected = true;\n";
573 }
574
575 # Default options for BookReader
576 if ('' != $metaData->{'bookreader-defaults'}) {
577     echo "br.defaults = '" . $metaData->{'bookreader-defaults'} . "';\n";
578 }
579
580 ?>
581
582 // Check for config object
583 // $$$ change this to use the newer params object
584 if (typeof(brConfig) != 'undefined') {
585     if (typeof(brConfig["ui"]) != 'undefined') {
586         br.ui = brConfig["ui"];
587     }
588
589     if (brConfig['mode'] == 1) {
590         br.mode = 1;
591         if (typeof(brConfig['reduce'] != 'undefined')) {
592             br.reduce = brConfig['reduce'];
593         }
594     } else if (brConfig['mode'] == 2) {
595         br.mode = 2;      
596     }
597     
598     if (typeof(brConfig["isAdmin"]) != 'undefined') {
599         br.isAdmin = brConfig["isAdmin"];
600     } else {
601         br.isAdmin = false;
602     }
603 } // brConfig
604
605
606 function OLAuth() {
607     this.olConnect = false;
608     this.loanUUID = false;
609     this.permsToken = false;
610     
611     var cookieRe = /;\s*/;
612     var cookies = document.cookie.split(cookieRe);
613     var length = cookies.length;
614     var i;
615     for (i=0; i<length; i++) {
616         if (0 == cookies[i].indexOf('br-loan-' + br.bookId)) {
617             this.loanUUID = cookies[i].split('=')[1];
618         }
619         if (0 == cookies[i].indexOf('loan-' + br.bookId)) {
620             this.permsToken = cookies[i].split('=')[1];
621         }
622         
623         // Set olHost to use if passed in
624         if (0 == cookies[i].indexOf('ol-host')) {
625             br.olHost = 'http://' + unescape(cookies[i].split('=')[1]);
626         }
627     }
628
629     this.authUrl = br.olHost + '/ia_auth/' + br.bookId;
630
631     return this;
632 }
633
634 OLAuth.prototype.init = function() {
635     var htmlStr =  'Checking loan status with Open Library';
636
637     this.showPopup("#F0EEE2", "#000", htmlStr, 'Please wait as we check the status of this book...');
638     var authUrl = this.authUrl+'?rand='+Math.random();
639     if (false !== this.loanUUID) {
640         authUrl += '&loan='+this.loanUUID
641     }
642     if (false !== this.permsToken) {
643         authUrl += '&token='+this.permsToken
644     }
645     $.ajax({url:authUrl, dataType:'jsonp', jsonpCallback:'olAuth.initCallback'});
646 }
647
648 OLAuth.prototype.showPopup = function(bgColor, textColor, msg, resolution) {
649     this.popup = document.createElement("div");
650     $(this.popup).css({
651         position: 'absolute',
652         top:      '50px',
653         left:     ($('#BookReader').attr('clientWidth')-400)/2 + 'px',
654         width:    '400px',
655         padding:  "15px",
656         border:   "3px double #999999",
657         zIndex:   3,
658         textAlign: 'center',
659         backgroundColor: bgColor,
660         color: textColor
661     }).appendTo('#BookReader');
662
663     this.setPopupMsg(msg, resolution);
664
665 }
666
667 OLAuth.prototype.setPopupMsg = function(msg, resolution) {
668     this.popup.innerHTML = ['<p><strong>', msg, '</strong></p><p>', resolution, '</p>'].join('\n');
669 }
670
671 OLAuth.prototype.showError = function(msg, resolution) {
672    $(this.popup).css({
673         backgroundColor: "#fff",
674         color: "#000"
675     });
676
677     this.setPopupMsg(msg, resolution);
678 }
679
680 OLAuth.prototype.initCallback = function(obj) {
681     if (false == obj.success) {
682         if (br.isAdmin) {
683             ret = confirm("We couldn't authenticate your loan with Open Library, but since you are an administrator or uploader of this book, you can access this book for QA purposes. Would you like to QA this book?");
684             if (!ret) {
685                 this.showError(obj.msg, obj.resolution)
686             } else {
687                 br.init();
688             }
689         } else {
690             this.showError(obj.msg, obj.resolution)
691         }       
692     } else {    
693         //user is authenticated
694         this.setCookie(obj.token);
695         this.olConnect = true;
696         this.startPolling();    
697         br.init();
698     }
699 }
700
701 OLAuth.prototype.callback = function(obj) {
702     if (false == obj.success) {
703         this.showPopup("#F0EEE2", "#000", obj.msg, obj.resolution);
704         clearInterval(this.poller);
705         this.ttsPoller = null;
706     } else {
707         this.olConnect = true;
708         this.setCookie(obj.token);
709     }
710 }
711
712 OLAuth.prototype.setCookie = function(value) {
713     var date = new Date();
714     date.setTime(date.getTime()+(10*60*1000));  //10 min expiry
715     var expiry = date.toGMTString();
716     var cookie = 'loan-'+br.bookId+'='+value;
717     cookie    += '; expires='+expiry;
718     cookie    += '; path=/; domain=.archive.org;';
719     document.cookie = cookie;
720     this.permsToken = value;
721     
722     //refresh the br-loan uuid cookie with current expiry, if needed
723     if (false !== this.loanUUID) {
724         cookie = 'br-loan-'+br.bookId+'='+this.loanUUID;
725         cookie    += '; expires='+expiry;
726         cookie    += '; path=/; domain=.archive.org;';
727         document.cookie = cookie;
728     }
729 }
730
731 OLAuth.prototype.deleteCookies = function() {
732     var date = new Date();
733     date.setTime(date.getTime()-(24*60*60*1000));  //one day ago
734     var expiry = date.toGMTString();
735     var cookie = 'loan-'+br.bookId+'=""';
736     cookie    += '; expires='+expiry;
737     cookie    += '; path=/; domain=.archive.org;';
738     document.cookie = cookie;
739     
740     cookie = 'br-loan-'+br.bookId+'=""';
741     cookie    += '; expires='+expiry;
742     cookie    += '; path=/; domain=.archive.org;';
743     document.cookie = cookie;
744 }
745
746 OLAuth.prototype.startPolling = function () {    
747     var self = this;
748     this.poller=setInterval(function(){
749         if (!self.olConnect) {
750           self.showPopup("#F0EEE2", "#000", 'Connection error', 'The BookReader cannot reach Open Library. This might mean that you are offline or that Open Library is down. Please check your Internet connection and refresh this page or try again later.');
751           clearInterval(self.poller);
752           self.ttsPoller = null;        
753         } else {
754           self.olConnect = false;
755           //be sure to add random param to authUrl to avoid stale cache
756           var authUrl = self.authUrl+'?rand='+Math.random();
757           if (false !== self.loanUUID) {
758               authUrl += '&loan='+self.loanUUID
759           }
760           if (false !== self.permsToken) {
761               authUrl += '&token='+self.permsToken
762           }
763
764           $.ajax({url:authUrl, dataType:'jsonp', jsonpCallback:'olAuth.callback'});
765         }
766     },300000);   //five minute interval
767 }
768
769 br.cleanupMetadata();
770 if (br.olAuth) {
771     var olAuth = new OLAuth();
772     olAuth.init();
773 } else {
774     br.init();
775 }
776 <?
777
778
779 function BRFatal($string) {
780     // log error
781     ?>
782     
783     if (typeof(archive_analytics) != 'undefined') {
784         var values = {
785             'bookreader': 'fatal',
786             'description': "<? echo $string; ?>",
787             'itemid': "<? echo $_REQUEST['id']; ?>",
788             'server': "<? echo $_REQUEST['server']; ?>",
789             'request_uri': "<? echo $_SERVER["REQUEST_URI"]; ?>"
790         }
791         
792         if (document.referrer == '') {
793             values['referrer'] = '-';
794         } else {
795             values['referrer'] = document.referrer;
796         }
797         
798         var qs = archive_analytics.format_bug(values);
799
800         var error_img = new Image(100,25);
801         error_img.src = archive_analytics.img_src + "?" + qs;
802     }
803
804     alert("<? echo $string;?>");
805     
806     <?
807     
808     die(-1);
809 }
810
811 // Returns true if a page should be added based on it's information in
812 // the metadata
813 function shouldAddPage($page) {
814     // Return false only if the page is marked addToAccessFormats false.
815     // If there is no assertion we assume it should be added.
816     if (isset($page->addToAccessFormats)) {
817         if ("false" == strtolower(trim($page->addToAccessFormats))) {
818             return false;
819         }
820     }
821     
822     return true;
823 }
824
825 // Returns { 'imageFormat' => , 'archiveFormat' => '} given a sub-item prefix and loaded xml data
826 function findImageStack($subPrefix, $filesData) {
827
828     // $$$ The order of the image formats determines which will be returned first
829     $imageFormats = array('JP2' => 'jp2', 'TIFF' => 'tif', 'JPEG' => 'jpg');
830     $archiveFormats = array('ZIP' => 'zip', 'Tar' => 'tar');
831     $imageGroup = implode('|', array_keys($imageFormats));
832     $archiveGroup = implode('|', array_keys($archiveFormats));
833     // $$$ Currently only return processed images
834     $imageStackRegex = "/Single Page (Processed) (${imageGroup}) (${archiveGroup})/";
835         
836     foreach ($filesData->file as $file) {        
837         if (strpos($file['name'], $subPrefix) === 0) { // subprefix matches beginning
838             if (preg_match($imageStackRegex, $file->format, $matches)) {
839             
840                 // Make sure we have a regular image stack
841                 $imageFormat = $imageFormats[$matches[2]];
842                 if (strpos($file['name'], $subPrefix . '_' . $imageFormat) === 0) {            
843                     return array('imageFormat' => $imageFormat,
844                                  'archiveFormat' => $archiveFormats[$matches[3]],
845                                  'imageStackFile' => $file['name']);
846                 }
847             }
848         }
849     }
850     
851     return array('imageFormat' => 'unknown', 'archiveFormat' => 'unknown', 'imageStackFile' => 'unknown');
852         
853 }
854
855 ?>
856