Update tests
[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.authUrl = br.olHost + '/ia_auth/' + br.bookId;
608     this.olConnect = false;
609     this.loanUUID = false;
610     this.permsToken = false;
611     
612     var cookieRe = /;\s*/;
613     var cookies = document.cookie.split(cookieRe);
614     var length = cookies.length;
615     var i;
616     for (i=0; i<length; i++) {
617         if (0 == cookies[i].indexOf('br-loan-' + br.bookId)) {
618             this.loanUUID = cookies[i].split('=')[1];
619         }
620         if (0 == cookies[i].indexOf('loan-' + br.bookId)) {
621             this.permsToken = cookies[i].split('=')[1];
622         }
623     }
624
625     return this;
626 }
627
628 OLAuth.prototype.init = function() {
629     var htmlStr =  'Checking loan status with Open Library';
630
631     this.showPopup("#F0EEE2", "#000", htmlStr, 'Please wait as we check the status of this book...');
632     var authUrl = this.authUrl+'?rand='+Math.random();
633     if (false !== this.loanUUID) {
634         authUrl += '&loan='+this.loanUUID
635     }
636     if (false !== this.permsToken) {
637         authUrl += '&token='+this.permsToken
638     }
639     $.ajax({url:authUrl, dataType:'jsonp', jsonpCallback:'olAuth.initCallback'});
640 }
641
642 OLAuth.prototype.showPopup = function(bgColor, textColor, msg, resolution) {
643     this.popup = document.createElement("div");
644     $(this.popup).css({
645         position: 'absolute',
646         top:      '50px',
647         left:     ($('#BookReader').attr('clientWidth')-400)/2 + 'px',
648         width:    '400px',
649         padding:  "15px",
650         border:   "3px double #999999",
651         zIndex:   3,
652         textAlign: 'center',
653         backgroundColor: bgColor,
654         color: textColor
655     }).appendTo('#BookReader');
656
657     this.setPopupMsg(msg, resolution);
658
659 }
660
661 OLAuth.prototype.setPopupMsg = function(msg, resolution) {
662     this.popup.innerHTML = ['<p><strong>', msg, '</strong></p><p>', resolution, '</p>'].join('\n');
663 }
664
665 OLAuth.prototype.showError = function(msg, resolution) {
666    $(this.popup).css({
667         backgroundColor: "#fff",
668         color: "#000"
669     });
670
671     this.setPopupMsg(msg, resolution);
672 }
673
674 OLAuth.prototype.initCallback = function(obj) {
675     if (false == obj.success) {
676         if (br.isAdmin) {
677             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?");
678             if (!ret) {
679                 this.showError(obj.msg, obj.resolution)
680             } else {
681                 br.init();
682             }
683         } else {
684             this.showError(obj.msg, obj.resolution)
685         }       
686     } else {    
687         //user is authenticated
688         this.setCookie(obj.token);
689         this.olConnect = true;
690         this.startPolling();    
691         br.init();
692     }
693 }
694
695 OLAuth.prototype.callback = function(obj) {
696     if (false == obj.success) {
697         this.showPopup("#F0EEE2", "#000", obj.msg, obj.resolution);
698         clearInterval(this.poller);
699         this.ttsPoller = null;
700     } else {
701         this.olConnect = true;
702         this.setCookie(obj.token);
703     }
704 }
705
706 OLAuth.prototype.setCookie = function(value) {
707     var date = new Date();
708     date.setTime(date.getTime()+(10*60*1000));  //10 min expiry
709     var expiry = date.toGMTString();
710     var cookie = 'loan-'+br.bookId+'='+value;
711     cookie    += '; expires='+expiry;
712     cookie    += '; path=/; domain=.archive.org;';
713     document.cookie = cookie;
714     this.permsToken = value;
715     
716     //refresh the br-loan uuid cookie with current expiry, if needed
717     if (false !== this.loanUUID) {
718         cookie = 'br-loan-'+br.bookId+'='+this.loanUUID;
719         cookie    += '; expires='+expiry;
720         cookie    += '; path=/; domain=.archive.org;';
721         document.cookie = cookie;
722     }
723 }
724
725 OLAuth.prototype.deleteCookies = function() {
726     var date = new Date();
727     date.setTime(date.getTime()-(24*60*60*1000));  //one day ago
728     var expiry = date.toGMTString();
729     var cookie = 'loan-'+br.bookId+'=""';
730     cookie    += '; expires='+expiry;
731     cookie    += '; path=/; domain=.archive.org;';
732     document.cookie = cookie;
733     
734     cookie = 'br-loan-'+br.bookId+'=""';
735     cookie    += '; expires='+expiry;
736     cookie    += '; path=/; domain=.archive.org;';
737     document.cookie = cookie;
738 }
739
740 OLAuth.prototype.startPolling = function () {    
741     var self = this;
742     this.poller=setInterval(function(){
743         if (!self.olConnect) {
744           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.');
745           clearInterval(self.poller);
746           self.ttsPoller = null;        
747         } else {
748           self.olConnect = false;
749           //be sure to add random param to authUrl to avoid stale cache
750           var authUrl = self.authUrl+'?rand='+Math.random();
751           if (false !== self.loanUUID) {
752               authUrl += '&loan='+self.loanUUID
753           }
754           if (false !== self.permsToken) {
755               authUrl += '&token='+self.permsToken
756           }
757
758           $.ajax({url:authUrl, dataType:'jsonp', jsonpCallback:'olAuth.callback'});
759         }
760     },300000);   //five minute interval
761 }
762
763 br.cleanupMetadata();
764 if (br.olAuth) {
765     var olAuth = new OLAuth();
766     olAuth.init();
767 } else {
768     br.init();
769 }
770 <?
771
772
773 function BRFatal($string) {
774     // log error
775     ?>
776     
777     if (typeof(archive_analytics) != 'undefined') {
778         var values = {
779             'bookreader': 'fatal',
780             'description': "<? echo $string; ?>",
781             'itemid': "<? echo $_REQUEST['id']; ?>",
782             'server': "<? echo $_REQUEST['server']; ?>",
783             'request_uri': "<? echo $_SERVER["REQUEST_URI"]; ?>"
784         }
785         
786         if (document.referrer == '') {
787             values['referrer'] = '-';
788         } else {
789             values['referrer'] = document.referrer;
790         }
791         
792         var qs = archive_analytics.format_bug(values);
793
794         var error_img = new Image(100,25);
795         error_img.src = archive_analytics.img_src + "?" + qs;
796     }
797
798     alert("<? echo $string;?>");
799     
800     <?
801     
802     die(-1);
803 }
804
805 // Returns true if a page should be added based on it's information in
806 // the metadata
807 function shouldAddPage($page) {
808     // Return false only if the page is marked addToAccessFormats false.
809     // If there is no assertion we assume it should be added.
810     if (isset($page->addToAccessFormats)) {
811         if ("false" == strtolower(trim($page->addToAccessFormats))) {
812             return false;
813         }
814     }
815     
816     return true;
817 }
818
819 // Returns { 'imageFormat' => , 'archiveFormat' => '} given a sub-item prefix and loaded xml data
820 function findImageStack($subPrefix, $filesData) {
821
822     // $$$ The order of the image formats determines which will be returned first
823     $imageFormats = array('JP2' => 'jp2', 'TIFF' => 'tif', 'JPEG' => 'jpg');
824     $archiveFormats = array('ZIP' => 'zip', 'Tar' => 'tar');
825     $imageGroup = implode('|', array_keys($imageFormats));
826     $archiveGroup = implode('|', array_keys($archiveFormats));
827     // $$$ Currently only return processed images
828     $imageStackRegex = "/Single Page (Processed) (${imageGroup}) (${archiveGroup})/";
829         
830     foreach ($filesData->file as $file) {        
831         if (strpos($file['name'], $subPrefix) === 0) { // subprefix matches beginning
832             if (preg_match($imageStackRegex, $file->format, $matches)) {
833             
834                 // Make sure we have a regular image stack
835                 $imageFormat = $imageFormats[$matches[2]];
836                 if (strpos($file['name'], $subPrefix . '_' . $imageFormat) === 0) {            
837                     return array('imageFormat' => $imageFormat,
838                                  'archiveFormat' => $archiveFormats[$matches[3]],
839                                  'imageStackFile' => $file['name']);
840                 }
841             }
842         }
843     }
844     
845     return array('imageFormat' => 'unknown', 'archiveFormat' => 'unknown', 'imageStackFile' => 'unknown');
846         
847 }
848
849 ?>
850