home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / lib / libnet / mkcache.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  87.9 KB  |  3,449 lines

  1. /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. /* implements disk caching:  See mkmemcac.c for memory cache
  20.  *
  21.  * Designed and originally implemented by Lou Montulli '94
  22.  * Modifications/additions by Gagan Saksena '97
  23.  */
  24.  
  25. /* Please leave outside of ifdef for windows precompiled headers */
  26. #include "mkutils.h"
  27.  
  28. #ifdef MOZILLA_CLIENT
  29.  
  30. /* dbm code */
  31.  
  32. #include "extcache.h"
  33. #include "mkcache.h"
  34. #include "glhist.h"
  35. #include "xp_hash.h"
  36. #include "xp_mcom.h"
  37. #include "client.h"
  38. #include "mkgeturl.h"
  39. #include "mkstream.h"
  40. #include "cert.h" /* for CERT_DupCertificate() */
  41. #include "mcom_db.h"
  42. #include "prclist.h"
  43.  
  44. #include "mkextcac.h"
  45. #include "mkfile.h"
  46. #include "mkmemcac.h"
  47. #include "merrors.h"
  48.  
  49. #ifdef PROFILE
  50. #pragma profile on
  51. #endif
  52.  
  53. #ifdef XP_OS2_NOT_YET
  54. /*serious hack to put cache cleanup on another thread...*/
  55. extern int XP_LazyFileRemove(const char * name, XP_FileType type);
  56. #else
  57. #define XP_LazyFileRemove  XP_FileRemove
  58. #endif
  59.  
  60. /* for XP_GetString() */
  61. #include "xpgetstr.h"
  62. extern int XP_CACHE_CLEANUP;
  63. extern int MK_CACHE_CONTENT_LENGTH;
  64. extern int MK_CACHE_REAL_CONTENT_LENGTH;
  65. extern int MK_CACHE_CONTENT_TYPE;
  66. extern int MK_CACHE_LOCAL_FILENAME;
  67. extern int MK_CACHE_LAST_MODIFIED;
  68. extern int MK_CACHE_EXPIRES;
  69. extern int MK_CACHE_LAST_ACCESSED;
  70. extern int MK_CACHE_CHARSET;
  71. extern int MK_CACHE_SECURE;
  72. extern int MK_CACHE_USES_RELATIVE_PATH;
  73. extern int MK_CACHE_FROM_NETSITE_SERVER;
  74.  
  75. #define INTERNAL_NAME_PREFIX       "INT_"
  76. #define DISK_CACHE_SIZE_KEY_NAME   "INT_DiskCacheSize"
  77. #define DISK_CACHE_NUMBER_KEY_NAME "INT_DiskCacheNumber"
  78. #define DISK_CACHE_NAME               "Netscape Internal Disk Cache"
  79.  
  80. #define CACHE_SYNC_RATE 30
  81.  
  82. typedef enum {
  83.     NEW_CACHE_STORE,
  84.     REFRESH_CACHE_STORE
  85. } store_type_enum;
  86.  
  87. PRIVATE DBT       *net_DiskCacheSizeKey=0;
  88. PRIVATE DBT          *net_DiskCacheNumberKey=0;
  89. PRIVATE DBT          *net_DiskCacheNameKey=0;
  90. PRIVATE uint32     net_DiskCacheSize=0;
  91. PRIVATE uint32     net_NumberInDiskCache=0;
  92. PRIVATE uint32     net_MaxDiskCacheSize=0;
  93. PRIVATE uint32     net_cache_file_block_size=0;
  94.  
  95. /* Saves the cache struct to the DB */
  96. extern void CACHE_SaveCacheInfoToDB(ExtCacheDBInfo *db_info);
  97.  
  98. #ifdef NO_MEMORY_CACHE
  99. PRIVATE uint32     net_MaxMemoryCacheSize=0;
  100. #endif /* NO_MEMORY_CACHE */
  101.  
  102. /* trace variable for cache testing */
  103. MODULE_PRIVATE XP_Bool NET_CacheTraceOn = FALSE;
  104.  
  105. PRIVATE XP_Bool net_dont_disk_cache_ssl = FALSE;
  106. PRIVATE DB * cache_database = 0; 
  107. /* PRIVATE XXX Mac CodeWarrior bug */ PRCList active_cache_data_objects
  108.     = PR_INIT_STATIC_CLIST(&active_cache_data_objects);
  109.  
  110. typedef struct _CacheDataObject {
  111.     PRCList          links;
  112.     XP_File          fp;
  113.     NET_StreamClass *next_stream;
  114.     URL_Struct      *URL_s;
  115.     net_CacheObject *cache_object;
  116. } CacheDataObject;
  117.  
  118. PRIVATE void net_RemoveAllDiskCacheObjects(void);
  119.  
  120. /* pass in TRUE to disable disk caching
  121.  * of SSL documents.
  122.  * pass in FALSE to enable disk cacheing
  123.  * of SSL documents
  124.  */
  125. PUBLIC void
  126. NET_DontDiskCacheSSL(XP_Bool set)
  127. {
  128.     net_dont_disk_cache_ssl = set;
  129. }
  130.  
  131. /* return the size of the file on
  132.  * disk based on the block size
  133.  */
  134. PRIVATE
  135. uint32
  136. net_calc_real_file_size(uint32 size)
  137. {
  138.     if(net_cache_file_block_size == 0)
  139.         return(size);
  140.     else  /* round sizes up to the next block size */
  141.         return(PR_ROUNDUP(size, net_cache_file_block_size));
  142. }
  143.  
  144. PRIVATE void
  145. net_GetDiskCacheSize(void)
  146. {
  147.     DBT data;
  148.  
  149.     if(!cache_database)
  150.         return;
  151.  
  152.     if(!net_DiskCacheSizeKey)
  153.       {
  154.         net_DiskCacheSizeKey = XP_NEW(DBT);
  155.         if(!net_DiskCacheSizeKey)
  156.             return;
  157.  
  158.         net_DiskCacheSizeKey->data = 0;
  159.         BlockAllocCopy(net_DiskCacheSizeKey->data, 
  160.                           DISK_CACHE_SIZE_KEY_NAME, 
  161.                        XP_STRLEN(DISK_CACHE_SIZE_KEY_NAME));
  162.         net_DiskCacheSizeKey->size = XP_STRLEN(DISK_CACHE_SIZE_KEY_NAME);
  163.       }
  164.  
  165.     if(0 == (*cache_database->get)(cache_database, 
  166.                                    net_DiskCacheSizeKey, 
  167.                                    &data, 
  168.                                    0))
  169.       {
  170.         if(data.size == sizeof(uint32))
  171.           {
  172.             COPY_INT32(&net_DiskCacheSize, data.data);
  173.           }
  174.         else
  175.           {
  176.             net_DiskCacheSize = 0;
  177.           }
  178.       }
  179.     else
  180.       {
  181.         net_DiskCacheSize = 0;
  182.       }
  183.  
  184.     if(!net_DiskCacheNumberKey)
  185.       {
  186.         net_DiskCacheNumberKey = XP_NEW(DBT);
  187.         if(!net_DiskCacheNumberKey)
  188.             return;
  189.  
  190.         net_DiskCacheNumberKey->data = 0;
  191.         BlockAllocCopy(net_DiskCacheNumberKey->data, 
  192.                        DISK_CACHE_NUMBER_KEY_NAME,
  193.                        XP_STRLEN(DISK_CACHE_NUMBER_KEY_NAME));
  194.         net_DiskCacheNumberKey->size = XP_STRLEN(DISK_CACHE_NUMBER_KEY_NAME);
  195.       }
  196.  
  197.     if(0 == (*cache_database->get)(cache_database,
  198.                                    net_DiskCacheNumberKey,
  199.                                    &data,
  200.                                    0))
  201.       {
  202.         if(data.size == sizeof(uint32))
  203.           {
  204.             COPY_INT32(&net_NumberInDiskCache, data.data);
  205.           }
  206.         else
  207.           {
  208.             net_NumberInDiskCache = 0;
  209.           }
  210.       }
  211.     else
  212.       {
  213.         net_NumberInDiskCache = 0;
  214.       }
  215.  
  216. }
  217.  
  218.  
  219. PRIVATE int
  220. net_OpenCacheFatDB(void)
  221. {
  222.     char* filename;
  223.     static Bool have_tried_open=FALSE;
  224.  
  225.     if(!cache_database)
  226.       {
  227.     HASHINFO hash_info = {
  228.         4 * 1024,
  229.         0,
  230.         0,
  231. #ifdef WIN16
  232.         60 * 1024,
  233. #else
  234.         96 * 1024,
  235. #endif
  236.         0,
  237.         0};
  238.         filename = WH_FileName("", xpCacheFAT);
  239.         if (!filename) return 0;
  240.  
  241.         /* @@@ add .db to the end of the files
  242.          */
  243.         cache_database = dbopen(filename,
  244.                                 O_RDWR | O_CREAT,
  245.                                 0600,
  246.                                 DB_HASH,
  247.                                 &hash_info);
  248.         XP_FREE(filename);
  249.  
  250.         if(!have_tried_open && !cache_database)
  251.           {
  252.             XP_StatStruct stat_entry;
  253.  
  254.             have_tried_open = TRUE; /* only do this once */
  255.  
  256.             TRACEMSG(("Could not open cache database -- errno: %d", errno));
  257.  
  258.             /* if the file is zero length remove it
  259.              */
  260.              if(XP_Stat("", &stat_entry, xpCacheFAT) != -1)
  261.               {
  262.                    if(stat_entry.st_size <= 0)
  263.                   {
  264.                     XP_FileRemove("", xpCacheFAT);
  265.                   }
  266.                 else
  267.                   {
  268.                     XP_File fp;
  269. #define BUFF_SIZE 1024
  270.                     char buffer[BUFF_SIZE];
  271.  
  272.                     /* open the file and look for
  273.                      * the old magic cookie.  If it's
  274.                      * there delete the file
  275.                      */
  276.                     fp = XP_FileOpen("", xpCacheFAT, XP_FILE_READ);
  277.  
  278.                     if(fp)
  279.                       {
  280.                         XP_FileReadLine(buffer, BUFF_SIZE, fp);
  281.  
  282.                         XP_FileClose(fp);
  283.  
  284.                         if(XP_STRSTR(buffer, 
  285.                                      "Cache-file-allocation-table-format"))
  286.                           XP_FileRemove("", xpCacheFAT);
  287.  
  288.                       }
  289.                   }
  290.               }
  291.  
  292.  
  293.             /* try it again */
  294.             filename = WH_FileName("", xpCacheFAT);
  295.             if (filename) {
  296.                 cache_database = dbopen(filename,
  297.                                         O_RDWR | O_CREAT,
  298.                                         0600,
  299.                                         DB_HASH,
  300.                                         0);
  301.                 XP_FREE(filename);
  302.             }
  303.             else 
  304.                 cache_database = NULL;
  305.           }
  306.  
  307.         if(cache_database)
  308.           {
  309.             if(-1 == (*cache_database->sync)(cache_database, 0))
  310.                 {
  311.                 TRACEMSG(("Error syncing cache database"));
  312.  
  313.                 /* close the database */
  314.                 (*cache_database->close)(cache_database);
  315.                 cache_database = 0;
  316.                 }
  317.  
  318.             net_GetDiskCacheSize();
  319.           }
  320.  
  321. #if !defined(XP_WIN) && !defined(XP_OS2)
  322.         /* if we don't know the standard block size yet
  323.          * get it now
  324.          */
  325.         if(!net_cache_file_block_size)
  326.           {
  327.             XP_StatStruct stat_entry;
  328.  
  329.             if(XP_Stat("", &stat_entry, xpCacheFAT) != -1)
  330.                 net_cache_file_block_size = stat_entry.st_blksize;
  331.           }
  332. #endif
  333.       }
  334.  
  335.     /* return non-zero if the cache_database pointer is
  336.      * non-zero
  337.      */
  338.     return((int) cache_database);
  339.  
  340. }
  341.  
  342. #if defined(DEBUG) && defined(UNIX)
  343. int
  344. cache_test_me()
  345. {
  346.  
  347.     net_CacheObject test;
  348.     net_CacheObject *rv;
  349.     int32 total_size;
  350.     DBT *db_obj;
  351.  
  352.     XP_MEMSET(&test, 0, sizeof(net_CacheObject));
  353.     StrAllocCopy(test.address, "test1");
  354.     db_obj = net_CacheStructToDBData(&test);
  355.     rv = net_DBDataToCacheStruct(db_obj);
  356.     printf("test1: %s\n", rv->address);
  357.  
  358.     XP_MEMSET(&test, 0, sizeof(net_CacheObject));
  359.     StrAllocCopy(test.address, "test2");
  360.     StrAllocCopy(test.charset, "test2");
  361.     db_obj = net_CacheStructToDBData(&test);
  362.     rv = net_DBDataToCacheStruct(db_obj);
  363.     printf("test2: %s    %s\n", rv->address, rv->charset);
  364.  
  365.     XP_MEMSET(&test, 0, sizeof(net_CacheObject));
  366.     StrAllocCopy(test.address, "test3");
  367.     StrAllocCopy(test.charset, "test3");
  368.     StrAllocCopy(test.key_cipher, "test3");
  369.     test.content_length = 3 ;
  370.     test.method = 3 ;
  371.     test.is_netsite = 3 ;
  372.     db_obj = net_CacheStructToDBData(&test);
  373.     rv = net_DBDataToCacheStruct(db_obj);
  374.     printf("test3: %s    %s    %s    %d    %d    %s\n", 
  375.             rv->address, rv->charset, rv->key_cipher,
  376.             rv->content_length, rv->method, 
  377.             (rv->is_netsite == 3 ? "TRUE" : "FALSE"));
  378.  
  379. }
  380. #endif
  381.  
  382. PRIVATE void
  383. net_StoreDiskCacheSize(void)
  384. {
  385.     DBT data;
  386.     uint32 tmp_num;
  387.  
  388.     if(!cache_database)
  389.         return;
  390.     
  391.     if(!net_DiskCacheSizeKey)
  392.       {
  393.         net_DiskCacheSizeKey = XP_NEW(DBT);
  394.         if(!net_DiskCacheSizeKey)
  395.             return;
  396.  
  397.         net_DiskCacheSizeKey->data = 0;
  398.         BlockAllocCopy(net_DiskCacheSizeKey->data, 
  399.                        DISK_CACHE_SIZE_KEY_NAME,
  400.                        XP_STRLEN((char *)DISK_CACHE_SIZE_KEY_NAME));
  401.         net_DiskCacheSizeKey->size = XP_STRLEN(DISK_CACHE_SIZE_KEY_NAME);
  402.       }
  403.  
  404.     if(!net_DiskCacheNumberKey)
  405.       {
  406.         net_DiskCacheNumberKey = XP_NEW(DBT);
  407.         if(!net_DiskCacheNumberKey)
  408.             return;
  409.  
  410.         net_DiskCacheNumberKey->data = 0;
  411.         BlockAllocCopy(net_DiskCacheNumberKey->data, 
  412.                        DISK_CACHE_NUMBER_KEY_NAME,
  413.                        XP_STRLEN((char *)DISK_CACHE_NUMBER_KEY_NAME));
  414.         net_DiskCacheNumberKey->size = XP_STRLEN(DISK_CACHE_NUMBER_KEY_NAME);
  415.       }
  416.  
  417.     if(!net_DiskCacheNameKey)
  418.       {
  419.         /* set the name of the cache so that
  420.          * if it is read as an external cache
  421.          * we will know what created it
  422.          */
  423.         net_DiskCacheNameKey = XP_NEW(DBT);
  424.         if(!net_DiskCacheNameKey)
  425.             return;
  426.  
  427.         net_DiskCacheNameKey->data = 0;
  428.         BlockAllocCopy(net_DiskCacheNameKey->data, 
  429.                        EXT_CACHE_NAME_STRING,
  430.                        XP_STRLEN((char *)EXT_CACHE_NAME_STRING));
  431.         net_DiskCacheNameKey->size = XP_STRLEN(EXT_CACHE_NAME_STRING);
  432.       }
  433.  
  434.     data.size = sizeof(uint32);
  435.     COPY_INT32(&tmp_num, &net_DiskCacheSize);
  436.     data.data = &tmp_num;
  437.     
  438.     (*cache_database->put)(cache_database, net_DiskCacheSizeKey, &data, 0);
  439.  
  440.     data.size = sizeof(uint32);
  441.     COPY_INT32(&tmp_num, &net_NumberInDiskCache);
  442.     data.data = &tmp_num;
  443.     
  444.     (*cache_database->put)(cache_database, net_DiskCacheNumberKey, &data, 0);
  445.  
  446.     data.size = XP_STRLEN(DISK_CACHE_NAME)+1;
  447.     data.data = DISK_CACHE_NAME;
  448.     
  449.     (*cache_database->put)(cache_database, net_DiskCacheNameKey, &data, 0);
  450.  
  451. }
  452.  
  453. /* returns TRUE if the object gets stored
  454.  * FALSE if not
  455.  */
  456. PRIVATE Bool
  457. net_CacheStore(net_CacheObject * obj,  
  458.                URL_Struct      * URL_s, 
  459.                Bool                 accept_partial_files,
  460.                store_type_enum      store_type)
  461. {
  462.     DBT *data, *key;
  463.     int status;
  464.     static cache_sync_count = 0;
  465.     XP_StatStruct stat_entry;
  466.  
  467.     /* larubbio */
  468.     Bool        SARCache = FALSE;
  469.     XP_FileType fileType;
  470.     DB            *local_cache_database = NULL;
  471.  
  472.     /* larubbio fix to allow 197 SAR cache adds without modifying 
  473.      * the navigator cache (too much)
  474.      */
  475.     if ( URL_s != NULL && URL_s->SARCache != NULL )
  476.     {
  477.         SARCache = TRUE;
  478.         fileType = xpSARCache;
  479.         local_cache_database = URL_s->SARCache->database;
  480.     }
  481.     else
  482.     {
  483.         fileType = xpCache;
  484.         local_cache_database = cache_database;
  485.     }
  486.  
  487.     if(!local_cache_database)
  488.       {
  489.         /* delete the file since we wont remember it
  490.          */
  491. #ifdef XP_OS2
  492.         XP_LazyFileRemove(obj->filename, fileType);
  493. #else
  494.         XP_FileRemove(obj->filename, fileType);
  495. #endif
  496.         
  497.         return FALSE;
  498.       }
  499.  
  500.     if(URL_s 
  501.         && URL_s->server_date 
  502.         && URL_s->server_date < obj->last_modified)
  503.       {
  504.         /* the last modified date is after the current date
  505.          * as given by the server.  We shoudn't cache this
  506.          * object
  507.          */
  508.  
  509.         TRACEMSG(("Found file dated into the future.  "
  510.                 "Zeroing the last modified date"));
  511.         obj->last_modified = 0;
  512.         URL_s->last_modified = 0;
  513.       }
  514.  
  515.     if(store_type == NEW_CACHE_STORE)
  516.       {
  517.         if(URL_s && URL_s->dont_cache)  
  518.             {
  519.             /* delete the file since we wont remember it
  520.              */
  521. #ifdef XP_OS2
  522.             XP_LazyFileRemove(obj->filename, fileType);
  523. #else
  524.             XP_FileRemove(obj->filename, fileType);
  525. #endif
  526.             return FALSE;
  527.           }
  528.         else if(XP_Stat(obj->filename, &stat_entry,  fileType) != -1)
  529.           {
  530.             if(stat_entry.st_size == 0)
  531.               {
  532.                 /* don't cache any zero length files
  533.                   */
  534. #ifdef XP_OS2
  535.                 XP_LazyFileRemove(obj->filename, fileType);
  536. #else
  537.                 XP_FileRemove(obj->filename, fileType);
  538. #endif
  539.                 return FALSE;
  540.               }
  541.  
  542.             if(obj->content_length <= 0)
  543.               {
  544.                 /* fill this in for consistancy */
  545.                   obj->real_content_length = stat_entry.st_size;
  546.                   obj->content_length = stat_entry.st_size;
  547.               }
  548.             else if(accept_partial_files
  549.                     && obj->content_length > (uint32) stat_entry.st_size)
  550.               {
  551.                   obj->real_content_length = obj->content_length;
  552.                 obj->content_length = (uint32) stat_entry.st_size;
  553.                 obj->incomplete_file = TRUE;
  554.               }
  555.                else
  556.               {
  557.                 /* stat the file to verify the content_length 
  558.                  * if the content_length is positive and does not
  559.                  * match the size of the cache file, handle it somehow
  560.                  */
  561.                 if(obj->content_length != (uint32) stat_entry.st_size)
  562.                    {
  563.                     /* this is a case of a server or network
  564.                      * error.  Assume that the file is corrupted,
  565.                      * Display it as it was for history navigation
  566.                      * but do a complete reload any time the server
  567.                      * is contacted
  568.                      * kill the last modified date to disable IMS 
  569.                      */
  570.                       obj->last_modified = 0;
  571.                     if(URL_s)
  572.                         URL_s->last_modified = 0;
  573.                     TRACEMSG(("\n\n!!!!!!!! Content length of cache file not equal"
  574.                           "          To the content transfer length: %d - %d  !!!!!!!\n",
  575.                           obj->content_length, stat_entry.st_size));
  576.                     }
  577.     
  578.                 /* fill this in for consistancy */
  579.                   
  580.                   obj->real_content_length 
  581.                             = obj->content_length 
  582.                                         = stat_entry.st_size;
  583.               }
  584.  
  585.             /* must be set now */
  586.             XP_ASSERT(obj->content_length);
  587.             
  588.           }
  589.         else        
  590.           {
  591.             /* delete the file since we wont remember it
  592.              */
  593. #ifdef XP_OS2
  594.             XP_LazyFileRemove(obj->filename, fileType);
  595. #else
  596.             XP_FileRemove(obj->filename, fileType);
  597. #endif
  598.             return FALSE;
  599.           }
  600.  
  601.         /* refresh these entries in case meta changes them */
  602.         if(URL_s)
  603.           {
  604.             obj->expires = URL_s->expires;
  605.             obj->last_modified = URL_s->last_modified;
  606.             StrAllocCopy(obj->charset, URL_s->charset);
  607.           }
  608.       }
  609.     else if(store_type == REFRESH_CACHE_STORE)
  610.       {
  611.         /* OK */
  612.       }
  613.     else
  614.       {
  615.         XP_ASSERT(0);
  616.       }
  617.  
  618.     /* update the last accessed time
  619.      */
  620.     obj->last_accessed = time(NULL);  /* current time */
  621.  
  622.     /* these must be true or else the partial cache logic is screwed */
  623.     XP_ASSERT(obj->content_length == obj->real_content_length
  624.               || obj->incomplete_file);
  625.  
  626.     /* create key */
  627.     key = net_GenCacheDBKey(obj->address, obj->post_data, obj->post_data_size);
  628.  
  629.     /* create new dbt data object */
  630.     data = net_CacheStructToDBData(obj);
  631.  
  632.     if(!key || !data)
  633.       {
  634.         TRACEMSG(("Failed to get key or data: malloc error probably"));
  635.         /* delete the file since we wont remember it
  636.          */
  637. #ifdef XP_OS2
  638.         XP_LazyFileRemove(obj->filename, fileType);
  639. #else
  640.         XP_FileRemove(obj->filename, fileType);
  641. #endif
  642.         return FALSE;
  643.       }
  644.  
  645.     if(store_type == NEW_CACHE_STORE)
  646.         status = (*local_cache_database->put)(local_cache_database, 
  647.                                         key, 
  648.                                         data, 
  649.                                         R_NOOVERWRITE);
  650.     else /* overwrite by default */
  651.         status = (*local_cache_database->put)(local_cache_database, key, data, 0);
  652.  
  653.     if(status > 0)
  654.       {
  655.         DBT old_data;
  656.  
  657.         TRACEMSG(("Duplicate cache object found"));
  658.  
  659.         /* get the duplicate out of the database */
  660.         status = (*local_cache_database->get)(local_cache_database, key, &old_data, 0);
  661.  
  662.         /* we should always get a success here 
  663.          * or at least a DB error.
  664.          */
  665.         assert(status < 1);
  666.         
  667.         if(status == 0)
  668.           {
  669.             /* found it */
  670.  
  671.                /* delete the previous object from the database
  672.              */
  673.                /* remove the old file */
  674.             char * filename = net_GetFilenameInCacheDBT((DBT *)&old_data);
  675.             if(filename)
  676.               {
  677. #ifdef XP_OS2
  678.                 XP_LazyFileRemove(filename, fileType);
  679. #else
  680.                 XP_FileRemove(filename, fileType);
  681. #endif
  682.                 FREE(filename);
  683.                  }
  684.  
  685.             /* larubbio file size checks for SARCache */
  686.             if ( SARCache )
  687.             {
  688.                 /* subtract the size of the file being removed */
  689.                 URL_s->SARCache->DiskCacheSize -= net_calc_real_file_size(
  690.                                                 net_GetInt32InCacheDBT(&old_data,
  691.                                                     CONTENT_LENGTH_BYTE_POSITION));
  692.                 URL_s->SARCache->NumberInDiskCache--;
  693.             }
  694.             else
  695.             {
  696.                 /* subtract the size of the file being removed */
  697.                 net_DiskCacheSize -= net_calc_real_file_size(
  698.                                                 net_GetInt32InCacheDBT(&old_data,
  699.                                                     CONTENT_LENGTH_BYTE_POSITION));
  700.                 net_NumberInDiskCache--;
  701.             }
  702.     
  703.             /* put the new data in over the old data */
  704.             status = (*local_cache_database->put)(local_cache_database, key, data, 0);
  705.              }
  706.       }
  707.  
  708.  
  709.     if(status < 0)
  710.       {
  711.         char * filename = net_GetFilenameInCacheDBT((DBT *)&data);
  712.  
  713.            TRACEMSG(("cache update failed due to database error"));
  714.  
  715.         /* remove the old file */
  716.         if(filename)
  717.             {
  718. #ifdef XP_OS2
  719.             XP_LazyFileRemove(filename, fileType);
  720. #else
  721.                XP_FileRemove(filename, fileType);
  722. #endif
  723.                FREE(filename);
  724.             }
  725.  
  726.         if ( !SARCache ) {
  727.             /* close the database */
  728.             (*local_cache_database->close)(local_cache_database);
  729.  
  730.             cache_database = 0;
  731.         }
  732.         else
  733.             CACHE_CloseCache(URL_s->SARCache);
  734.  
  735.         local_cache_database = 0;
  736.       }
  737.  
  738.     if ( !SARCache )
  739.     {
  740.         /* add the size of the new file 
  741.          * size_on_disk can be in error, use content_length
  742.          * when missized
  743.          */
  744.         net_DiskCacheSize += net_calc_real_file_size(obj->content_length);
  745.         net_NumberInDiskCache++;
  746.  
  747.         if (++cache_sync_count >= CACHE_SYNC_RATE) 
  748.         {
  749.         
  750.             /* sync the database everytime to guarentee
  751.              * consistancy
  752.              */
  753.             if(local_cache_database && -1 == (*local_cache_database->sync)(local_cache_database, 0))
  754.               {
  755.                 TRACEMSG(("Error syncing cache database"));
  756.  
  757.                 /* close the database */
  758.                 (*local_cache_database->close)(local_cache_database);
  759.                 cache_database = 0;
  760.                 local_cache_database = 0;
  761.               }
  762.  
  763.             cache_sync_count = 0;
  764.  
  765.         }
  766.     }
  767.     else
  768.     {
  769.         /* larubbio */
  770.         /* add the size of the new file 
  771.          * size_on_disk can be in error, use content_length
  772.          * when missized
  773.          */
  774.         URL_s->SARCache->DiskCacheSize += net_calc_real_file_size(obj->content_length);
  775.         URL_s->SARCache->NumberInDiskCache++;
  776.  
  777.         if(URL_s->SARCache->DiskCacheSize > URL_s->SARCache->MaxSize && -1 != URL_s->SARCache->MaxSize )
  778.         {
  779.             TRACEMSG(("MaxSize exceeded!!!"));
  780.             /* delete the file since we wont remember it
  781.              */
  782.             XP_FileRemove(obj->filename, fileType);
  783.  
  784.             URL_s->SARCache->DiskCacheSize -= net_calc_real_file_size(obj->content_length);
  785.             URL_s->SARCache->NumberInDiskCache--;
  786.  
  787.             return FALSE;
  788.         }
  789.  
  790.         /* sync the database every time to guarentee
  791.          * consistancy
  792.          */
  793.         if(local_cache_database && -1 == (*local_cache_database->sync)(local_cache_database, 0))
  794.           {
  795.             TRACEMSG(("Error syncing cache database"));
  796.  
  797.             /* close the database */
  798.             (*local_cache_database->close)(local_cache_database);
  799.             CACHE_CloseCache(URL_s->SARCache);
  800.             local_cache_database = 0;
  801.           }
  802.         else
  803.         {
  804.             /* This is inefficent to do each time, but it keeps us in synch, and this is for 
  805.                offline browsing, which is not a performance intensive task */
  806.             CACHE_SaveCacheInfoToDB(URL_s->SARCache);
  807.         }
  808.     }
  809.  
  810.     net_FreeCacheDBTdata(key);
  811.     net_FreeCacheDBTdata(data);
  812.  
  813.     return TRUE;
  814.  
  815. }
  816.  
  817. /* Public accesor function for Netcaster */
  818. PUBLIC Bool
  819. NET_CacheStore(net_CacheObject * obj,  
  820.                URL_Struct      * URL_s, 
  821.                Bool                 accept_partial_files)
  822. {
  823.     return net_CacheStore(obj, URL_s, accept_partial_files, NEW_CACHE_STORE);
  824. }
  825.  
  826. /* Accessor functions for cache database used by cache browser */
  827. PUBLIC int
  828. NET_FirstCacheObject(DBT *key, DBT *data)
  829. {
  830.     return (*cache_database->seq)(cache_database, key, data, R_FIRST);
  831. }
  832.  
  833. /* Accessor functions for cache database used by cache browser */
  834. PUBLIC int
  835. NET_NextCacheObject(DBT *key, DBT *data)
  836. {
  837.     return (*cache_database->seq)(cache_database, key, data, R_NEXT);
  838. }
  839.  
  840. /* Accessor functions for cache database used by cache browser */
  841. PUBLIC int32
  842. NET_GetMaxDiskCacheSize()
  843. {
  844.     return net_MaxDiskCacheSize;
  845. }
  846.  
  847. /****************************************************************
  848.  * General cache routines needed by lots of stuff
  849.  */
  850.  
  851. typedef struct _DatePlusDBT {
  852.     DBT    * dbt;
  853.     time_t   date;
  854. } DatePlusDBT;
  855.  
  856. /* removes the specified number of objects from the
  857.  * cache taking care to remove only the oldest objects.
  858.  */
  859. PUBLIC int32
  860. NET_RemoveDiskCacheObjects(uint32 remove_num)
  861. {
  862. #define CORRUPT_ENTRY_ARRAY_SIZE 50
  863.     uint32 corrupt_entry_count = 0;
  864.     DatePlusDBT *old_array;
  865.     DBT *corrupt_entry_array[CORRUPT_ENTRY_ARRAY_SIZE];
  866.     uint32 total_cl=0;
  867.     uint32 total_number=0;
  868.     time_t date, lock_date, last_modified_date;
  869.     uint32 i,j;
  870.     char *filename;
  871.     char *url_address;
  872.     DBT data;
  873.     DBT key;
  874.  
  875.     /*
  876.      * This optimization is not valid for the case of URLs that normally
  877.      * would not be cached because their size exceeds the cache size, but
  878.      * will be cached anyway because the must_cache flag of the URL is set.
  879.      * For these URLs, the condition below would be true (since we're
  880.      * trying to remove as many files as possible to make room for the
  881.      * too-big file), which would cause all files to be removed but also
  882.      * the cache database to be closed and deleted.  With the database
  883.      * gone, net_CacheStore will fail, so even though the large file was
  884.      * saved correctly it won't be used.  (See bug #11327.)
  885.      */
  886. #if 0
  887.     if(remove_num >= net_NumberInDiskCache)
  888.       {
  889.         net_RemoveAllDiskCacheObjects();
  890.         return(net_DiskCacheSize);
  891.       }
  892. #endif
  893.  
  894.     if(!cache_database)
  895.         return(net_DiskCacheSize);
  896.  
  897.     old_array = (DatePlusDBT *)XP_ALLOC(sizeof(DatePlusDBT) * remove_num);
  898.     
  899.     if(!old_array)
  900.         return(net_DiskCacheSize);
  901.  
  902.     XP_MEMSET(old_array, 0, sizeof(DatePlusDBT) * remove_num);
  903.  
  904.     /* We need to delete the oldest items in the database.
  905.      * Sequentailly go throught the DB and remove
  906.      * the oldest items
  907.      */
  908.     
  909.     if(0 != (*cache_database->seq)(cache_database, &key, &data, R_FIRST))
  910.         return(net_DiskCacheSize);
  911.     total_cl += net_calc_real_file_size(net_GetInt32InCacheDBT(&data, 
  912.                                                 CONTENT_LENGTH_BYTE_POSITION));
  913.     total_number++;
  914.  
  915.     /* Only add the first item to the old_array if the number to remove
  916.        is greater than zero, otherwise we're writing where we shouldn't be */
  917.     if(remove_num > 0)
  918.     {
  919.         old_array[0].dbt  = net_CacheDBTDup(&key);
  920.         old_array[0].date = net_GetTimeInCacheDBT(&data, 
  921.                                                   LAST_ACCESSED_BYTE_POSITION);
  922.     }
  923.  
  924.     while(0 == (*cache_database->seq)(cache_database, &key, &data, R_NEXT))
  925.       {
  926.         date = net_GetTimeInCacheDBT(&data, LAST_ACCESSED_BYTE_POSITION);
  927.  
  928.         if(date)
  929.             last_modified_date = net_GetTimeInCacheDBT(&data,
  930.                                                  LAST_MODIFIED_BYTE_POSITION);
  931.  
  932.         /* there are other items beside FAT entries in here
  933.          * but they don't have a date
  934.          */
  935.         if(!date)
  936.           {
  937.             /* this could be a corrupt entry */
  938.             if(!net_IsValidCacheDBT(&data))
  939.               {
  940.                  if((key.size < 4 || XP_STRNCMP((char*)key.data, 
  941.                                                 INTERNAL_NAME_PREFIX, 
  942.                                                 4))
  943.                     && corrupt_entry_count < CORRUPT_ENTRY_ARRAY_SIZE)
  944.                   {
  945.     
  946.                     /* store invalid cache entries in an array
  947.                      * for later deletion
  948.                      */
  949.                     corrupt_entry_array[corrupt_entry_count++] = 
  950.                                                             net_CacheDBTDup(&key);
  951.                     TRACEMSG(("Found %d corrupted cache entries",     
  952.                               corrupt_entry_count));
  953.                   }
  954.                   
  955.               }
  956.           }
  957.         else
  958.           {
  959.             url_address = net_GetAddressFromCacheKey(&key);
  960.  
  961.             if(!last_modified_date 
  962.                || (url_address && strncasecomp(url_address, "http",4)))
  963.               {
  964.                 /* this is not a http URL or it has no last modified date.
  965.                  * Delete it preferentially
  966.                  * if it's older than the current session
  967.                  */
  968.                 if(NET_StartupTime > date)
  969.                   {
  970.                     /* set the date really low so it automatically 
  971.                      * gets deleted
  972.                      */
  973.                     date = 1;
  974.                   }
  975.               }
  976.  
  977.             total_cl += net_calc_real_file_size(net_GetInt32InCacheDBT(&data, 
  978.                                                CONTENT_LENGTH_BYTE_POSITION));
  979.             total_number++;
  980.  
  981.             lock_date = net_GetTimeInCacheDBT(&data, LOCK_DATE_BYTE_POSITION);    
  982.  
  983.             /* honor locks issued during this session */
  984.             TRACEMSG(("cache: comparing lock date %ld to startup time %ld\n",
  985.                       lock_date, NET_StartupTime));
  986.             if(lock_date > NET_StartupTime)
  987.                 continue;
  988.             else if(lock_date)
  989.                 net_SetTimeInCacheDBT(&data, 
  990.                                           LOCK_DATE_BYTE_POSITION, 
  991.                                           0); /* current time */
  992.  
  993.             for(i=0; i < remove_num; i++)
  994.               {
  995.                 if(date < old_array[i].date || !old_array[i].date)
  996.                   {
  997.                     /* free the oldest one so it 
  998.                      * doesn't get lost as it is pushed off
  999.                      * the stack
  1000.                      */
  1001.                     if(old_array[remove_num-1].dbt)
  1002.                         net_FreeCacheDBTdata(old_array[remove_num-1].dbt);
  1003.     
  1004.                     /* shift all the entries down */
  1005.                     for(j=remove_num-1; j > i; j--)
  1006.                       {
  1007.                         old_array[j].dbt = old_array[j-1].dbt;
  1008.                         old_array[j].date = old_array[j-1].date;
  1009.                       }
  1010.     
  1011.                     old_array[i].date = date;
  1012.                     old_array[i].dbt = net_CacheDBTDup(&key);
  1013.                     
  1014.                     break;
  1015.                   }
  1016.                 }
  1017.           }
  1018.       }
  1019.  
  1020. #ifdef XP_UNIX
  1021.     /* assert(total_cl == net_DiskCacheSize); */
  1022. #endif 
  1023.     net_DiskCacheSize = total_cl;
  1024.  
  1025. #ifdef XP_UNIX
  1026.     /* assert(total_number == net_NumberInDiskCache); */
  1027. #endif 
  1028.     net_NumberInDiskCache = total_number;
  1029.  
  1030.     /* now old1 old2 and old3 should contain the oldest
  1031.      * keys in the database.  Delete them all.
  1032.      */
  1033.     for(i=0; i < remove_num; i++)
  1034.       {
  1035.         DBT *db_obj = old_array[i].dbt;
  1036.  
  1037.         if(db_obj)
  1038.             {
  1039.             if(0 == (*cache_database->get)(cache_database, db_obj, &data, 0))
  1040.                {
  1041.                   lock_date = net_GetTimeInCacheDBT(&data, LOCK_DATE_BYTE_POSITION);    
  1042.  
  1043.                   /* honor locks issued during this session */
  1044.                   TRACEMSG(("cache: comparing (2) lock date %ld to startup time %ld\n",
  1045.                             lock_date, NET_StartupTime));
  1046.                   if(lock_date > NET_StartupTime)
  1047.                   {
  1048.                       TRACEMSG(("cache: saved your ass again, bud!"));
  1049.                       continue;
  1050.                   }
  1051.  
  1052.                 filename = net_GetFilenameInCacheDBT(&data);
  1053.                 if(filename)
  1054.                       {
  1055.                     TRACEMSG(("Removing file: %s due to disk"
  1056.                                 " cache size overflow",filename));
  1057. #ifdef XP_OS2
  1058.                     XP_LazyFileRemove(filename, xpCache);
  1059. #else
  1060.                     XP_FileRemove(filename, xpCache);
  1061. #endif
  1062.                     FREE(filename);    
  1063.                       }
  1064.                 net_DiskCacheSize -= net_calc_real_file_size(
  1065.                                             net_GetInt32InCacheDBT(&data, 
  1066.                                              CONTENT_LENGTH_BYTE_POSITION)); 
  1067.                 net_NumberInDiskCache--;
  1068.                 (*cache_database->del)(cache_database, db_obj, 0);
  1069.               }
  1070.  
  1071.             net_FreeCacheDBTdata(db_obj);
  1072.           }
  1073.       }
  1074.  
  1075.     /* remove any invalid cache intries
  1076.      */
  1077.     for(i=0; i < corrupt_entry_count; i++)
  1078.       {
  1079.         DBT *newkey = corrupt_entry_array[i];
  1080.         if(newkey && -1 == (*cache_database->del)(cache_database, newkey, 0))
  1081.           {
  1082.             TRACEMSG(("Ack, error trying to delete corrupt entry, aborting",i));
  1083.             break;
  1084.           }
  1085.  
  1086.         TRACEMSG(("Deleting %d corrupted cache entries",i));
  1087.         net_FreeCacheDBTdata(newkey);
  1088.       } 
  1089.  
  1090.     /* don't need the stale array any more */
  1091.     XP_FREE(old_array);
  1092.  
  1093.     /* sync the database
  1094.      */
  1095.     net_StoreDiskCacheSize();
  1096.  
  1097.     if(-1 == (*cache_database->sync)(cache_database, 0))
  1098.       {
  1099.         TRACEMSG(("Error syncing cache database"));
  1100.  
  1101.         /* close the database */
  1102.         (*cache_database->close)(cache_database);
  1103.         cache_database = 0;
  1104.       }
  1105.           
  1106.     return(net_DiskCacheSize);
  1107. }
  1108.  
  1109. PRIVATE void
  1110. net_ReduceDiskCacheTo(MWContext *window_id, uint32 size, int recurse_count)
  1111. {
  1112.     uint32 avg, reduce, remove_num;
  1113.  
  1114.     if(net_DiskCacheSize < size 
  1115.         || !net_NumberInDiskCache
  1116.           || recurse_count >= 5)
  1117.         return;
  1118.  
  1119.     TRACEMSG(("net_ReduceDiskCacheTo: Current size: %d  "
  1120.               "Desired Size: %d  Number: %d", 
  1121.               net_DiskCacheSize,
  1122.               size,
  1123.               net_NumberInDiskCache));
  1124.  
  1125.     /* compute the avarage size of the
  1126.      * contents of the disk cache
  1127.      */
  1128.     if(net_NumberInDiskCache < 1)
  1129.         avg = 0;
  1130.     else
  1131.         avg = net_DiskCacheSize/net_NumberInDiskCache;
  1132.  
  1133.     /* compute the amount that we need to shrink
  1134.      * the disk cache
  1135.      */
  1136.     reduce = net_DiskCacheSize - size;
  1137.  
  1138.     /* add 10% of the total disk cache size
  1139.      * to the reduce number to reduce
  1140.      * the number of times that we need to
  1141.      * do this operation
  1142.      */
  1143.     reduce += net_DiskCacheSize/10;
  1144.  
  1145.     /* compute the number of objects to remove
  1146.      */
  1147.     if(avg < 1)
  1148.         remove_num = 1;
  1149.     else
  1150.         remove_num = reduce/avg;
  1151.  
  1152.     if(remove_num < 1)
  1153.         remove_num = 1;
  1154.  
  1155.     if(window_id)
  1156.       {
  1157.         char buffer[256];
  1158.         XP_SPRINTF(buffer, XP_GetString( XP_CACHE_CLEANUP ), remove_num);
  1159.         NET_Progress(window_id, buffer);
  1160.       }
  1161.  
  1162.     NET_RemoveDiskCacheObjects(remove_num);
  1163.  
  1164.     /* make sure we removed enough
  1165.      */
  1166.     if(net_DiskCacheSize > size)
  1167.         net_ReduceDiskCacheTo(window_id, size, ++recurse_count);
  1168.  
  1169.     return;
  1170. }
  1171.  
  1172. #ifdef NO_MEMORY_CACHE
  1173.  
  1174. /* set the size of the Memory cache.
  1175.  * Set it to 0 if you want cacheing turned off
  1176.  * completely
  1177.  */
  1178. PUBLIC void
  1179. NET_SetMemoryCacheSize(int32 new_size)
  1180. {
  1181.     
  1182.     net_MaxMemoryCacheSize=new_size;
  1183.     IL_ReduceImageCacheSizeTo(new_size);
  1184.     return;
  1185. }
  1186.  
  1187. PUBLIC int32
  1188. NET_GetMaxMemoryCacheSize()
  1189. {
  1190.     return net_MaxMemoryCacheSize;
  1191. }
  1192.  
  1193. /* remove the last memory cache object if one exists
  1194.  * returns the total size of the memory cache in bytes
  1195.  * after performing the operation
  1196.  */
  1197. PUBLIC int32
  1198. NET_RemoveLastMemoryCacheObject()
  1199. {
  1200.     /* and remove something from the image cache */
  1201.     return IL_ShrinkCache();
  1202.  
  1203.     /* XXX now the mac arithmetic is wrong */
  1204.     return(0);
  1205. }
  1206.  
  1207. /* returns the number of bytes currently in use by the Memory cache
  1208.  */
  1209. PUBLIC int32
  1210. NET_GetMemoryCacheSize()
  1211. {
  1212.     return(0);
  1213. }
  1214.  
  1215. /* stub functions for memory cache that are no
  1216.  * longer needed
  1217.  */
  1218. MODULE_PRIVATE int
  1219. NET_MemoryCacheLoad (ActiveEntry * cur_entry)
  1220. {
  1221.     return(-1);
  1222. }
  1223.  
  1224. MODULE_PRIVATE int
  1225. NET_ProcessMemoryCache (ActiveEntry * cur_entry)
  1226. {
  1227.     return(-1);
  1228. }
  1229.  
  1230. MODULE_PRIVATE int
  1231. NET_InterruptMemoryCache (ActiveEntry * cur_entry)
  1232. {
  1233.     return(-1);
  1234. }
  1235.  
  1236. #endif /* MEMORY_CACHE */
  1237.  
  1238. /* set the size of the Disk cache.
  1239.  * Set it to 0 if you want cacheing turned off
  1240.  * completely
  1241.  */
  1242. PUBLIC void
  1243. NET_SetDiskCacheSize(int32 new_size)
  1244. {
  1245.     if(new_size < 0)
  1246.         new_size = 0;
  1247.  
  1248.     net_MaxDiskCacheSize = new_size;
  1249.  
  1250.     /* open it if it's not open already */
  1251.     if(net_MaxDiskCacheSize > 0)
  1252.       {
  1253.         net_OpenCacheFatDB();
  1254.         net_ReduceDiskCacheTo(NULL, (uint32) new_size, 0);
  1255.       }
  1256.     else
  1257.       {
  1258.         net_RemoveAllDiskCacheObjects();
  1259.       }
  1260.  
  1261.  
  1262.     return;
  1263. }
  1264.  
  1265. /* remove the last disk cache object if one exists
  1266.  * returns the total size of the disk cache in bytes
  1267.  * after performing the operation
  1268.  */
  1269. PUBLIC int32
  1270. NET_RemoveLastDiskCacheObject(void)
  1271. {
  1272.     return(net_DiskCacheSize);
  1273. }
  1274.  
  1275. PRIVATE void
  1276. net_RemoveAllDiskCacheObjects(void)
  1277. {
  1278.     char * filename;
  1279.     DBT data;
  1280.     DBT key;
  1281.  
  1282.     if(!cache_database)
  1283.         return;
  1284.  
  1285.     if(0 != (*cache_database->seq)(cache_database, &key, &data, R_FIRST))
  1286.         return;
  1287.  
  1288.     do
  1289.       {
  1290.         filename = net_GetFilenameInCacheDBT(&data);     
  1291.         if(filename)                                      
  1292.           {                                                
  1293.             TRACEMSG(("Removing file: %s due to disk"       
  1294.                       " cache size remove",filename));     
  1295. #ifdef XP_OS2
  1296.         XP_LazyFileRemove(filename, xpCache);
  1297. #else
  1298.             XP_FileRemove(filename, xpCache);                 
  1299. #endif
  1300.             FREE(filename);                                    
  1301.           }                                                     
  1302.         /* We don't acctually need to do the
  1303.          * del since we will del the database
  1304.          */
  1305.         /* (*cache_database->del)(cache_database, &key, 0); */
  1306.       }
  1307.     while(0 == (*cache_database->seq)(cache_database, &key, &data, R_NEXT));
  1308.  
  1309.     net_DiskCacheSize = 0;
  1310.     net_NumberInDiskCache = 0;
  1311.  
  1312.     if(-1 == (*cache_database->close)(cache_database))
  1313.       {
  1314.         TRACEMSG(("Error closing cache database"));
  1315.       }
  1316.  
  1317.     cache_database = 0;
  1318.  
  1319.     /* remove the database */
  1320.     XP_FileRemove("", xpCacheFAT);
  1321. }
  1322.  
  1323. /* returns the number of bytes currently in use by the Disk cache
  1324.  */
  1325. PUBLIC int32
  1326. NET_GetDiskCacheSize()
  1327. {
  1328.     return(net_DiskCacheSize);
  1329. }
  1330.  
  1331.  
  1332. /******************************************************************
  1333.  * Cache Stream input routines
  1334.  */
  1335.  
  1336. /* is the stream ready for writing?
  1337.  */
  1338. PRIVATE unsigned int net_CacheWriteReady (NET_StreamClass *stream)
  1339. {
  1340.    CacheDataObject *obj=stream->data_object;   
  1341.    if(obj->next_stream)
  1342.        return((*obj->next_stream->is_write_ready)(obj->next_stream));
  1343.    else
  1344.        return(MAX_WRITE_READY);
  1345. }
  1346.  
  1347. /*  stream write function
  1348.  */
  1349. PRIVATE int net_CacheWrite (NET_StreamClass *stream, CONST char* buffer, int32 len)
  1350. {
  1351.     CacheDataObject *obj=stream->data_object;    
  1352.     TRACEMSG(("net_CacheWrite called with %ld buffer size", len));
  1353.  
  1354.     if(obj->fp)
  1355.       {
  1356.         /* increase the global cache size counter
  1357.          */
  1358.         if(XP_FileWrite((char *) buffer, len, obj->fp) < (uint32)len)
  1359.           {
  1360.             TRACEMSG(("Error writing to cache file"));
  1361.             XP_FileClose(obj->fp);
  1362. #ifdef XP_OS2
  1363.             XP_LazyFileRemove(obj->cache_object->filename, xpCache);
  1364. #else
  1365.             XP_FileRemove(obj->cache_object->filename, xpCache);
  1366. #endif
  1367.             if(obj->URL_s)
  1368.                 obj->URL_s->dont_cache = TRUE;
  1369.             obj->fp = 0;
  1370.           }
  1371.             
  1372.       }
  1373.  
  1374.     if(obj->next_stream)
  1375.       {
  1376.         int status=0;
  1377.     
  1378.         assert (buffer);
  1379.         assert (len > -1);
  1380.         status = (*obj->next_stream->put_block)
  1381.                                 (obj->next_stream, buffer, len);
  1382.  
  1383.         /* abort */
  1384.         if(status < 0)
  1385.             return(status);
  1386.       }
  1387.  
  1388.     return(1);
  1389. }
  1390.  
  1391. /*  complete the stream
  1392. */
  1393. PRIVATE void net_CacheComplete (NET_StreamClass *stream)
  1394. {
  1395.     CacheDataObject *obj=stream->data_object;    
  1396.     /* close the cache file 
  1397.      */
  1398.     if(obj->fp)
  1399.         XP_FileClose(obj->fp);
  1400.  
  1401.     assert(obj->cache_object);
  1402.  
  1403.     /* add it to the database */
  1404.     if(net_CacheStore(obj->cache_object, 
  1405.                       obj->URL_s, 
  1406.                       FALSE, 
  1407.                       NEW_CACHE_STORE))
  1408.       {
  1409.         /* set the cache_file in the url struct so that Plugins can
  1410.           * use it...
  1411.          */    
  1412.         if(obj->URL_s)
  1413.             StrAllocCopy(obj->URL_s->cache_file, obj->cache_object->filename);
  1414.       }
  1415.  
  1416.     /* complete the next stream
  1417.      */
  1418.     if(obj->next_stream)
  1419.       {
  1420.         (*obj->next_stream->complete)(obj->next_stream);
  1421.         FREE(obj->next_stream);
  1422.       }
  1423.  
  1424.     net_freeCacheObj(obj->cache_object);
  1425.     PR_REMOVE_LINK(&obj->links);
  1426.     FREE(obj);
  1427.  
  1428.     return;
  1429. }
  1430.  
  1431. /* Abort the stream 
  1432.  * 
  1433.  */
  1434. PRIVATE void net_CacheAbort (NET_StreamClass *stream, int status)
  1435. {
  1436.  
  1437.     CacheDataObject *obj=stream->data_object;    
  1438.     XP_ASSERT(obj);
  1439.     XP_ASSERT(obj->cache_object);
  1440.  
  1441.     /* abort the next stream
  1442.      */
  1443.     if(obj->next_stream)
  1444.       {
  1445.         (*obj->next_stream->abort)(obj->next_stream, status);
  1446.         FREE(obj->next_stream);
  1447.       }
  1448.  
  1449.     /* fp might be null if we had a file write error */
  1450.     if(obj->fp)
  1451.       {
  1452.         XP_FileClose(obj->fp);
  1453.  
  1454.         /* do this test in here since the file must be
  1455.          * alright for us to use this
  1456.          *
  1457.          * test to see if we were user interrupted and if
  1458.          * the server support byteranges.  If so, store
  1459.          * the partial object since we will request it
  1460.          * with a partial byterange later
  1461.          *
  1462.          * Also, we can't do partial caching unless we know
  1463.          * the content_length
  1464.          */
  1465.         if(obj->URL_s
  1466.              && obj->URL_s->content_length
  1467.               && (obj->URL_s->server_can_do_byteranges || obj->URL_s->server_can_do_restart)
  1468.                 && !obj->URL_s->dont_cache)  
  1469.           {
  1470.  
  1471.             /* store the partial file */
  1472.             if(obj->URL_s->real_content_length > 0)
  1473.                 obj->cache_object->content_length = obj->URL_s->real_content_length;
  1474.             net_CacheStore(obj->cache_object, 
  1475.                            obj->URL_s, 
  1476.                            TRUE, 
  1477.                            NEW_CACHE_STORE);
  1478.  
  1479.           }
  1480.         else if(status == MK_INTERRUPTED 
  1481.                 && obj->URL_s->content_length
  1482.                 && !strcasecomp(obj->URL_s->content_type, TEXT_HTML))
  1483.           {
  1484.             /* temporarly cache interrupted HTML pages for history navigation */
  1485.             obj->URL_s->last_modified = 0;
  1486.             net_CacheStore(obj->cache_object, 
  1487.                            obj->URL_s, 
  1488.                            FALSE, 
  1489.                            NEW_CACHE_STORE);
  1490.             
  1491.           }
  1492.         else
  1493.            {
  1494. #ifdef XP_OS2
  1495.             XP_LazyFileRemove(obj->cache_object->filename, xpCache);
  1496. #else
  1497.             XP_FileRemove(obj->cache_object->filename, xpCache);
  1498. #endif
  1499.            }
  1500.       }
  1501.  
  1502.     net_freeCacheObj(obj->cache_object);
  1503.     PR_REMOVE_LINK(&obj->links);
  1504.     FREE(obj);
  1505.  
  1506.     return;
  1507. }
  1508.  
  1509.  
  1510. #ifdef XP_UNIX
  1511. extern char **fe_encoding_extensions; /* gag! */
  1512. #endif
  1513.  
  1514. /* setup the stream
  1515.  */
  1516. MODULE_PRIVATE NET_StreamClass * 
  1517. NET_CacheConverter (FO_Present_Types format_out,
  1518.                     void       *converter_obj,
  1519.                     URL_Struct *URL_s,
  1520.                     MWContext  *window_id)
  1521. {
  1522.     CacheDataObject * data_object=0;
  1523.     net_CacheObject * cache_object=0;
  1524.     NET_StreamClass * stream=0;
  1525.     char *filename=0, *new_filename=0;
  1526.     char *org_content_type = 0;
  1527.     Bool do_disk_cache=FALSE;
  1528.     Bool want_to_cache=FALSE;
  1529.     XP_File fp=0;
  1530.     NET_StreamClass * next_stream=0;
  1531.  
  1532.     /* XXX brendan will #define this hack after 3.0 ships! */
  1533.     XP_Bool dont_hold_URL_s = (converter_obj != NULL);
  1534.     
  1535.     TRACEMSG(("Setting up cache stream. Have URL: %s\n", URL_s->address));
  1536.  
  1537.     FE_EnableClicking(window_id);
  1538.  
  1539. #ifdef MOZILLA_CLIENT
  1540.     /* add this new url to the Global history since we must be getting it now
  1541.      */
  1542.     if (NET_URL_Type(URL_s->address) != WYSIWYG_TYPE_URL && URL_s->SARCache == NULL)
  1543.         GH_UpdateGlobalHistory(URL_s);
  1544. #endif /* MOZILLA_CLIENT */ 
  1545.  
  1546.     StrAllocCopy(org_content_type, URL_s->content_type);
  1547.     if(!org_content_type)
  1548.         return(NULL);
  1549.  
  1550.     if(format_out != FO_CACHE_ONLY)
  1551.       {
  1552.         format_out = CLEAR_CACHE_BIT(format_out);
  1553.         next_stream = NET_StreamBuilder(format_out, URL_s, window_id);
  1554.         if(!next_stream)
  1555.              {
  1556.             FREEIF(org_content_type);
  1557.             return(NULL);
  1558.            }
  1559.       }
  1560.  
  1561.     /* set the content type back the way it should be
  1562.      * this is because some streams muck with it and
  1563.      * dont set it back and we need it intact
  1564.      */
  1565.     FREE(URL_s->content_type);
  1566.     URL_s->content_type = org_content_type;
  1567.     org_content_type = 0;
  1568.  
  1569.     /* do we want to cache this object?
  1570.      */
  1571.     if(URL_s->server_can_do_restart) URL_s->must_cache = TRUE;
  1572.  
  1573.  
  1574.     TRACEMSG(("cache: URL_s->must_cache is %s", URL_s->must_cache ? "TRUE" : "FALSE"));
  1575.  
  1576.     if(URL_s->must_cache    /* overrides all the rest of these tests */
  1577.        ||  (CLEAR_CACHE_BIT(format_out) == FO_INTERNAL_IMAGE 
  1578.             || format_out == FO_CACHE_ONLY
  1579.             || !strncasecomp(URL_s->content_type, "IMAGE", 5)
  1580.             || !strncasecomp(URL_s->content_type, "TEXT", 4)
  1581.             || !strncasecomp(URL_s->content_type, "MESSAGE", 7)
  1582.             || !strcasecomp(URL_s->content_type, APPLICATION_HTTP_INDEX)
  1583.             || !strcasecomp(URL_s->content_type, APPLICATION_JAVAARCHIVE)
  1584.             || ( (URL_s->content_length>0) && ((uint32) URL_s->content_length < (net_MaxDiskCacheSize/4)) )
  1585.            )
  1586.        )
  1587.       {
  1588.         /* set a flag to say that we want to cache */
  1589.         want_to_cache = TRUE;
  1590.       }
  1591.         
  1592.     /* set a flag if we should disk cache it based
  1593.       * on whether the cache setting is non-zero and
  1594.      * the cache database is open
  1595.      */
  1596.  
  1597.     TRACEMSG(("cache: want_to_cache is %s", want_to_cache ? "TRUE" : "FALSE"));
  1598.  
  1599.     if(want_to_cache 
  1600.        && (!net_dont_disk_cache_ssl 
  1601.             || strncasecomp(URL_s->address, "https:", 6))
  1602.        && !URL_s->dont_cache
  1603.        && (net_MaxDiskCacheSize > 0 || URL_s->must_cache)
  1604.        && net_OpenCacheFatDB() /* make sure database is open */
  1605.          && strncasecomp(URL_s->address, "news:", 5)   /* not news: */
  1606.        && strncasecomp(URL_s->address, "snews:", 6)  /* not snews: */
  1607.        && strncasecomp(URL_s->address, "mailbox://", 10))  /* not IMAP */
  1608.         do_disk_cache = TRUE;
  1609.  
  1610.     /* Special case for StreamAsFile plugins:  */
  1611.     if (URL_s->must_cache   /* this only set by plugin code ? */
  1612.         && ((XP_STRNCASECMP(URL_s->address, "news:", 5)==0)      /* is news */
  1613.         ||  (XP_STRNCASECMP(URL_s->address, "https:", 6)==0)     /* is secure */
  1614.         || !strncasecomp(URL_s->address, "mailbox://", 10))) /* is imap */
  1615.         do_disk_cache = TRUE;
  1616.  
  1617.     /* malloc and init all the necessary structs
  1618.      * do_disk_cache will be set false on error
  1619.      */
  1620.     if(do_disk_cache)
  1621.       {
  1622.  
  1623.         TRACEMSG(("Object has not been cached before"));
  1624.             
  1625.         cache_object = XP_NEW(net_CacheObject);
  1626.         if (!cache_object)
  1627.           {
  1628.             return(NULL);
  1629.           }
  1630.     
  1631.         /* assign and init the cache object */
  1632.         XP_MEMSET(cache_object, 0, sizeof(net_CacheObject));
  1633.     
  1634.         /* copy the contents of the URL structure
  1635.          */
  1636.         StrAllocCopy(cache_object->address, URL_s->address);
  1637.         cache_object->method = URL_s->method;
  1638.         if(URL_s->post_data)
  1639.           {
  1640.             cache_object->post_data_size = URL_s->post_data_size;
  1641.             StrAllocCopy(cache_object->post_data, URL_s->post_data);
  1642.             StrAllocCopy(cache_object->post_headers, URL_s->post_headers);
  1643.           }
  1644.     
  1645.         /* add expiration stuff from URL structure
  1646.          */
  1647.         cache_object->expires        = URL_s->expires;
  1648.         cache_object->last_modified  = URL_s->last_modified;
  1649.     
  1650.         cache_object->content_length      = URL_s->content_length;
  1651.         cache_object->real_content_length = URL_s->content_length;
  1652.         cache_object->is_netsite     = URL_s->is_netsite;
  1653.  
  1654.         StrAllocCopy(cache_object->content_type, URL_s->content_type);
  1655.         StrAllocCopy(cache_object->charset, URL_s->charset);
  1656.         StrAllocCopy(cache_object->content_encoding, URL_s->content_encoding);
  1657.  
  1658.         /* copy security info */
  1659.         cache_object->security_on             = URL_s->security_on;
  1660.         StrAllocCopy(cache_object->key_cipher,  URL_s->key_cipher);
  1661.         cache_object->key_size                = URL_s->key_size;
  1662.         cache_object->key_secret_size         = URL_s->key_secret_size;
  1663.  
  1664.         StrAllocCopy(cache_object->page_services_url, URL_s->page_services_url);
  1665.  
  1666.         /* we always use relative paths in the main disk cache
  1667.          */
  1668.         cache_object->is_relative_path        = TRUE;
  1669.  
  1670.         if (URL_s->certificate)
  1671.             cache_object->certificate =
  1672.             CERT_DupCertificate(URL_s->certificate);
  1673.  
  1674.  
  1675.         /* open a file for the cache
  1676.            larubbio added SARCache check it's late in 4.0 cycle, and I don't want to have
  1677.            any impact on the other platforms
  1678.  
  1679.          */
  1680.           filename = WH_TempName(
  1681. #ifdef XP_UNIX 
  1682.              (NULL != URL_s->SARCache) ? xpSARCache :
  1683. #endif
  1684.              xpCache, "cache");
  1685.         
  1686.         if (filename)  
  1687.           {
  1688.             /* Put an appropriate suffix on the tmp cache file */
  1689.             if (cache_object->address)
  1690.               {
  1691.                 
  1692.                 char *tail;
  1693.                 char *suffix;
  1694.                 char *allocSuffix; /* in case we have to allocate a suffix */
  1695.                 char *end;
  1696.                 char *junk;
  1697.                 char old_char;
  1698.  
  1699.                 suffix = allocSuffix = NULL;
  1700.  
  1701.                 if (URL_s->content_name){
  1702.                     suffix = (URL_s->content_name ? XP_STRRCHR (URL_s->content_name, '.') : 0);
  1703.                 }
  1704.                 else if ((URL_s->address) && 
  1705.                         (!XP_STRNCASECMP(URL_s->address, "mailbox:", 8)
  1706.                         || !XP_STRNCASECMP(URL_s->address, "news:", 5)
  1707.                         || !XP_STRNCASECMP(URL_s->address, "snews:", 6))
  1708.                          && (URL_s->content_type) && (*(URL_s->content_type)))
  1709.                 {
  1710.                     /*
  1711.                         Gag. If we're a mailbox URL and can't figure out the content name,
  1712.                         but have a content type, ask the type registry for a suitable suffix. 
  1713.                         (This allows us to set up Java and audio cache files so that those
  1714.                         subsystems will actually work with the cache files. Ick.)
  1715.                     */
  1716.                     char *regSuffix = NET_cinfo_find_ext(URL_s->content_type);
  1717.                     if (regSuffix)
  1718.                     {
  1719.                         suffix = PR_smprintf(".%s", regSuffix);
  1720.                         allocSuffix = suffix; /* we allocated it here, we delete it below */
  1721.                     }
  1722.                 }
  1723.                 
  1724.                 if (!suffix)
  1725.                 {
  1726.                     tail = XP_STRRCHR (cache_object->address, '/');
  1727.                     suffix = (tail ? XP_STRRCHR (tail, '.') : 0);
  1728.                 }
  1729.                 end = suffix + (suffix ? XP_STRLEN (suffix) : 0);
  1730.                 junk=0;                
  1731.             
  1732. #ifdef XP_UNIX
  1733.                 /* Gag.  foo.html.gz --> cacheXXXXX.html, not cacheXXXXX.gz. */
  1734.                 if (suffix && fe_encoding_extensions)
  1735.                   {
  1736.                     int i = 0;
  1737.                     while (fe_encoding_extensions [i])
  1738.                       {
  1739.                         if (!XP_STRCMP (suffix, fe_encoding_extensions [i]))
  1740.                           {
  1741.                             end = suffix;
  1742.                             suffix--;
  1743.                             while (suffix > tail && *suffix != '.')
  1744.                               suffix--;
  1745.                             if (*suffix != '.')
  1746.                               suffix = 0;
  1747.                             break;
  1748.                           }
  1749.                         i++;
  1750.                       }
  1751.                   }
  1752. #endif
  1753.  
  1754.                 /* Avoid "cache2F1F6AD102169F0.sources&maxhits=10" */
  1755.                 if (suffix)
  1756.                   {
  1757.                     junk = suffix + 1;
  1758.                     while (isalnum (*junk))
  1759.                       junk++;
  1760.                     old_char = *junk;
  1761.                     *junk = 0;
  1762.                   }
  1763.  
  1764.  
  1765. #if defined(XP_WIN) || defined(XP_OS2)               /* IBM - SAH */
  1766.                 /* Remove any suffix that the temp filename currently has
  1767.                  */
  1768.                 XP_STRTOK(filename, ".");
  1769. #endif
  1770.  
  1771.                 if (suffix && (end - suffix) < 20)
  1772.                   {
  1773.                     /* make sure it is terminated... */
  1774.                     if(!junk)
  1775.                       {
  1776.                         junk = end;
  1777.                         old_char = *junk;
  1778.                         *junk = 0;
  1779.                       }
  1780.                     StrAllocCopy(new_filename, filename);
  1781. #if defined(XP_WIN) || defined(XP_OS2)               /* IBM - SAH  - even though */
  1782.                                                      /*              the comment */
  1783.                                                      /*              say 16 bit  */
  1784.                                                      /*              32 bit Win  */
  1785.                                                      /*              goes thru   */
  1786.                                                      /*              here, so do */
  1787.                                                      /*              the same for*/
  1788.                                                      /*              OS2         */
  1789.                     /* make all suffixes be UPPERCASE for win16
  1790.                      * since the operating system will make 
  1791.                      * them so and we need to know the exact
  1792.                      * name for hashing and comparison purposes
  1793.                      */
  1794.                     if(1)
  1795.                       {
  1796.                         char *new_suffix = XP_STRDUP(suffix);
  1797.                         if(new_suffix)
  1798.                           {
  1799.                             char *cp = new_suffix;
  1800.                             int i;
  1801.                             /* limit it to 4 chars.
  1802.                              * a dot and three letters
  1803.                              */
  1804.                             for(i=0; *cp && i < 4; i++)
  1805.                               {
  1806.                                 *cp = XP_TO_UPPER(*cp);
  1807.                                 cp++;
  1808.                               }
  1809.                             *cp = '\0'; /* make sure it's terminated */
  1810.                             StrAllocCat(new_filename, new_suffix);
  1811.                             XP_FREE(new_suffix);
  1812.                           }
  1813.                       }
  1814. #else
  1815.                     StrAllocCat(new_filename, suffix);
  1816. #endif
  1817.                   }
  1818.                 else 
  1819.                   {
  1820.                     StrAllocCopy(new_filename, filename);
  1821.                   }
  1822.  
  1823.  
  1824.                 if(junk)
  1825.                     *junk = old_char;
  1826.  
  1827.                 if (allocSuffix)
  1828.                     XP_FREE(allocSuffix);
  1829.               }
  1830.             XP_FREE(filename);
  1831.           }
  1832.  
  1833.         if(new_filename)
  1834.         {
  1835.             /* larubbio added 197 SAR cache checks */
  1836.             if ( URL_s->SARCache == NULL )
  1837.                    fp = XP_FileOpen(new_filename, xpCache, XP_FILE_WRITE_BIN);
  1838.             else
  1839.                    fp = XP_FileOpen(new_filename, xpSARCache, XP_FILE_WRITE_BIN);
  1840.         }
  1841.    
  1842.         if(!fp)
  1843.           {
  1844.             net_freeCacheObj(cache_object);
  1845.             cache_object = 0;
  1846.             do_disk_cache = FALSE;
  1847.             FREEIF(new_filename);
  1848.           }
  1849.         else
  1850.           {
  1851.             cache_object->filename = new_filename;
  1852.  
  1853.             /* cap the total size of the cache
  1854.              */
  1855.  
  1856.             /* larubbio disk cache size checks for SARCache 
  1857.              * Also, don't reduce the cache size yet for "must_cache"
  1858.              * objects, since in the download-restart case the object
  1859.              * will be deleted most of the time before it ever gets
  1860.              * counted in the cache.  Objects that do get put into
  1861.              * the cache will self correct at the next call to
  1862.              * ReduceDiskCacheTo()
  1863.              */
  1864.             if(net_DiskCacheSize+URL_s->content_length > net_MaxDiskCacheSize 
  1865.                 && URL_s->SARCache == NULL
  1866.                 && !URL_s->must_cache)
  1867.               {
  1868.                 int32 new_size = net_MaxDiskCacheSize - URL_s->content_length;
  1869.                 if(new_size < 0)
  1870.                     new_size = 0;
  1871.                 net_ReduceDiskCacheTo(window_id, (uint32)new_size, 0);
  1872.               }
  1873.           }
  1874.       }
  1875.  
  1876.     /* if we get this far and do_disk_cache is true
  1877.      * then we want cache and all the setup succeeded.
  1878.      */
  1879.     if(do_disk_cache)
  1880.       {
  1881.         TRACEMSG(("Caching this URL!!!!"));
  1882.  
  1883.         data_object = XP_NEW(CacheDataObject);
  1884.         if (!data_object)
  1885.           {
  1886.             XP_FileClose(fp);
  1887.             return(NULL);
  1888.           }
  1889.  
  1890.         stream = XP_NEW(NET_StreamClass);
  1891.         if(!stream)
  1892.           {
  1893.             XP_FileClose(fp);
  1894.             FREE(data_object);
  1895.             return(NULL);
  1896.           }
  1897.  
  1898.         /* init the object */
  1899.         XP_MEMSET(data_object, 0, sizeof(CacheDataObject));
  1900.     
  1901.         /* assign the cache object to the stream data object
  1902.          */
  1903.         data_object->cache_object = cache_object;
  1904.  
  1905.         /* save the URL struct since we will
  1906.           * need to use some data from it later
  1907.          * XXX if converter_obj is non-null it is a flag telling us not
  1908.          * XXX to hold a pointer to the URL struct.
  1909.          */
  1910.         if (dont_hold_URL_s == FALSE)
  1911.             data_object->URL_s = URL_s;
  1912.         data_object->fp = fp;
  1913.  
  1914.         TRACEMSG(("Returning stream from NET_CacheConverter\n"));
  1915.  
  1916.         stream->name           = "Cache stream";
  1917.         stream->complete       = (MKStreamCompleteFunc) net_CacheComplete;
  1918.         stream->abort          = (MKStreamAbortFunc) net_CacheAbort;
  1919.         stream->put_block      = (MKStreamWriteFunc) net_CacheWrite;
  1920.         stream->is_write_ready = (MKStreamWriteReadyFunc) net_CacheWriteReady;
  1921.         stream->data_object    = data_object;  /* document info object */
  1922.         stream->window_id      = window_id;
  1923.  
  1924.         if(format_out != FO_CACHE_ONLY)
  1925.             data_object->next_stream = next_stream;
  1926.  
  1927.         PR_APPEND_LINK(&data_object->links, &active_cache_data_objects);
  1928.         return stream;
  1929.       }
  1930.     else
  1931.       {
  1932.  
  1933.         TRACEMSG(("NOT Disk Caching this URL"));
  1934.  
  1935.         if(want_to_cache)
  1936.           {
  1937.             net_MemCacheConverterObject mem_conv_obj;
  1938.  
  1939.             mem_conv_obj.next_stream = next_stream;
  1940.             mem_conv_obj.dont_hold_URL_s = dont_hold_URL_s;
  1941.             return(NET_MemCacheConverter(format_out, 
  1942.                                          &mem_conv_obj,
  1943.                                          URL_s, 
  1944.                                          window_id));
  1945.           }
  1946.  
  1947.         /* bypass the whole cache mechanism
  1948.           */
  1949.         if(format_out != FO_CACHE_ONLY)
  1950.           {
  1951.               format_out = CLEAR_CACHE_BIT(format_out);
  1952.  
  1953.             return(next_stream);
  1954.           }
  1955.  
  1956.       }
  1957.  
  1958.     return(NULL);
  1959.  
  1960. }
  1961.  
  1962. /***************************************************************************
  1963.  *   Cache object manipulation stuff
  1964.  */
  1965.  
  1966. /* locks or unlocks a cache file.  The 
  1967.  * cache lock is only good for a single
  1968.  * session
  1969.  */
  1970. PUBLIC Bool
  1971. NET_ChangeCacheFileLock(URL_Struct *URL_s, Bool set)
  1972. {
  1973.     int   status;
  1974.     DBT   data;
  1975.     DBT * key;
  1976.     DBT * new_data=0;
  1977.     net_CacheObject *found_cache_obj;
  1978.  
  1979.     /* lock or unlock the memory cache too */
  1980.     NET_ChangeMemCacheLock(URL_s, set);
  1981.  
  1982.     if(!cache_database)
  1983.         return(FALSE);
  1984.  
  1985.     key = net_GenCacheDBKey(URL_s->address,
  1986.                             URL_s->post_data,
  1987.                             URL_s->post_data_size);
  1988.  
  1989.     status = (*cache_database->get)(cache_database, key, &data, 0);
  1990.  
  1991.     if(status != 0)
  1992.       {
  1993.         TRACEMSG(("Key not found in database"));
  1994.         net_FreeCacheDBTdata(key);
  1995.         return(FALSE);
  1996.       }
  1997.  
  1998.     found_cache_obj = net_Fast_DBDataToCacheStruct(&data);
  1999.  
  2000.     if(!found_cache_obj)
  2001.       {
  2002.         TRACEMSG(("mkcache: Corrupted db entry"));
  2003.         return(FALSE);
  2004.       }
  2005.  
  2006.     if(set)
  2007.         found_cache_obj->lock_date = time(NULL);
  2008.     else
  2009.         found_cache_obj->lock_date = 0;
  2010.  
  2011.     /* create new dbt data object */
  2012.     new_data = net_CacheStructToDBData(found_cache_obj);
  2013.  
  2014.     if(new_data)
  2015.         status = (*cache_database->put)(cache_database, key, new_data, 0);
  2016.  
  2017.     return(status == 0);
  2018. }
  2019.  
  2020. MODULE_PRIVATE void NET_RefreshCacheFileExpiration(URL_Struct * URL_s)
  2021. {
  2022.     net_CacheObject *found_cache_obj;
  2023.     int  status;
  2024.     DBT *key;
  2025.     DBT  data;
  2026.  
  2027.     if(!cache_database)
  2028.       {
  2029.         TRACEMSG(("Cache database not open"));
  2030.         return;
  2031.       }
  2032.  
  2033.     /* only update if the server status is 304 
  2034.      * The other cases involve a new cache object
  2035.      * and all the info will automatically get updated
  2036.      */
  2037.     if(URL_s->server_status != 304)
  2038.           return;
  2039.  
  2040.     /* gen a key */
  2041.     key = net_GenCacheDBKey(URL_s->address,
  2042.                             URL_s->post_data,
  2043.                             URL_s->post_data_size);
  2044.  
  2045.     /* look up the key */
  2046.     status = (*cache_database->get)(cache_database, key, &data, 0);
  2047.  
  2048.     /* don't need the key anymore */
  2049.     net_FreeCacheDBTdata(key);
  2050.  
  2051.     if(status != 0)
  2052.         return;
  2053.  
  2054.     /* turn the cache DB object into a cache object */
  2055.     found_cache_obj = net_Fast_DBDataToCacheStruct(&data);
  2056.  
  2057.     if(!found_cache_obj)
  2058.         return;
  2059.  
  2060.     /* stick the address and post data in there
  2061.      * since this stuff is ususally in the Key
  2062.      */
  2063.     StrAllocCopy(found_cache_obj->address, URL_s->address);
  2064.     if(URL_s->post_data_size)
  2065.       {
  2066.         found_cache_obj->post_data_size = URL_s->post_data_size;
  2067.         BlockAllocCopy(found_cache_obj->post_data,
  2068.                        URL_s->post_data,
  2069.                        URL_s->post_data_size);
  2070.       }
  2071.  
  2072.     /* this will update the last modified time */
  2073.     net_CacheStore(found_cache_obj, 
  2074.                     NULL, 
  2075.                     FALSE, 
  2076.                     REFRESH_CACHE_STORE);
  2077.  
  2078.     return;
  2079.  
  2080. #if 0
  2081.     /* this is the really old version of RefreshURL */
  2082.  
  2083.     /* this isn't really needed because we can do it all
  2084.      * in the Complete step by keeping a copy if the URL struct.
  2085.      */
  2086.     int   status;
  2087.     DBT   data;
  2088.     DBT * key;
  2089.     DBT * new_data=0;
  2090.  
  2091.     if(!cache_database)
  2092.         return;
  2093.  
  2094.     key = net_GenCacheDBKey(URL_s->address,
  2095.                             URL_s->post_data,
  2096.                             URL_s->post_data_size);
  2097.  
  2098.     status = (*cache_database->get)(cache_database, key, &data, 0);
  2099.  
  2100.     if(status != 0)
  2101.       {
  2102.         TRACEMSG(("Key not found in database"));
  2103.         net_FreeCacheDBTdata(key);
  2104.         return;
  2105.       }
  2106.  
  2107.     new_data = net_CacheDBTDup(&data);
  2108.  
  2109.     if(!new_data)
  2110.       {
  2111.         net_FreeCacheDBTdata(key);
  2112.         return;
  2113.       }
  2114.  
  2115.     net_SetTimeInCacheDBT(new_data, 
  2116.                           EXPIRES_BYTE_POSITION, 
  2117.                           URL_s->expires);
  2118.     net_SetTimeInCacheDBT(new_data, 
  2119.                           LAST_MODIFIED_BYTE_POSITION, 
  2120.                           URL_s->last_modified);
  2121.     net_SetTimeInCacheDBT(new_data, 
  2122.                           LAST_ACCESSED_BYTE_POSITION, 
  2123.                           time(NULL)); /* current time */
  2124.  
  2125.     TRACEMSG(("Refreshing the cache expires date: %d  last_mod: %d\n",
  2126.                                     URL_s->expires, URL_s->last_modified));
  2127.  
  2128.     
  2129.     status = (*cache_database->put)(cache_database, key, new_data, 0);
  2130.  
  2131. #ifdef DEBUG
  2132.     if(status != 0)
  2133.         TRACEMSG(("Error updateing cache info in database"));
  2134. #endif /* DEBUG */
  2135.  
  2136.     net_FreeCacheDBTdata(key);
  2137.  
  2138.     net_FreeCacheDBTdata(new_data);
  2139.  
  2140.     return;
  2141. #endif
  2142. }
  2143.  
  2144. /* returns TRUE if the url is in the disk cache
  2145.  */
  2146. PUBLIC Bool
  2147. NET_IsURLInDiskCache(URL_Struct *URL_s)
  2148. {
  2149.     DBT *key;
  2150.     DBT data;
  2151.     int status;
  2152.  
  2153.     if(!cache_database)
  2154.       {
  2155.         TRACEMSG(("Cache database not open"));
  2156.          return(0); 
  2157.       }
  2158.  
  2159.     key = net_GenCacheDBKey(URL_s->address, 
  2160.                             URL_s->post_data, 
  2161.                             URL_s->post_data_size);
  2162.  
  2163.     status = (*cache_database->get)(cache_database, key, &data, 0);
  2164.  
  2165.     net_FreeCacheDBTdata(key);
  2166.     
  2167.     if(status == 0)
  2168.         return(TRUE);
  2169.     else
  2170.         return(FALSE);
  2171. }
  2172.  
  2173. /* remove a URL from the cache
  2174.  */
  2175. MODULE_PRIVATE void
  2176. NET_RemoveURLFromCache(URL_Struct *URL_s)
  2177. {
  2178.  
  2179.     int status;
  2180.     DBT data;
  2181.     DBT *key;
  2182.  
  2183.     /* larubbio */
  2184.     Bool        SARCache = FALSE;
  2185.     XP_FileType fileType;
  2186.     DB            *local_cache_database = NULL;
  2187.  
  2188.     /* larubbio fix to allow 197 SAR cache adds without modifying 
  2189.      * the navigator cache (too much)
  2190.      */
  2191.     if ( URL_s != NULL && URL_s->SARCache != NULL )
  2192.     {
  2193.         SARCache = TRUE;
  2194.         fileType = xpSARCache;
  2195.         local_cache_database = URL_s->SARCache->database;
  2196.     }
  2197.     else
  2198.     {
  2199.         fileType = xpCache;
  2200.         local_cache_database = cache_database;
  2201.     }
  2202.  
  2203.  
  2204.     NET_RemoveURLFromMemCache(URL_s);
  2205.  
  2206.     if(!local_cache_database)
  2207.         return;
  2208.  
  2209.     key = net_GenCacheDBKey(URL_s->address, 
  2210.                                 URL_s->post_data, 
  2211.                                 URL_s->post_data_size);
  2212.  
  2213.     if(!key)
  2214.         return;
  2215.  
  2216.     status = (*local_cache_database->get)(local_cache_database, key, &data, 0);
  2217.  
  2218.     if(status == 0)
  2219.        {
  2220.         char * filename = net_GetFilenameInCacheDBT(&data);
  2221.  
  2222.         if(filename)
  2223.           {
  2224. #ifdef XP_OS2
  2225.             XP_LazyFileRemove(filename, fileType);
  2226. #else
  2227.             XP_FileRemove(filename, fileType);
  2228. #endif
  2229.             FREE(filename);
  2230.           }
  2231.  
  2232.         (*local_cache_database->del)(local_cache_database, key, 0);
  2233.  
  2234.         if ( SARCache )
  2235.         {
  2236.             /* subtract the size of the file being removed */
  2237.             URL_s->SARCache->DiskCacheSize -= net_calc_real_file_size(
  2238.                                                 net_GetInt32InCacheDBT(&data,
  2239.                                                 CONTENT_LENGTH_BYTE_POSITION));
  2240.             URL_s->SARCache->NumberInDiskCache--;
  2241.         }
  2242.         else
  2243.         {
  2244.             net_DiskCacheSize -= net_calc_real_file_size(
  2245.                                                 net_GetInt32InCacheDBT(&data,
  2246.                                                 CONTENT_LENGTH_BYTE_POSITION));
  2247.             net_NumberInDiskCache--;
  2248.         }
  2249.       }
  2250.  
  2251.     net_FreeCacheDBTdata(key);
  2252. }
  2253.  
  2254. /* return TRUE if the URL is in the cache and
  2255.  * is a partial cache file
  2256.  */
  2257. MODULE_PRIVATE Bool
  2258. NET_IsPartialCacheFile(URL_Struct *URL_s)
  2259. {
  2260.     net_CacheObject *found_cache_obj;
  2261.     int  status;
  2262.     DBT *key;
  2263.     DBT  data;
  2264.  
  2265.     if(!cache_database)
  2266.       {
  2267.         TRACEMSG(("Cache database not open"));
  2268.         return(0);
  2269.       }
  2270.  
  2271.     key = net_GenCacheDBKey(URL_s->address, 
  2272.                             URL_s->post_data, 
  2273.                             URL_s->post_data_size);
  2274.  
  2275.     status = (*cache_database->get)(cache_database, key, &data, 0);
  2276.  
  2277.     net_FreeCacheDBTdata(key);
  2278.  
  2279.     if(status != 0)
  2280.         return(0);
  2281.         
  2282.     found_cache_obj = net_Fast_DBDataToCacheStruct(&data);
  2283.  
  2284.     if(found_cache_obj)
  2285.         return(found_cache_obj->incomplete_file);
  2286.     else
  2287.         return(0);
  2288. }
  2289.  
  2290. PUBLIC int
  2291. NET_FindURLInCache(URL_Struct * URL_s, MWContext *ctxt)
  2292. {
  2293.     net_CacheObject *found_cache_obj;
  2294.     XP_StatStruct    stat_entry;
  2295.     int   status;
  2296.     char *byterange;
  2297.     char  byterange_char;
  2298.     DBT  *key;
  2299.     DBT   data;
  2300.     TRACEMSG(("Checking for URL in cache"));
  2301.  
  2302.     /* zero the last modified date so that we don't
  2303.      * screw up the If-modified-since header by
  2304.      * having it in even when the document isn't
  2305.      * cached.
  2306.      */
  2307.     URL_s->last_modified = 0;
  2308.  
  2309.     if(!cache_database)
  2310.       {
  2311.         TRACEMSG(("Cache database not open"));
  2312.  
  2313.         /* can't find it here.  Let's look
  2314.          * in the memory and external caches
  2315.          */
  2316.         status = NET_FindURLInMemCache(URL_s, ctxt);
  2317.     
  2318.         if(status)
  2319.             return(status);
  2320.         else
  2321.             return(NET_FindURLInExtCache(URL_s, ctxt));
  2322.       }
  2323.  
  2324.     byterange = strcasestr(URL_s->address, ";bytes=");
  2325.     
  2326.     /* this might be a cached imap url.  Ignore the mime
  2327.        part when going back for attachments, otherwise we'll
  2328.        reload the attachment from the server */
  2329.     if (!byterange)
  2330.         byterange = strcasestr(URL_s->address, "&part=");
  2331.  
  2332.     if(byterange)
  2333.       {
  2334.         byterange_char = *byterange;
  2335.         *byterange = '\0';
  2336.       }
  2337.  
  2338.     key = net_GenCacheDBKey(URL_s->address, 
  2339.                             URL_s->post_data, 
  2340.                             URL_s->post_data_size);
  2341.     
  2342.  
  2343.     if(byterange)
  2344.         *byterange = byterange_char;
  2345.  
  2346.     status = (*cache_database->get)(cache_database, key, &data, 0);
  2347.  
  2348.  
  2349.     /* try it again with the byterange stuff
  2350.      */
  2351.     if(status != 0 && byterange)
  2352.       {
  2353.         net_FreeCacheDBTdata(key);
  2354.         key = net_GenCacheDBKey(URL_s->address, 
  2355.                                 URL_s->post_data, 
  2356.                                 URL_s->post_data_size);
  2357.         status = (*cache_database->get)(cache_database, key, &data, 0);
  2358.       }
  2359.  
  2360.     /* If the file doesn't have an extension try adding
  2361.      * a slash to the end and look for it again.
  2362.      * this will catch the most common redirect cases
  2363.       */
  2364.     if(status != 0)
  2365.       {
  2366.         char *slash;
  2367.  
  2368.         slash = XP_STRRCHR(URL_s->address, '/');
  2369.         if(slash && !XP_STRCHR(slash, '.') && *(slash+1) != '\0')
  2370.           {
  2371.             /* no extension.  Add the slash and
  2372.              * look for it in the database
  2373.              */
  2374.             StrAllocCat(URL_s->address, "/");
  2375.             net_FreeCacheDBTdata(key);
  2376.             key = net_GenCacheDBKey(URL_s->address, 
  2377.                                     URL_s->post_data, 
  2378.                                     URL_s->post_data_size);
  2379.             status = (*cache_database->get)(cache_database, key, &data, 0);
  2380.  
  2381.             if(status != 0)
  2382.               {
  2383.                 /* adding the slash didn't work, get rid of it 
  2384.                   */
  2385.                 URL_s->address[XP_STRLEN(URL_s->address)-1] = '\0';
  2386.               }
  2387.           }
  2388.       }
  2389.  
  2390.     /* If the java Cache api is requesting this file, and it was found in the
  2391.      * navigator cache, remove it from that cache so it can be recached in the proper archive cache
  2392.      */
  2393.     if( (0 == status) && (NULL != URL_s->SARCache) )
  2394.       {
  2395.         found_cache_obj = net_Fast_DBDataToCacheStruct(&data);
  2396.  
  2397.         if(!found_cache_obj)
  2398.         {
  2399.             TRACEMSG(("mkcache: Corrupted db entry"));
  2400.             return(0);
  2401.         }
  2402.  
  2403.         /* remove the object from the cache
  2404.          */
  2405.         XP_FileRemove(found_cache_obj->filename, xpCache);
  2406.  
  2407.         if(cache_database)
  2408.             status = (*cache_database->del)(cache_database, key, 0);
  2409.  
  2410.         /* remove the size of that file from the running total */
  2411.         net_DiskCacheSize -= net_calc_real_file_size(
  2412.                                             found_cache_obj->content_length);
  2413.  
  2414.         status = -1;
  2415.       }
  2416.  
  2417.  
  2418.     if(status != 0)
  2419.       {
  2420.         TRACEMSG(("Key not found in database"));
  2421.         net_FreeCacheDBTdata(key);
  2422.  
  2423.         /* can't find it here.  Let's look
  2424.          * in the memory and external caches
  2425.          */
  2426.         status = NET_FindURLInMemCache(URL_s, ctxt);
  2427.     
  2428.         if(status)
  2429.             return(status);
  2430.         else
  2431.             return(NET_FindURLInExtCache(URL_s, ctxt));
  2432.       }
  2433.  
  2434.     found_cache_obj = net_Fast_DBDataToCacheStruct(&data);
  2435.  
  2436.     if(!found_cache_obj)
  2437.       {
  2438.         TRACEMSG(("mkcache: Corrupted db entry"));
  2439.         return(0);
  2440.       }
  2441.  
  2442.     TRACEMSG(("mkcache: found URL in cache!"));
  2443.  
  2444.     /* pretend we don't have the object cached if we are looking
  2445.      * for a byterange URL and the object is only partially
  2446.      * cached
  2447.      */
  2448.     if(byterange && found_cache_obj->incomplete_file)
  2449.       {
  2450.         return(0);
  2451.       }
  2452.  
  2453.     /* make sure the file still exists
  2454.      */
  2455.     if(XP_Stat(found_cache_obj->filename, &stat_entry, xpCache) == -1)
  2456.       {
  2457.         /* file does not exist!!
  2458.          * remove the entry 
  2459.          */
  2460.         TRACEMSG(("Error! Cache file missing"));
  2461.  
  2462.         if(cache_database)
  2463.             status = (*cache_database->del)(cache_database, key, 0);
  2464.  
  2465.         /* remove the size of that file from the running total */
  2466.         net_DiskCacheSize -= net_calc_real_file_size(
  2467.                                             found_cache_obj->content_length);
  2468.  
  2469. #ifdef DEBUG
  2470.         if(status != 0)
  2471.             TRACEMSG(("Error deleting bad file from cache"));
  2472. #endif /* DEBUG */
  2473.  
  2474.         net_FreeCacheDBTdata(key);
  2475.  
  2476.         return(0);
  2477.             
  2478.       }
  2479.  
  2480.     /*
  2481.      * if the last accessed date is before the startup date set the
  2482.      * expiration date really low so that the URL is forced to be rechecked
  2483.      * again.  We don't just not return the URL as being in the
  2484.      * cache because we want to use "If-modified-since"
  2485.      *
  2486.      * This works correctly because mkhttp will zero the
  2487.      * expires field.
  2488.      *
  2489.      * if it's not an http url then just delete the entry
  2490.      * since we can't do an If-modified-since
  2491.      *
  2492.      * NOTE: use the use_local_copy flag as a signal not to
  2493.       * do the "once per session" check since it is possible
  2494.      * that the cache is read only, also use history_num
  2495.      * since we shouldn't reload on history navigation or resize
  2496.      */
  2497.     if(!URL_s->use_local_copy)
  2498.       {
  2499.         if(found_cache_obj->last_accessed < NET_StartupTime
  2500.             && NET_CacheUseMethod != CU_NEVER_CHECK 
  2501. #ifdef MOZ_OFFLINE          
  2502.             && !NET_IsOffline() 
  2503. #endif /* MOZ_OFFLINE */
  2504.          )                            /* *X* check for is offline */
  2505.           {
  2506.             if(!strncasecomp(URL_s->address, "http", 4))
  2507.               {
  2508.                 URL_s->expires = 1;
  2509.  
  2510. #if 0
  2511.     /* this is ifdeffed because of the following bug:
  2512.      * If you update now, there is still the possibility
  2513.      * of putting this URL on the wait queue.  If that
  2514.      * happens, when the URL gets pulled off the wait queue
  2515.      * it will be called with NET_GetURL again and come
  2516.       * here again.  Since we already updated it wont
  2517.      * get set expired again.  So instead I will update
  2518.      * the URL when I get a 304 in NET_RefreshCacheFileExpiration
  2519.      */
  2520.                 /* stick the address and post data in there
  2521.                  * since this stuff is in the Key
  2522.                  */
  2523.                 StrAllocCopy(found_cache_obj->address, URL_s->address);
  2524.                 if(URL_s->post_data_size)
  2525.                   {
  2526.                     found_cache_obj->post_data_size = URL_s->post_data_size;
  2527.                     BlockAllocCopy(found_cache_obj->post_data,
  2528.                                        URL_s->post_data, 
  2529.                                        URL_s->post_data_size);
  2530.                   }
  2531.                 
  2532.                 /* this will update the last accessed time
  2533.                  */
  2534.                 net_CacheStore(found_cache_obj, 
  2535.                                NULL, 
  2536.                                FALSE, 
  2537.                                REFRESH_CACHE_STORE);
  2538. #endif
  2539.               }
  2540.             else
  2541.               {
  2542.                 /* remove the object from the cache
  2543.                  */
  2544. #ifdef XP_OS2
  2545.                 XP_LazyFileRemove(found_cache_obj->filename, xpCache);
  2546. #else
  2547.                 XP_FileRemove(found_cache_obj->filename, xpCache);
  2548. #endif
  2549.                 /* remove the size of that file from the running total */
  2550.                 net_DiskCacheSize -= net_calc_real_file_size(
  2551.                                             found_cache_obj->content_length);
  2552.     
  2553.                 status = (*cache_database->del)(cache_database, key, 0);
  2554. #ifdef DEBUG
  2555.                 if(status != 0)
  2556.                     TRACEMSG(("Error deleting expired file from cache"));
  2557. #endif /* DEBUG */
  2558.  
  2559.                 net_FreeCacheDBTdata(key);
  2560.  
  2561.                 return(0);
  2562.               }
  2563.           }
  2564.         else
  2565.           {
  2566.             /* otherwise use the normal expires date */
  2567.              URL_s->expires = found_cache_obj->expires;
  2568.           }
  2569.       }
  2570.     else
  2571.       {
  2572.          URL_s->expires = 0; /* prevent looping */
  2573.       }
  2574.  
  2575.     /* we don't need the key anymore */
  2576.     net_FreeCacheDBTdata(key);
  2577.  
  2578.     /* copy in the cache file name
  2579.      */
  2580.     StrAllocCopy(URL_s->cache_file, found_cache_obj->filename);
  2581.  
  2582.     /* copy the contents of the URL struct so that the content type
  2583.      * and other stuff gets recorded
  2584.      */
  2585.     if(!URL_s->preset_content_type)
  2586.         StrAllocCopy(URL_s->content_type,     found_cache_obj->content_type);
  2587.     StrAllocCopy(URL_s->charset,          found_cache_obj->charset);
  2588.     StrAllocCopy(URL_s->content_encoding, found_cache_obj->content_encoding);
  2589.  
  2590.     StrAllocCopy(URL_s->page_services_url, found_cache_obj->page_services_url);
  2591.  
  2592.     /* only set these for HTTP url's
  2593.      * otherwise the content-length will mess up files that don't
  2594.      * return a content-length and are different
  2595.      */
  2596.     if(!strncasecomp(URL_s->address, "http", 4) || !strncasecomp(URL_s->address, "ftp", 3))
  2597.       {
  2598.         URL_s->content_length = found_cache_obj->content_length;
  2599.            URL_s->real_content_length = found_cache_obj->real_content_length;
  2600.  
  2601.         if(URL_s->content_length != URL_s->real_content_length
  2602.            && !found_cache_obj->incomplete_file)
  2603.           {
  2604.             XP_ASSERT(0);  
  2605.  
  2606.             URL_s->real_content_length = 0;
  2607.             URL_s->content_length = 0;
  2608.  
  2609.             /* content type indicates a partial cache file but
  2610.              * the incomplete file flag is not set.  Something
  2611.              * went wrong.
  2612.              */
  2613.             return(0);  /* return not found */
  2614.       }
  2615.       }
  2616.  
  2617.      URL_s->last_modified  = found_cache_obj->last_modified;
  2618.      URL_s->is_netsite     = found_cache_obj->is_netsite;
  2619.  
  2620.     /* copy security info */
  2621.     URL_s->security_on             = found_cache_obj->security_on;
  2622.     URL_s->key_size                = found_cache_obj->key_size;
  2623.     URL_s->key_secret_size         = found_cache_obj->key_secret_size;
  2624.     StrAllocCopy(URL_s->key_cipher,  found_cache_obj->key_cipher);
  2625.  
  2626.     /* free any existing certificate first */
  2627.     CERT_DestroyCertificate(URL_s->certificate);
  2628.     URL_s->certificate = NULL;
  2629.     
  2630.     if (found_cache_obj->certificate)
  2631.           URL_s->certificate =
  2632.             CERT_DupCertificate(found_cache_obj->certificate);
  2633.  
  2634.     TRACEMSG(("Cached copy is valid. returning method"));
  2635.  
  2636.     TRACEMSG(("Using Disk Copy"));
  2637.  
  2638.     return(FILE_CACHE_TYPE_URL);
  2639. }
  2640.  
  2641.  
  2642. /* read the Cache File allocation table.
  2643.  */
  2644. PUBLIC void
  2645. NET_ReadCacheFAT(char * cachefatfile, Bool stat_files)
  2646. {
  2647.     if(net_MaxDiskCacheSize > 0)
  2648.         net_OpenCacheFatDB();
  2649.  
  2650.     return;
  2651. }
  2652.  
  2653. /* unload the disk cache FAT list to disk
  2654.  *
  2655.  * set final_call to true if this is the last call to
  2656.  * this function before cleaning up the cache and shutting down.
  2657.  *
  2658.  * Front ends should never set final_call to TRUE, this will
  2659.  * be done by the cache cleanup code when the netlib is being
  2660.  * shutdown.
  2661.  */
  2662. PUBLIC void
  2663. NET_WriteCacheFAT(char *filename, Bool final_call)
  2664. {
  2665.     net_StoreDiskCacheSize();
  2666.  
  2667.     if(!cache_database)
  2668.         return;
  2669.  
  2670.     if(-1 == (*cache_database->sync)(cache_database, 0))
  2671.       {
  2672.         TRACEMSG(("Error syncing cache database"));
  2673.         /* close the database */
  2674.         (*cache_database->close)(cache_database);
  2675.         cache_database = 0;
  2676.       }
  2677.  
  2678.     return;
  2679. }
  2680.  
  2681. MODULE_PRIVATE void
  2682. NET_CleanupCache (char * filename)
  2683. {
  2684.     net_StoreDiskCacheSize();
  2685.  
  2686.     if(!cache_database)
  2687.         return;
  2688.  
  2689.     if(-1 == (*cache_database->close)(cache_database))
  2690.       {
  2691.         TRACEMSG(("Error closing cache database"));
  2692.       }
  2693.  
  2694.     cache_database = 0;
  2695.  
  2696.     CACHE_CloseAllOpenSARCache();
  2697.  
  2698.     return;
  2699. }
  2700.  
  2701. /* returns the number of files currently in the
  2702.  * disk cache
  2703.  */
  2704. PUBLIC uint32
  2705. NET_NumberOfFilesInDiskCache()
  2706. {
  2707.     return(net_NumberInDiskCache);
  2708. }
  2709.  
  2710. static int
  2711. net_cache_strcmp (const void *a, const void *b)
  2712. {
  2713.   return XP_STRCMP ((const char *) a, (const char *) b);
  2714. }
  2715.  
  2716.  
  2717. /* this function recurses through all directories in
  2718.  * the cache directory and stuffs all the files into
  2719.  * the hash table.  Any directory names below the
  2720.  * root cache directory should have their relative path 
  2721.  * names prepended to them
  2722.  *
  2723.  * returns 0 on success, -1 on failure
  2724.  */
  2725. PRIVATE int
  2726. net_cache_recursive_file_finder(XP_HashList *hash_table, 
  2727.                                 const char *prefix,
  2728.                                 char *cur_dir, 
  2729.                                 char *base_dir,
  2730.                                 char *buffer)
  2731. {
  2732.     XP_Dir dir_ptr;
  2733.        XP_DirEntryStruct * dir_entry;
  2734.     int base_len;
  2735.     int prefix_len, d_len, status;
  2736.     char *dir_prefix=0;
  2737.     char *d_name;
  2738.     Bool add_dir_prefix=TRUE;
  2739.  
  2740.     /* compute the difference between base_dir and
  2741.      * cur_dir.  The difference should be prepended
  2742.      * to the front of filenames
  2743.      */
  2744.     base_len = XP_STRLEN(base_dir);
  2745.     StrAllocCopy(dir_prefix, cur_dir+base_len);
  2746.  
  2747.     if(!dir_prefix)
  2748.         return(-1);
  2749.  
  2750.  
  2751.     if(*dir_prefix == '\0')
  2752.         add_dir_prefix = FALSE;
  2753.     else if(dir_prefix[XP_STRLEN(dir_prefix)-1] == '/')
  2754.         dir_prefix[XP_STRLEN(dir_prefix)-1] = '\0';
  2755.  
  2756.     if(!(dir_ptr = XP_OpenDir (cur_dir, xpCache)))
  2757.     {
  2758.         FREE(dir_prefix);
  2759.         return(-1);
  2760.     }
  2761.  
  2762.     /* add all the files on disk to a hash table
  2763.      */
  2764.     prefix_len = XP_STRLEN(prefix);
  2765.     while((dir_entry = XP_ReadDir(dir_ptr)) != 0)
  2766.       {
  2767.         /* only do comparison and delete if the prefix
  2768.          * is the same
  2769.          */
  2770.         d_name = dir_entry->d_name;
  2771.         d_len = XP_STRLEN(d_name);
  2772.         status = 0;
  2773.         if(XP_STRNCMP(d_name, prefix, prefix_len))
  2774.            {
  2775. #if 0
  2776.             XP_StatStruct stat_entry;
  2777. #endif
  2778.  
  2779.             /* This directory didn't begin with the cache prefix, so it
  2780.                *should* be a directory.  But if it's not, then it's some
  2781.                random junk that somehow got into the cache directory.
  2782.  
  2783.                Rather than stat'ing it first and then recursing, we will
  2784.                simply assume it's a directory, recurse, and call XP_OpenDir
  2785.                on it.  If it's not a directory this will fail, and we will
  2786.                ignore it.
  2787.              */
  2788.  
  2789. #ifdef XP_UNIX
  2790.             /* Unix-specific speed hack: only recursively descend directories
  2791.                if they have names which consist of exactly two hex digits.
  2792.                Because of the behavior of xp_file.c on Unix, anything else is
  2793.                either not a directory, or not a directory which we use.
  2794.              */
  2795.             if (! (d_len == 2 &&
  2796.                    ((d_name[0] >= '0' && d_name[0] <= '9') ||
  2797.                     (d_name[0] >= 'A' && d_name[0] <= 'F')) &&
  2798.                    ((d_name[1] >= '0' && d_name[1] <= '9') ||
  2799.                     (d_name[1] >= 'A' && d_name[1] <= 'F'))))
  2800.               continue;
  2801. #else /* !XP_UNIX */
  2802.             /* This is redundant on Unix because of the above check. */
  2803.             if(!XP_STRCMP(d_name, ".") || !XP_STRCMP(d_name, ".."))
  2804.               {
  2805.                 /* ignore . and .. */
  2806.                 status = -1;
  2807.               }
  2808. #endif /* !XP_UNIX */
  2809.  
  2810.             else if(add_dir_prefix)
  2811.                 {
  2812.                 XP_SPRINTF(buffer, "%.250s/%.250s", dir_prefix, d_name);
  2813.                 }
  2814.  
  2815.             if(status != -1)
  2816.                 {
  2817.                 char *new_dir=0;
  2818.                 StrAllocCopy(new_dir, cur_dir);
  2819.                 if(cur_dir[XP_STRLEN(cur_dir)-1] != '/')
  2820.                     StrAllocCat(new_dir, "/");
  2821.                 StrAllocCat(new_dir, d_name);
  2822.                 net_cache_recursive_file_finder(hash_table, 
  2823.                                                 prefix,
  2824.                                                 new_dir, 
  2825.                                                 base_dir,
  2826.                                                 buffer);
  2827.                 FREE(new_dir);
  2828.                 }
  2829.             continue;
  2830.           }
  2831.  
  2832.         if(add_dir_prefix)
  2833.           {
  2834.             XP_SPRINTF(buffer, "%.250s/%.250s", dir_prefix, d_name);
  2835.             XP_HashListAddObject(hash_table, XP_STRDUP(buffer));
  2836.           }
  2837.         else
  2838.           {
  2839.             XP_HashListAddObject(hash_table, XP_STRDUP(d_name));
  2840.           }
  2841.         
  2842.       }
  2843.  
  2844.     FREE(dir_prefix);
  2845.  
  2846.     XP_CloseDir(dir_ptr);
  2847.     return 0;
  2848. }
  2849. /* cleans up the cache directory by listing every
  2850.  * file and deleting the ones it doesn't know about
  2851.  * that begin with the cacheing prefix
  2852.  */
  2853. PUBLIC int
  2854. NET_CleanupCacheDirectory(char * dir_name, const char * prefix)
  2855. {
  2856. #define REMOVE_LIST_SIZE 1000
  2857.     DBT *remove_list[REMOVE_LIST_SIZE];
  2858.     char *filename, *d_name;
  2859.     XP_HashList *hash_table;
  2860.     DBT key, data;
  2861.     int status;
  2862.     char buffer[512];
  2863.     uint32 num_files;
  2864.     int i;
  2865.     int number_in_remove_list=0;
  2866. #ifdef XP_MAC
  2867.  
  2868.     /* make sure the size of the cache is as we want it
  2869.      */
  2870.     if(net_MaxDiskCacheSize == 0)
  2871.         net_RemoveAllDiskCacheObjects();
  2872.     else
  2873.         net_ReduceDiskCacheTo(NULL, net_MaxDiskCacheSize, 0);
  2874.  
  2875.     if(!dir_name)
  2876.         dir_name = "";
  2877.  
  2878.     /* optimization for cleanup.
  2879.      *
  2880.      * If the number of files on disk is within a couple
  2881.      * of the number of files that we know about then
  2882.      * skip the cache directory cleanup
  2883.      */
  2884.     num_files = XP_FileNumberOfFilesInDirectory(dir_name, xpCache);
  2885.     if(num_files-3 <= net_NumberInDiskCache)
  2886.         return(0);
  2887. #endif 
  2888.  
  2889.     if(!cache_database)
  2890.         return(-1);
  2891.  
  2892.     TRACEMSG(("cleaning up cache directory of unknown cache files"));
  2893.  
  2894.     hash_table = XP_HashListNew(1597, XP_StringHash, net_cache_strcmp);
  2895.  
  2896.     if(!hash_table)
  2897.         return(-1);
  2898.     
  2899.     /* find all the files in the cache directory 
  2900.      */
  2901.     if(net_cache_recursive_file_finder(hash_table, 
  2902.                                        prefix, 
  2903.                                        dir_name, 
  2904.                                        dir_name, 
  2905.                                        buffer))
  2906.         return(-1);
  2907.  
  2908.     /* init the count of all the files in the database */
  2909.     num_files = 0;
  2910.  
  2911.     /* now run through the disk cache FAT and remove
  2912.      * any matches from the hash table
  2913.      */
  2914.     status = (*cache_database->seq)(cache_database, &key, &data, R_FIRST);
  2915.  
  2916.     while(status == 0)
  2917.       {
  2918.         filename = net_GetFilenameInCacheDBT(&data);
  2919.         if(filename)
  2920.           {
  2921.             time_t last_modified_date = net_GetTimeInCacheDBT(&data, 
  2922.                                                 LAST_MODIFIED_BYTE_POSITION);
  2923.  
  2924.             if(!last_modified_date)
  2925.               {
  2926.                 /* if there is no last_modified date then
  2927.                  * it doesn't do us much good to keep the
  2928.                  * data since it can't be compared and used
  2929.                  * in a future session.  Put the file in a remove list
  2930.                  *
  2931.                  * Don't do this if the check mode is NEVER
  2932.                  *
  2933.                  */
  2934.                 if(NET_CacheUseMethod != CU_NEVER_CHECK
  2935.                    && number_in_remove_list < REMOVE_LIST_SIZE)
  2936.                     remove_list[number_in_remove_list++] = 
  2937.                                                         net_CacheDBTDup(&key);
  2938.               }
  2939.             else
  2940.               {
  2941.                 num_files++; /* keep a count of all the files in the database */
  2942.  
  2943.                 d_name = (char*) XP_HashListRemoveObject(hash_table, filename);
  2944.                 if(d_name)
  2945.                     {
  2946.                     FREE(d_name);
  2947.                     }
  2948.               }
  2949.             FREE(filename);
  2950.           }
  2951.         else
  2952.           {
  2953.             /* could not grab the filename from
  2954.              * the DBT.  See if this is a valid
  2955.              * entry
  2956.              */
  2957.             if(!net_IsValidCacheDBT(&data)
  2958.                 && (key.size < 4 || XP_STRNCMP((char*)key.data,
  2959.                                                 INTERNAL_NAME_PREFIX,
  2960.                                                 4))
  2961.                 && number_in_remove_list < REMOVE_LIST_SIZE)
  2962.               {
  2963.                 remove_list[number_in_remove_list++] = net_CacheDBTDup(&key);
  2964.               }
  2965.           }    
  2966.  
  2967.         status = (*cache_database->seq)(cache_database, &key, &data, R_NEXT);
  2968.       }
  2969.  
  2970.     /* any files left in the hash table are not in the
  2971.      * cache FAT, so delete them
  2972.      *
  2973.      * @@@@ Manipulate the hash table directly
  2974.      */
  2975.     {
  2976.         int list_count;
  2977.         XP_List *list_ptr;
  2978.         
  2979.         for(list_count=0; list_count < hash_table->size; list_count++)
  2980.             {
  2981.             list_ptr = hash_table->list[list_count];
  2982.             if(list_ptr)
  2983.                 {
  2984.                 while((filename = 
  2985.                             (char *) XP_ListRemoveTopObject(list_ptr)) != 0)
  2986.                     {
  2987. #ifdef XP_OS2
  2988.                     XP_LazyFileRemove(filename, xpCache);
  2989. #else
  2990.                     XP_FileRemove(filename, xpCache);
  2991. #endif
  2992.                     TRACEMSG(("Unknown cache file %s found! -- deleteing...", 
  2993.                                                         filename));
  2994.                     FREE(filename);
  2995.                     }
  2996.                 XP_ListDestroy(list_ptr);  /* free the list */
  2997.                 }
  2998.             }
  2999.  
  3000.         XP_HashListDestroy(hash_table);
  3001.     }
  3002.  
  3003.     /* remove the entries that are no longer needed or
  3004.      * are corrupt
  3005.      *
  3006.      * Note that we don't need to remove the files since
  3007.      * they will already have been removed from the code
  3008.      * above
  3009.      */
  3010.     TRACEMSG(("Deleting %d unneeded cache entries",number_in_remove_list));
  3011.     for(i=0; i < number_in_remove_list; i++)
  3012.       {
  3013.         DBT *newkey = remove_list[i];
  3014.         if(-1 == (*cache_database->del)(cache_database, newkey, 0))
  3015.           {
  3016.             TRACEMSG(("Ack, error trying to delete corrupt entry, aborting",i));            break;
  3017.           }
  3018.  
  3019.         net_FreeCacheDBTdata(newkey);
  3020.       }
  3021.  
  3022.     /* if the number of files that we counted in the database
  3023.      * does not agree with the number we think it should be
  3024.      * reset the number we think it should be with the actual
  3025.      * number
  3026.      */
  3027.     if(net_NumberInDiskCache != num_files)
  3028.       {
  3029.         TRACEMSG(("Reseting number of files in cache to: %d", num_files));
  3030.         net_NumberInDiskCache = num_files;
  3031.         net_StoreDiskCacheSize();  /* this will store the number of files */
  3032.       }
  3033.     return(0);
  3034. }
  3035.  
  3036. /* removes all cache files from the cache directory
  3037.  * and deletes the cache FAT
  3038.  */
  3039. PUBLIC int
  3040. NET_DestroyCacheDirectory(char * dir_name, char * prefix)
  3041. {
  3042.     net_RemoveAllDiskCacheObjects();
  3043.     NET_CleanupCacheDirectory(dir_name, prefix);
  3044.  
  3045.     (*cache_database->close)(cache_database);
  3046.     cache_database = 0;
  3047.  
  3048.     net_DiskCacheSize=0;
  3049.     net_NumberInDiskCache=0;
  3050.     
  3051.     return XP_FileRemove("", xpCacheFAT);
  3052. }
  3053.  
  3054. /* create an HTML stream and push a bunch of HTML about
  3055.  * the cache
  3056.  */
  3057. MODULE_PRIVATE void 
  3058. NET_DisplayCacheInfoAsHTML(ActiveEntry * cur_entry)
  3059. {
  3060.     char *buffer = (char*)XP_ALLOC(2048);
  3061.     char *address;
  3062.     char *escaped;
  3063.        NET_StreamClass * stream;
  3064.     net_CacheObject * cache_obj;
  3065.     DBT key, data;
  3066.     Bool long_form = FALSE;
  3067.     int i;
  3068.  
  3069.     if(!buffer)
  3070.       {
  3071.         cur_entry->status = MK_UNABLE_TO_CONVERT;
  3072.         return;
  3073.       }
  3074.  
  3075.     if(strcasestr(cur_entry->URL_s->address, "?long"))
  3076.         long_form = TRUE;
  3077.     else if(strcasestr(cur_entry->URL_s->address, "?traceon"))
  3078.         NET_CacheTraceOn = TRUE;
  3079.     else if(strcasestr(cur_entry->URL_s->address, "?traceoff"))
  3080.         NET_CacheTraceOn = FALSE;
  3081.  
  3082.     StrAllocCopy(cur_entry->URL_s->content_type, TEXT_HTML);
  3083.  
  3084.     cur_entry->format_out = CLEAR_CACHE_BIT(cur_entry->format_out);
  3085.     stream = NET_StreamBuilder(cur_entry->format_out, 
  3086.                                cur_entry->URL_s, 
  3087.                                cur_entry->window_id);
  3088.  
  3089.     if(!stream)
  3090.       {
  3091.         cur_entry->status = MK_UNABLE_TO_CONVERT;
  3092.         FREE(buffer);
  3093.         return;
  3094.       }
  3095.  
  3096.  
  3097.     /* define a macro to push a string up the stream
  3098.      * and handle errors
  3099.      */
  3100. #define PUT_PART(part)                                                    \
  3101. cur_entry->status = (*stream->put_block)(stream,            \
  3102.                                         part ? part : "Unknown",        \
  3103.                                         part ? XP_STRLEN(part) : 7);    \
  3104. if(cur_entry->status < 0)                                                \
  3105.   goto END;
  3106.  
  3107.     XP_SPRINTF(buffer, 
  3108. "<TITLE>Information about the Netscape disk cache</TITLE>\n"
  3109. "<h2>Disk Cache statistics</h2>\n"
  3110. "<TABLE>\n"
  3111. "<TR>\n"
  3112. "<TD ALIGN=RIGHT><b>Maximum size:</TD>\n"
  3113. "<TD>%ld</TD>\n"
  3114. "</TR>\n"
  3115. "<TR>\n"
  3116. "<TD ALIGN=RIGHT><b>Current size:</TD>\n"
  3117. "<TD>%ld</TD>\n"
  3118. "</TR>\n"
  3119. "<TR>\n"
  3120. "<TD ALIGN=RIGHT><b>Number of files in cache:</TD>\n"
  3121. "<TD>%ld</TD>\n"
  3122. "</TR>\n"
  3123. "<TR>\n"
  3124. "<TD ALIGN=RIGHT><b>Average cache file size:</TD>\n"
  3125. "<TD>%ld</TD>\n"
  3126. "</TR>\n"
  3127. "</TABLE>\n"
  3128. "<HR>",
  3129. net_MaxDiskCacheSize,
  3130. net_DiskCacheSize,
  3131. net_NumberInDiskCache,
  3132. net_NumberInDiskCache ? net_DiskCacheSize/net_NumberInDiskCache : 0);
  3133.  
  3134.     PUT_PART(buffer);
  3135.  
  3136.     if(!cache_database)
  3137.       {
  3138.         XP_STRCPY(buffer, "The cache database is currently closed");
  3139.         PUT_PART(buffer);
  3140.         goto END;
  3141.       }
  3142.  
  3143.     if(0 != (*cache_database->seq)(cache_database, &key, &data, R_FIRST))
  3144.         return;
  3145.  
  3146.     /* define some macros to help us output HTML tables
  3147.      */
  3148. #if 0
  3149.  
  3150. #define TABLE_TOP(arg1)                \
  3151.     XP_SPRINTF(buffer,                 \
  3152. "<TR><TD ALIGN=RIGHT><b>%s</TD>\n"    \
  3153. "<TD>", arg1);                        \
  3154. PUT_PART(buffer);
  3155.  
  3156. #define TABLE_BOTTOM                \
  3157.     XP_SPRINTF(buffer,                 \
  3158. "</TD></TR>");                        \
  3159. PUT_PART(buffer);
  3160.  
  3161. #else
  3162.  
  3163. #define TABLE_TOP(arg1)                    \
  3164.     XP_STRCPY(buffer, "<tt>");            \
  3165.     for(i=XP_STRLEN(arg1); i < 16; i++)    \
  3166.         XP_STRCAT(buffer, " ");    \
  3167.     XP_STRCAT(buffer, arg1);            \
  3168.     XP_STRCAT(buffer, " </tt>");        \
  3169.     PUT_PART(buffer);
  3170.  
  3171. #define TABLE_BOTTOM                    \
  3172.     XP_STRCPY(buffer, "<BR>\n");        \
  3173.     PUT_PART(buffer);
  3174.  
  3175. #endif
  3176.  
  3177.     do
  3178.       {
  3179.  
  3180.         cache_obj = net_Fast_DBDataToCacheStruct(&data);
  3181.  
  3182.         if(!cache_obj)
  3183.           {
  3184.             if(!net_IsValidCacheDBT(&data)
  3185.                  && (key.size < 4 || XP_STRNCMP((char*)key.data, 
  3186.                                                 INTERNAL_NAME_PREFIX, 
  3187.                                                 4)))
  3188.               {
  3189.                 
  3190.                 XP_STRCPY(buffer, "<H3>Corrupted or misversioned cache entry</H3>"
  3191.                                   "This entry will be deleted automatically "
  3192.                                   "in the future."
  3193.                                   "<HR ALIGN=LEFT WIDTH=50%>");
  3194.                 PUT_PART(buffer);
  3195.               }
  3196.           }
  3197.         else
  3198.           {
  3199. #if 0
  3200.             /* begin a table for this entry */
  3201.             XP_STRCPY(buffer, "<TABLE>");
  3202.             PUT_PART(buffer);
  3203. #endif
  3204.  
  3205.             /* put the URL out there */
  3206.             /* the URL is 8 bytes into the key struct
  3207.               */
  3208.             address = (char *)key.data+8;
  3209.  
  3210.             TABLE_TOP("URL:");
  3211.             XP_STRCPY(buffer, "<A TARGET=Internal_URL_Info HREF=about:");
  3212.             PUT_PART(buffer);
  3213.             PUT_PART(address);
  3214.             XP_STRCPY(buffer, ">");
  3215.             PUT_PART(buffer);
  3216.             escaped = NET_EscapeHTML(address);
  3217.             PUT_PART(escaped);
  3218.             FREE(escaped);
  3219.             XP_STRCPY(buffer, "</A>");
  3220.             PUT_PART(buffer);
  3221.             TABLE_BOTTOM;
  3222.  
  3223.             TABLE_TOP( XP_GetString(MK_CACHE_CONTENT_LENGTH) );
  3224.             XP_SPRINTF(buffer, "%lu", cache_obj->content_length);
  3225.             PUT_PART(buffer);
  3226.             TABLE_BOTTOM;
  3227.  
  3228.             if(cache_obj->content_length != cache_obj->real_content_length)
  3229.               {
  3230.                 TABLE_TOP( XP_GetString(MK_CACHE_REAL_CONTENT_LENGTH) );
  3231.                 XP_SPRINTF(buffer, "%lu", cache_obj->real_content_length);
  3232.                 PUT_PART(buffer);
  3233.                 TABLE_BOTTOM;
  3234.               }
  3235.  
  3236.             TABLE_TOP( XP_GetString(MK_CACHE_CONTENT_TYPE) );
  3237.             PUT_PART(cache_obj->content_type);
  3238.             TABLE_BOTTOM;
  3239.  
  3240.             TABLE_TOP( XP_GetString(MK_CACHE_LOCAL_FILENAME) );
  3241.             PUT_PART(cache_obj->filename);
  3242.             TABLE_BOTTOM;
  3243.  
  3244.             TABLE_TOP( XP_GetString(MK_CACHE_LAST_MODIFIED) );
  3245.             if(cache_obj->last_modified)
  3246.               {
  3247.                 PUT_PART(ctime(&cache_obj->last_modified));
  3248.               }
  3249.             else
  3250.               {
  3251.                 XP_STRCPY(buffer, "No date sent");
  3252.                 PUT_PART(buffer);
  3253.               }
  3254.             TABLE_BOTTOM;
  3255.  
  3256.             TABLE_TOP( XP_GetString(MK_CACHE_EXPIRES) );
  3257.             if(cache_obj->expires)
  3258.               {
  3259.                 PUT_PART(ctime(&cache_obj->expires));
  3260.               }
  3261.             else
  3262.               {
  3263.                 XP_STRCPY(buffer, "No expiration date sent");
  3264.                 PUT_PART(buffer);
  3265.               }
  3266.             TABLE_BOTTOM;
  3267.  
  3268.             if(long_form)
  3269.               {
  3270.                 TABLE_TOP( XP_GetString(MK_CACHE_LAST_ACCESSED) );
  3271.                 PUT_PART(ctime(&cache_obj->last_accessed));
  3272.                 TABLE_BOTTOM;
  3273.  
  3274.                 TABLE_TOP( XP_GetString(MK_CACHE_CHARSET) );
  3275.                 if(cache_obj->charset)
  3276.                   {
  3277.                     PUT_PART(cache_obj->charset);
  3278.                   }
  3279.                 else
  3280.                   {
  3281.                     XP_STRCPY(buffer, "iso-8859-1 (default)");
  3282.                     PUT_PART(buffer);
  3283.                   }
  3284.                 TABLE_BOTTOM;
  3285.  
  3286.                 TABLE_TOP( XP_GetString(MK_CACHE_SECURE) );
  3287.                 XP_SPRINTF(buffer, "%s", cache_obj->security_on ? 
  3288.                                                     "TRUE" : "FALSE");
  3289.                 PUT_PART(buffer);
  3290.                 TABLE_BOTTOM;
  3291.  
  3292.                 TABLE_TOP( XP_GetString(MK_CACHE_USES_RELATIVE_PATH) );
  3293.                 XP_SPRINTF(buffer, "%s", cache_obj->is_relative_path ? 
  3294.                                                     "TRUE" : "FALSE");
  3295.                 PUT_PART(buffer);
  3296.                 TABLE_BOTTOM;
  3297.  
  3298.                 TABLE_TOP( XP_GetString(MK_CACHE_FROM_NETSITE_SERVER) );
  3299.                 XP_SPRINTF(buffer, "%s", cache_obj->is_netsite ? 
  3300.                                                     "TRUE" : "FALSE");
  3301.                 PUT_PART(buffer);
  3302.                 TABLE_BOTTOM;
  3303.  
  3304.                 TABLE_TOP( "Lock date:" );
  3305.                 if(cache_obj->lock_date)
  3306.                   {
  3307.                     PUT_PART(ctime(&cache_obj->lock_date));
  3308.                   }
  3309.                 else
  3310.                   {
  3311.                     XP_STRCPY(buffer, "Not locked");
  3312.                     PUT_PART(buffer);
  3313.                   }
  3314.                 TABLE_BOTTOM;
  3315.               }
  3316.                 
  3317.  
  3318. #if 0
  3319.             /* end the table for this entry */
  3320.             XP_STRCPY(buffer, "</TABLE><HR ALIGN=LEFT WIDTH=50%>");
  3321.             PUT_PART(buffer);
  3322. #else
  3323.             XP_STRCPY(buffer, "\n<P>\n");
  3324.             PUT_PART(buffer);
  3325. #endif
  3326.           }
  3327.     
  3328.     
  3329.       }
  3330.     while(0 == (*cache_database->seq)(cache_database, &key, &data, R_NEXT));
  3331.  
  3332. END:
  3333.     FREE(buffer);
  3334.     if(cur_entry->status < 0)
  3335.         (*stream->abort)(stream, cur_entry->status);
  3336.     else
  3337.         (*stream->complete)(stream);
  3338.  
  3339.     return;
  3340. }
  3341.  
  3342. #include "libmocha.h"
  3343.  
  3344. #define SANE_BUFLEN    1024
  3345.  
  3346. NET_StreamClass *
  3347. NET_CloneWysiwygCacheFile(MWContext *window_id, URL_Struct *URL_s,
  3348.               uint32 nbytes, const char * wysiwyg_url, 
  3349.               const char * base_href)
  3350. {
  3351.     char *filename;
  3352.     PRCList *link;
  3353.     CacheDataObject *data_object;
  3354.     NET_StreamClass *stream;
  3355.     XP_File fromfp;
  3356.     int32 buflen, len;
  3357.     char *buf;
  3358.     int url_type = NET_URL_Type(URL_s->address);
  3359.     XP_FileType mode = xpCache;
  3360.     
  3361.     if (url_type == MAILBOX_TYPE_URL ||
  3362.         url_type == IMAP_TYPE_URL ||
  3363.         url_type == POP3_TYPE_URL)
  3364.         return NULL;
  3365.  
  3366.     filename = URL_s->cache_file;   
  3367.     if (!filename) 
  3368.       {
  3369.         /* not hitting the cache -- check whether we're filling it */
  3370.         for (link = active_cache_data_objects.next;
  3371.              link != &active_cache_data_objects;
  3372.              link = link->next)
  3373.           {
  3374.             data_object = (CacheDataObject *)link;
  3375.             if (data_object->URL_s == URL_s)
  3376.               {
  3377.                 XP_FileFlush(data_object->fp);
  3378.                 filename = data_object->cache_object->filename;
  3379.                 goto found;
  3380.               }
  3381.           }
  3382.  
  3383.         /* try memory cache and local filesystem */
  3384.         stream = net_CloneWysiwygMemCacheEntry(window_id, URL_s, nbytes,
  3385.                                wysiwyg_url, base_href);
  3386.         if (stream)
  3387.             return stream;
  3388.         return net_CloneWysiwygLocalFile(window_id, URL_s, nbytes, 
  3389.                          wysiwyg_url, base_href);
  3390.       }
  3391.     else
  3392.       {
  3393.         /* 
  3394.          * If this is a local file URL_s->cache_file will have been
  3395.          *   set by the code in mkfile.c so that the stream is treated
  3396.          *   like a disk-cache stream.  But, in this case, we care that
  3397.          *   they are different and need to preserve the fact that its
  3398.          *   a local file URL
  3399.          */
  3400.         if(NET_IsLocalFileURL(URL_s->address))
  3401.             mode = xpURL;
  3402.       }
  3403.  
  3404. found:
  3405.     fromfp = XP_FileOpen(filename, mode, XP_FILE_READ_BIN);
  3406.     if (!fromfp)
  3407.         return NULL;
  3408.     stream = LM_WysiwygCacheConverter(window_id, URL_s, wysiwyg_url, 
  3409.                       base_href);
  3410.     if (!stream)
  3411.       {
  3412.         XP_FileClose(fromfp);
  3413.         return 0;
  3414.       }
  3415.     buflen = stream->is_write_ready(stream);
  3416.     if (buflen > SANE_BUFLEN)
  3417.         buflen = SANE_BUFLEN;
  3418.     buf = (char *)XP_ALLOC(buflen * sizeof(char));
  3419.     if (!buf)
  3420.       {
  3421.         XP_FileClose(fromfp);
  3422.         return 0;
  3423.       }
  3424.     while (nbytes != 0)
  3425.       {
  3426.         len = buflen;
  3427.         if ((uint32)len > nbytes)
  3428.             len = (int32)nbytes;
  3429.         len = XP_FileRead(buf, len, fromfp);
  3430.         if (len <= 0)
  3431.             break;
  3432.         if (stream->put_block(stream, buf, len) < 0)
  3433.             break;
  3434.         nbytes -= len;
  3435.       }
  3436.     FREE(buf);
  3437.     XP_FileClose(fromfp);
  3438.     if (nbytes != 0)
  3439.       {
  3440.         /* NB: Our caller must clear top_state->mocha_write_stream. */
  3441.         stream->abort(stream, MK_UNABLE_TO_CONVERT);
  3442.         XP_DELETE(stream);
  3443.         return 0;
  3444.       }
  3445.     return stream;
  3446. }
  3447.  
  3448. #endif /* MOZILLA_CLIENT */
  3449.