Compare commits

..

107 Commits

Author SHA1 Message Date
hoa.nguyen%intel.com
22c40d96b2 removed the report of db filesize in GetStorageInUse.
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@55763 18797224-902f-48f8-a5cc-f745e15eee43
1999-12-08 21:54:27 +00:00
hoa.nguyen%intel.com
06a79b2069 fixed a bug in SetStoredContentLength so that it will update m_StorageInUse in nsNetDiskCache.
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@55762 18797224-902f-48f8-a5cc-f745e15eee43
1999-12-08 21:53:57 +00:00
hoa.nguyen%intel.com
ebc4face0d Added SetDiskCacheFolder for filecache test.
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@55608 18797224-902f-48f8-a5cc-f745e15eee43
1999-12-07 22:08:45 +00:00
hoa.nguyen%intel.com
150696bb86 Fixed DB corruption detection and error recovery logic. Removed Preference. Added routine for the special entry in DB.
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@55606 18797224-902f-48f8-a5cc-f745e15eee43
1999-12-07 22:07:56 +00:00
hoa.nguyen%intel.com
683045595b Added a few member according to the new nsIChannel i/f. Converted all the function to use raw file transport instead of nsIOService.
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@55605 18797224-902f-48f8-a5cc-f745e15eee43
1999-12-07 22:07:21 +00:00
hoa.nguyen%intel.com
7f09538b93 Fixed a memory leak on mInfo. Init() now also pass through recordID.
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@55601 18797224-902f-48f8-a5cc-f745e15eee43
1999-12-07 22:06:29 +00:00
hoa.nguyen%intel.com
bb364ef512 member name changed to follow the same convention. Added error recovery routine.
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@55600 18797224-902f-48f8-a5cc-f745e15eee43
1999-12-07 22:05:57 +00:00
hoa.nguyen%intel.com
7c96c92a19 sync now happens once every second. DB filesize is only updated upon sync. A special entry is added to record initial size and entry number of filecache.
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@55597 18797224-902f-48f8-a5cc-f745e15eee43
1999-12-07 22:04:56 +00:00
fur%netscape.com
a6defdef4c Merge portability changes and bug fixes from the trunk
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@55586 18797224-902f-48f8-a5cc-f745e15eee43
1999-12-07 17:40:40 +00:00
fur%netscape.com
76159a2caf Updated to NPL 1.1
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@55504 18797224-902f-48f8-a5cc-f745e15eee43
1999-12-07 01:40:45 +00:00
fur%netscape.com
1988cb05b5 Tweak comments
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@55499 18797224-902f-48f8-a5cc-f745e15eee43
1999-12-07 01:14:55 +00:00
fur%netscape.com
dd8c6b3bed Added nsINetDataCacheManager::SetDiskCacheFolder()
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@55484 18797224-902f-48f8-a5cc-f745e15eee43
1999-12-07 00:02:58 +00:00
fur%netscape.com
bc64749366 Account for arg changes in NewChannel() API
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@55475 18797224-902f-48f8-a5cc-f745e15eee43
1999-12-06 23:30:30 +00:00
fur%netscape.com
2e9287bd58 Match NewChannel() API changes on trunk
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@55472 18797224-902f-48f8-a5cc-f745e15eee43
1999-12-06 23:23:07 +00:00
fur%netscape.com
0f2274a140 Checkpoint
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@55471 18797224-902f-48f8-a5cc-f745e15eee43
1999-12-06 23:22:37 +00:00
fur%netscape.com
957fa10cac Retire nsINetDataCache::GetCapacity
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@55469 18797224-902f-48f8-a5cc-f745e15eee43
1999-12-06 23:16:10 +00:00
fur%netscape.com
e603146886 Track trunk API changes
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@55467 18797224-902f-48f8-a5cc-f745e15eee43
1999-12-06 23:15:32 +00:00
fur%netscape.com
cb698a0df1 + Retired nsINetDataCache::GetCapacity()
+ Fixed gcc build problem


git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@55466 18797224-902f-48f8-a5cc-f745e15eee43
1999-12-06 23:14:38 +00:00
fur%netscape.com
1b918d9ef0 + Added proxy channel arg to NewChannel()
+ Changed name of setProtocolPrivate/getProtocolPrivate to setAnnotation/getAnnotation\
+ Added inUse attribute
+ Touched up comments


git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@55465 18797224-902f-48f8-a5cc-f745e15eee43
1999-12-06 23:08:08 +00:00
fur%netscape.com
6407144c9f Removed capacity attribute
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@55464 18797224-902f-48f8-a5cc-f745e15eee43
1999-12-06 23:06:44 +00:00
fur%netscape.com
2ed563a178 Merge with trunk makefile.win
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@55462 18797224-902f-48f8-a5cc-f745e15eee43
1999-12-06 23:05:39 +00:00
fur%netscape.com
4becc0b508 Add assertion to cache manager to ensure that it is limiting cache occupancy
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@54566 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-29 15:23:34 +00:00
fur%netscape.com
7d5427ea31 Obey the MAX_CONTENT_LENGTH limit
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@54565 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-29 15:22:56 +00:00
fur%netscape.com
99904bcc48 Eliminate libs build target, as Warren has done for the rest of the tree
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@54545 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-29 02:15:04 +00:00
fur%netscape.com
bcb56c9593 Add strong ref to channel
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@54544 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-29 02:14:17 +00:00
fur%netscape.com
f18bc8e6cd Fix ownership issues. Change SetProtocolData/GetProtocolData args
to match new prototype.


git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@54109 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-21 07:51:56 +00:00
fur%netscape.com
7d14c5669a Handle NULL load group - they're supposed to be optional
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@54108 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-21 07:51:14 +00:00
fur%netscape.com
c0dd3df02e Fix tons of ref-counting ownership issues and other bug fixes
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@54107 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-21 07:50:25 +00:00
fur%netscape.com
e5cc84978f Checkpoint
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@54097 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-21 05:08:20 +00:00
fur%netscape.com
5694537330 Changed SetProtocolData/GetProtocolData to accept a tag argument so that
multiple cache clients can attach info to the cache database.


git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@54096 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-21 05:07:40 +00:00
fur%netscape.com
297c5ceba3 Add/modify APIs to track nsIChannel
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@54095 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-21 05:05:01 +00:00
fur%netscape.com
e0311312f7 Temporarily disable pref-reading code, since it doesn't work in the browser
and the code that measures the size of the cache db, since it's a performance
hog.


git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@54094 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-21 05:04:13 +00:00
fur%netscape.com
cf3dc77b02 Fix unitialized variable
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@54093 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-21 05:01:03 +00:00
fur%netscape.com
dd2506a737 Quash warnings
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@53842 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-18 06:19:51 +00:00
fur%netscape.com
b1bee1f21c Merge with trunk
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@53831 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-18 05:38:26 +00:00
fur%netscape.com
48ecc5625b Added review comments
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@53674 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-16 19:46:28 +00:00
fur%netscape.com
1b791685e6 No longer need factory code. Its been moved to netwerk/cache/builds/nsNetDataCacheModule.cpp
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@53663 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-16 18:21:11 +00:00
fur%netscape.com
dc94d1d6e2 Added review comments
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@53647 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-16 10:08:26 +00:00
hoa.nguyen%intel.com
f5b437ade3 added Unix support
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@53574 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-16 00:21:05 +00:00
hoa.nguyen%intel.com
8c0b4b3e4a changed NPL to MPL
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@53573 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-16 00:16:33 +00:00
hoa.nguyen%intel.com
fb640ab144 added Truncate function
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@53572 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-16 00:07:27 +00:00
hoa.nguyen%intel.com
106e263b33 added support for memory cache
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@53570 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-16 00:00:54 +00:00
fur%netscape.com
85045a8552 Add TestCacheMgr
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@53537 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-15 21:13:19 +00:00
fur%netscape.com
a2279be132 *** empty log message ***
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@53536 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-15 21:12:58 +00:00
fur%netscape.com
0ce702d402 Don't call NS_ERROR() when a record ID is not found
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@53533 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-15 21:12:17 +00:00
fur%netscape.com
f14d03cd67 Fixed CommitFlags()
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@53531 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-15 21:11:14 +00:00
fur%netscape.com
b91343fdf6 Checkpoint
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@53520 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-15 18:30:44 +00:00
fur%netscape.com
2c517489b5 Disable warning, so cache code can run
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@53519 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-15 17:39:35 +00:00
(no author)
ae57da58eb This commit was manufactured by cvs2svn to create branch
'CacheIntegration_BRANCH'.

git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@53517 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-15 17:10:07 +00:00
fur%netscape.com
8d4586dd65 Update components table and macro instantiations to conform to new definitions
in nsIGenericFactory.h


git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@53499 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-15 09:06:41 +00:00
fur%netscape.com
9b473ad9be Added starting offset param to interceptAsyncRead() method
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@53498 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-15 08:53:15 +00:00
fur%netscape.com
2ad227a994 Merged with trunk
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@53496 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-15 08:01:58 +00:00
fur%netscape.com
94d8da33c1 Replace 1.0 NPL with 1.1 version
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@53487 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-15 06:13:13 +00:00
fur%netscape.com
81c05809fd Remove dead files
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@53486 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-15 06:08:40 +00:00
fur%netscape.com
e30547b2b2 Remove dead files
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@53485 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-15 05:52:29 +00:00
fur%netscape.com
257f9cfaaa Fix Boogs. Replace 1.0 NPL with 1.1 version
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@53484 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-15 05:51:02 +00:00
fur%netscape.com
96e2654e43 Replace 1.0 NPL with 1.1 NPL
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@53474 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-14 20:35:26 +00:00
fur%netscape.com
3b023433be Replace 1.0 NPL with 1.1 version
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@53472 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-14 19:56:44 +00:00
fur%netscape.com
1b89716afe Added more comments
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@53471 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-14 19:50:30 +00:00
fur%netscape.com
ad02058877 Add comments. Change method names
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@53470 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-14 18:51:57 +00:00
fur%netscape.com
fa8a3196e7 Merge with trunk
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@53434 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-13 19:35:49 +00:00
fur%netscape.com
5c2c543e58 Fixed bugs which prevented embedded NUL characters
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@53431 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-13 18:45:28 +00:00
fur%netscape.com
c588721cc0 Added NS_NewStorageStream().
Changed method name, Initialize ==> Init


git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@53430 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-13 18:43:20 +00:00
fur%netscape.com
0b049b17ba Fix Boogs
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@53429 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-13 18:41:01 +00:00
fur%netscape.com
854ef4631d Merge from trunk
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@53268 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-11 22:29:20 +00:00
fur%netscape.com
051c558653 Detect failure to truncate cache entry
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@53214 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-11 18:16:24 +00:00
fur%netscape.com
37a04adb09 Killed build warnings. Added stubs for unimplemented methods
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@53072 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-10 06:05:33 +00:00
fur%netscape.com
c823c04b45 Combine cache components into module
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@53014 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-09 22:08:49 +00:00
fur%netscape.com
03cbd000eb Sync with trunk
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@52998 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-09 17:36:48 +00:00
fur%netscape.com
a91e91a1c7 Added Windows makefiles so that the cache manager, file cache and
memory cache components are built as part of netlib and combined into
a single XPCOM module, named "nkcache.dll"


git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@52970 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-08 22:44:04 +00:00
fur%netscape.com
be7a5a48b6 Added call to LimitCacheSize
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@52968 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-08 22:40:41 +00:00
fur%netscape.com
b2bc7468e8 Add cache manager CID
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@52967 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-08 22:38:20 +00:00
fur%netscape.com
9692dfd994 Add cache manager ProgID
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@52966 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-08 22:37:30 +00:00
fur%netscape.com
f3edd4cfb5 Added an owning reference from nsDiskCacheRecordChannel to
its associated nsDiskCacheRecord.  Without this, the channel
may access free'ed memory.


git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@52962 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-08 22:28:39 +00:00
fur%netscape.com
33403345c1 Rename class to avoid name collision with similar code in file cache.
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@52961 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-08 22:25:28 +00:00
fur%netscape.com
20c850de23 Merge with tip
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@52960 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-08 22:23:35 +00:00
fur%netscape.com
e8b619cd02 Merge with tip
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@52959 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-08 22:18:25 +00:00
fur%netscape.com
eed396bb92 Stabilize ref-count during construction
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@52946 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-08 18:46:17 +00:00
fur%netscape.com
41d44c070b Eliminate dead files
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@52932 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-07 20:19:55 +00:00
fur%netscape.com
698ba42268 Revamped directory structure
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@52922 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-06 19:36:16 +00:00
(no author)
1a0fd23991 This commit was manufactured by cvs2svn to create branch
'CacheIntegration_BRANCH'.

git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@52912 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-06 03:43:56 +00:00
fur%netscape.com
67dded330b Add nsDiskCacheRecordChannel.cpp
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@52876 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-05 22:18:26 +00:00
fur%netscape.com
936ff4777a Fix compilation errors on Win32
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@52874 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-05 22:18:04 +00:00
fur%netscape.com
96c55e42f7 Accommodate API changes in nsINetDataCache
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@52873 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-05 22:17:42 +00:00
fur%netscape.com
82fa0cf06a Got rid of GetReadOnly(). Added GetFlags()
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@52872 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-05 22:15:05 +00:00
fur%netscape.com
98c8285334 First shot at Win32 makefile
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@52869 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-05 22:03:02 +00:00
fur%netscape.com
bad4b683f4 Removed SetCapacity() method
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@52868 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-05 22:01:26 +00:00
fur%netscape.com
cb5269a28a Checkpoint
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@52864 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-05 21:47:25 +00:00
fur%netscape.com
74712f3635 Added binary I/O streams
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@52860 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-05 20:02:06 +00:00
fur%netscape.com
9f8ea739db Correct error comment
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@52859 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-05 20:01:39 +00:00
hoa.nguyen%intel.com
97a10dd7c6 Add offset writing for nsOutputStream
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@52789 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-04 18:02:39 +00:00
hoa.nguyen%intel.com
85a132fac0 Add command line switch to test memory and disk cache.
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@52788 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-04 18:01:28 +00:00
hoa.nguyen%intel.com
e594eee877 Add proxy channel interface, and misc bug fixes.
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@52787 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-04 17:59:42 +00:00
hoa.nguyen%intel.com
9148eee3d6 Initial checkin of disk cache modules
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@51580 18797224-902f-48f8-a5cc-f745e15eee43
1999-10-22 22:37:18 +00:00
hoa.nguyen%intel.com
b5989a8382 Initial checkin of disk cache module
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@51579 18797224-902f-48f8-a5cc-f745e15eee43
1999-10-22 22:36:07 +00:00
fur%netscape.com
2b861f60d9 Create a new channel for every call to Write()
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@51335 18797224-902f-48f8-a5cc-f745e15eee43
1999-10-21 01:35:51 +00:00
fur%netscape.com
87db050b37 Added tests for:
nsINetDataCache::GetStorageInUse()
    nsINetDataCacheRecord::SetContentLength()
    nsIOutputStream::Write(), using non-zero starting offsets


git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@51071 18797224-902f-48f8-a5cc-f745e15eee43
1999-10-18 23:55:44 +00:00
fur%netscape.com
ffe483cf95 Initial cut at memory-cache functionality is complete
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@51067 18797224-902f-48f8-a5cc-f745e15eee43
1999-10-18 23:46:08 +00:00
fur%netscape.com
52aa17a1c3 Incorporate nsStorageStream into xpcom.dll
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@50814 18797224-902f-48f8-a5cc-f745e15eee43
1999-10-15 07:40:42 +00:00
fur%netscape.com
5fdb3aa69e Initial implementation of 'storage stream' - used as the heart of the memory cache
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@50812 18797224-902f-48f8-a5cc-f745e15eee43
1999-10-15 07:39:45 +00:00
fur%netscape.com
8cae473bc0 Add opaque keys to nsHashtable
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@50811 18797224-902f-48f8-a5cc-f745e15eee43
1999-10-15 07:38:01 +00:00
fur%netscape.com
0719303755 Fix linkage problem
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@50810 18797224-902f-48f8-a5cc-f745e15eee43
1999-10-15 07:37:21 +00:00
fur%netscape.com
90d3e40858 Fix bugs in Next(). Prev() and IsDone()
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@50809 18797224-902f-48f8-a5cc-f745e15eee43
1999-10-15 07:36:35 +00:00
fur%netscape.com
c792b2d35c Changed IDL to generate identical C++ headers, but with better scriptability
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@50808 18797224-902f-48f8-a5cc-f745e15eee43
1999-10-15 07:32:04 +00:00
fur%netscape.com
7a4377d840 Initial cut at memory cache
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@50806 18797224-902f-48f8-a5cc-f745e15eee43
1999-10-15 07:24:06 +00:00
fur%netscape.com
a5fa416010 Added TestRawCache.cpp
git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@50804 18797224-902f-48f8-a5cc-f745e15eee43
1999-10-15 07:19:52 +00:00
(no author)
49d00db5e2 This commit was manufactured by cvs2svn to create branch
'CacheIntegration_BRANCH'.

git-svn-id: svn://10.0.0.236/branches/CacheIntegration_BRANCH@50589 18797224-902f-48f8-a5cc-f745e15eee43
1999-10-13 10:24:13 +00:00
119 changed files with 24531 additions and 10204 deletions

View File

@@ -1,298 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "msgCore.h" // for pre-compiled headers
//#include "nsIMsgIdentity.h"
#include "nsIMsgAccountManager.h"
//#include "nsIPop3IncomingServer.h"
#include "nsMsgMailSession.h"
#include "nsMsgLocalCID.h"
#include "nsMsgBaseCID.h"
#include "nsCOMPtr.h"
#include "nsMsgFolderCache.h"
#include "nsIFileLocator.h"
#include "nsFileLocations.h"
#include "nsIMsgStatusFeedback.h"
NS_IMPL_ISUPPORTS(nsMsgMailSession, nsCOMTypeInfo<nsIMsgMailSession>::GetIID());
static NS_DEFINE_CID(kMsgAccountManagerCID, NS_MSGACCOUNTMANAGER_CID);
static NS_DEFINE_CID(kMsgFolderCacheCID, NS_MSGFOLDERCACHE_CID);
static NS_DEFINE_IID(kIFileLocatorIID, NS_IFILELOCATOR_IID);
static NS_DEFINE_CID(kFileLocatorCID, NS_FILELOCATOR_CID);
//static NS_DEFINE_CID(kMsgIdentityCID, NS_MSGIDENTITY_CID);
//static NS_DEFINE_CID(kPop3IncomingServerCID, NS_POP3INCOMINGSERVER_CID);
//static NS_DEFINE_CID(kPrefCID, NS_PREF_CID);
nsMsgMailSession::nsMsgMailSession():
mRefCnt(0),
m_accountManager(0),
m_msgFolderCache(0)
{
NS_INIT_REFCNT();
}
nsMsgMailSession::~nsMsgMailSession()
{
Shutdown();
}
nsresult nsMsgMailSession::Init()
{
nsresult rv = NS_NewISupportsArray(getter_AddRefs(mListeners));
return rv;
}
nsresult nsMsgMailSession::Shutdown()
{
if(m_accountManager)
{
if (m_msgFolderCache)
m_accountManager->WriteToFolderCache(m_msgFolderCache);
m_accountManager->CloseCachedConnections();
m_accountManager->UnloadAccounts();
}
NS_IF_RELEASE(m_accountManager);
NS_IF_RELEASE(m_msgFolderCache);
return NS_OK;
}
// nsIMsgMailSession
nsresult nsMsgMailSession::GetCurrentIdentity(nsIMsgIdentity ** aIdentity)
{
nsresult rv;
nsCOMPtr<nsIMsgAccountManager> accountManager;
rv = GetAccountManager(getter_AddRefs(accountManager));
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIMsgAccount> defaultAccount;
rv = accountManager->GetDefaultAccount(getter_AddRefs(defaultAccount));
if (NS_FAILED(rv)) return rv;
rv = defaultAccount->GetDefaultIdentity(aIdentity);
if (NS_SUCCEEDED(rv))
NS_ADDREF(*aIdentity);
return rv;
}
nsresult nsMsgMailSession::GetCurrentServer(nsIMsgIncomingServer ** aServer)
{
nsresult rv=NS_ERROR_UNEXPECTED;
nsCOMPtr<nsIMsgAccountManager> accountManager;
rv = GetAccountManager(getter_AddRefs(accountManager));
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIMsgAccount> defaultAccount;
rv = accountManager->GetDefaultAccount(getter_AddRefs(defaultAccount));
if (NS_FAILED(rv)) return rv;
//if successful aServer will be addref'd by GetIncomingServer
rv = defaultAccount->GetIncomingServer(aServer);
return rv;
}
nsresult nsMsgMailSession::GetAccountManager(nsIMsgAccountManager* *aAM)
{
NS_ENSURE_ARG_POINTER(aAM);
nsresult rv;
NS_WITH_SERVICE(nsIMsgAccountManager, accountManager, kMsgAccountManagerCID, &rv);
if (NS_FAILED(rv)) return rv;
accountManager->LoadAccounts();
*aAM = accountManager;
NS_IF_ADDREF(*aAM);
return NS_OK;
}
nsresult nsMsgMailSession::GetFolderCache(nsIMsgFolderCache* *aFolderCache)
{
if (!aFolderCache) return NS_ERROR_NULL_POINTER;
nsresult rv = NS_OK;
if (!m_msgFolderCache)
{
rv = nsComponentManager::CreateInstance(kMsgFolderCacheCID,
NULL,
nsCOMTypeInfo<nsIMsgFolderCache>::GetIID(),
(void **)&m_msgFolderCache);
if (NS_FAILED(rv))
return rv;
nsCOMPtr <nsIFileSpec> cacheFile;
NS_WITH_SERVICE(nsIFileLocator, locator, kFileLocatorCID, &rv);
if (NS_FAILED(rv)) return rv;
rv = locator->GetFileLocation(nsSpecialFileSpec::App_MessengerFolderCache50, getter_AddRefs(cacheFile));
if (NS_FAILED(rv)) return rv;
m_msgFolderCache->Init(cacheFile);
}
*aFolderCache = m_msgFolderCache;
NS_IF_ADDREF(*aFolderCache);
return rv;
}
nsresult nsMsgMailSession::GetTemporaryMsgStatusFeedback(nsIMsgStatusFeedback* *aMsgStatusFeedback)
{
if (!aMsgStatusFeedback) return NS_ERROR_NULL_POINTER;
*aMsgStatusFeedback = m_temporaryMsgStatusFeedback;
NS_IF_ADDREF(*aMsgStatusFeedback);
return NS_OK;
}
nsresult nsMsgMailSession::SetTemporaryMsgStatusFeedback(nsIMsgStatusFeedback* aMsgStatusFeedback)
{
m_temporaryMsgStatusFeedback = do_QueryInterface(aMsgStatusFeedback);
return NS_OK;
}
NS_IMETHODIMP nsMsgMailSession::AddFolderListener(nsIFolderListener * listener)
{
mListeners->AppendElement(listener);
return NS_OK;
}
NS_IMETHODIMP nsMsgMailSession::RemoveFolderListener(nsIFolderListener * listener)
{
mListeners->RemoveElement(listener);
return NS_OK;
}
NS_IMETHODIMP
nsMsgMailSession::NotifyFolderItemPropertyChanged(nsISupports *item,
const char *property,
const char* oldValue,
const char* newValue)
{
nsresult rv;
PRUint32 count;
rv = mListeners->Count(&count);
if (NS_FAILED(rv)) return rv;
for(PRUint32 i = 0; i < count; i++)
{
nsCOMPtr<nsIFolderListener> listener = getter_AddRefs((nsIFolderListener*)mListeners->ElementAt(i));
listener->OnItemPropertyChanged(item, property, oldValue, newValue);
}
return NS_OK;
}
NS_IMETHODIMP
nsMsgMailSession::NotifyFolderItemPropertyFlagChanged(nsISupports *item,
const char *property,
PRUint32 oldValue,
PRUint32 newValue)
{
nsresult rv;
PRUint32 count;
rv = mListeners->Count(&count);
if (NS_FAILED(rv)) return rv;
for(PRUint32 i = 0; i < count; i++)
{
nsCOMPtr<nsIFolderListener> listener = getter_AddRefs((nsIFolderListener*)mListeners->ElementAt(i));
listener->OnItemPropertyFlagChanged(item, property, oldValue, newValue);
}
return NS_OK;
}
NS_IMETHODIMP nsMsgMailSession::NotifyFolderItemAdded(nsIFolder *folder, nsISupports *item)
{
nsresult rv;
PRUint32 count;
rv = mListeners->Count(&count);
if (NS_FAILED(rv)) return rv;
for(PRUint32 i = 0; i < count; i++)
{
nsCOMPtr<nsIFolderListener> listener = getter_AddRefs((nsIFolderListener*)mListeners->ElementAt(i));
listener->OnItemAdded(folder, item);
}
return NS_OK;
}
NS_IMETHODIMP nsMsgMailSession::NotifyFolderItemDeleted(nsIFolder *folder, nsISupports *item)
{
nsresult rv;
PRUint32 count;
rv = mListeners->Count(&count);
if (NS_FAILED(rv)) return rv;
for(PRUint32 i = 0; i < count; i++)
{
nsCOMPtr<nsIFolderListener> listener = getter_AddRefs((nsIFolderListener*)mListeners->ElementAt(i));
listener->OnItemRemoved(folder, item);
}
return NS_OK;
}
NS_IMETHODIMP nsMsgMailSession::NotifyFolderLoaded(nsIFolder *folder)
{
nsresult rv;
PRUint32 count;
rv = mListeners->Count(&count);
if (NS_FAILED(rv)) return rv;
for(PRUint32 i = 0; i < count; i++)
{
nsCOMPtr<nsIFolderListener> listener = getter_AddRefs((nsIFolderListener*)mListeners->ElementAt(i));
listener->OnFolderLoaded(folder);
}
return NS_OK;
}

View File

@@ -1,21 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "MacPrefix.h"

View File

@@ -1,21 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "MacPrefix_debug.h"

View File

@@ -1,87 +0,0 @@
#!nmake
#
# The contents of this file are subject to the Netscape Public License
# Version 1.0 (the "NPL"); you may not use this file except in
# compliance with the NPL. You may obtain a copy of the NPL at
# http://www.mozilla.org/NPL/
#
# Software distributed under the NPL is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
# for the specific language governing rights and limitations under the
# NPL.
#
# The Initial Developer of this code under the NPL is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All Rights
# Reserved.
DEPTH=..\..\..
MODULE= msgbsutl
include <$(DEPTH)\config\config.mak>
################################################################################
## exports
EXPORTS= \
nsMsgLineBuffer.h \
nsMsgGroupRecord.h \
nsUInt32Array.h \
nsMsgKeySet.h \
nsMsgFolder.h \
nsMsgDBFolder.h \
nsLocalFolderSummarySpec.h \
nsMsgIdentity.h \
nsMsgIncomingServer.h \
nsNewsSummarySpec.h \
nsMsgUtils.h \
nsMessage.h \
nsMsgProtocol.h \
nsMsgMailNewsUrl.h \
nsMsgTxn.h \
nsMsgI18N.h \
$(NULL)
################################################################################
## library
LIBNAME = .\$(OBJDIR)\msgbsutl
DLL = $(LIBNAME).dll
DEFINES=-D_IMPL_NS_MSG_BASE
LCFLAGS = \
$(LCFLAGS) \
$(DEFINES) \
$(NULL)
CPP_OBJS= \
.\$(OBJDIR)\nsMsgGroupRecord.obj \
.\$(OBJDIR)\nsMsgLineBuffer.obj \
.\$(OBJDIR)\nsUInt32Array.obj \
.\$(OBJDIR)\nsMsgKeySet.obj \
.\$(OBJDIR)\nsMsgFolder.obj \
.\$(OBJDIR)\nsMsgDBFolder.obj \
.\$(OBJDIR)\nsLocalFolderSummarySpec.obj \
.\$(OBJDIR)\nsMsgIdentity.obj \
.\$(OBJDIR)\nsMsgIncomingServer.obj \
.\$(OBJDIR)\nsNewsSummarySpec.obj \
.\$(OBJDIR)\nsMsgUtils.obj \
.\$(OBJDIR)\nsMessage.obj \
.\$(OBJDIR)\nsMsgProtocol.obj \
.\$(OBJDIR)\nsMsgMailNewsUrl.obj \
.\$(OBJDIR)\nsMsgTxn.obj \
.\$(OBJDIR)\nsMsgI18N.obj \
$(NULL)
LLIBS= \
$(DIST)\lib\xpcom.lib \
$(DIST)\lib\rdfutil_s.lib \
$(LIBNSPR) \
$(NULL)
include <$(DEPTH)/config/rules.mak>
libs:: $(DLL)
$(MAKE_INSTALL) $(LIBNAME).$(DLL_SUFFIX) $(DIST)\bin
$(MAKE_INSTALL) $(LIBNAME).$(LIB_SUFFIX) $(DIST)\lib

View File

@@ -1,76 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "nsLocalFolderSummarySpec.h"
#include "plstr.h"
#include "nsString.h"
MOZ_DECL_CTOR_COUNTER(nsLocalFolderSummarySpec);
nsLocalFolderSummarySpec::~nsLocalFolderSummarySpec()
{
MOZ_COUNT_DTOR(nsLocalFolderSummarySpec);
}
nsLocalFolderSummarySpec::nsLocalFolderSummarySpec()
{
MOZ_COUNT_CTOR(nsLocalFolderSummarySpec);
}
nsLocalFolderSummarySpec::nsLocalFolderSummarySpec(const char *folderPath, PRBool create)
: nsFileSpec(folderPath, create)
{
MOZ_COUNT_CTOR(nsLocalFolderSummarySpec);
CreateSummaryFileName();
}
nsLocalFolderSummarySpec::nsLocalFolderSummarySpec(const nsFileSpec& inFolderPath)
: nsFileSpec(inFolderPath)
{
MOZ_COUNT_CTOR(nsLocalFolderSummarySpec);
CreateSummaryFileName();
}
nsLocalFolderSummarySpec::nsLocalFolderSummarySpec(const nsFilePath &inFolderPath, PRBool create) : nsFileSpec(inFolderPath, create)
{
MOZ_COUNT_CTOR(nsLocalFolderSummarySpec);
CreateSummaryFileName();
}
void nsLocalFolderSummarySpec::SetFolderName(const char *folderPath)
{
*this = folderPath;
}
void nsLocalFolderSummarySpec:: CreateSummaryFileName()
{
char *leafName = GetLeafName();
nsString fullLeafName(leafName);
// Append .msf (msg summary file) this is what windows will want.
// Mac and Unix can decide for themselves.
fullLeafName += ".msf"; // message summary file
char *cLeafName = fullLeafName.ToNewCString();
SetLeafName(cLeafName);
nsAllocator::Free(cLeafName);
PL_strfree(leafName);
}

View File

@@ -1,46 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _nsLocalFolderSummarySpec_H
#define _nsLocalFolderSummarySpec_H
#include "msgCore.h"
#include "nsFileSpec.h"
// Class to name a summary file for a local mail folder,
// given a full folder file spec. For windows, this just means tacking .msf on the end.
// For Unix, it might mean something like putting a '.' on the front and .msgsummary on the end.
// Note this class expects the invoking code to fully specify the folder path.
// This class does NOT prepend the local folder directory, or put .sbd on the containing
// directory names.
class NS_MSG_BASE nsLocalFolderSummarySpec : public nsFileSpec
{
public:
virtual ~nsLocalFolderSummarySpec();
nsLocalFolderSummarySpec();
nsLocalFolderSummarySpec(const char *folderPath, PRBool create = PR_FALSE);
nsLocalFolderSummarySpec(const nsFileSpec& inFolderPath);
nsLocalFolderSummarySpec(const nsFilePath &inFolderPath, PRBool create = PR_FALSE);
void SetFolderName(const char *folderPath);
protected:
void CreateSummaryFileName();
};
#endif

View File

@@ -1,509 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "msgCore.h" // precompiled header...
#include "nsMessage.h"
#include "nsIMsgFolder.h"
nsMessage::nsMessage(void)
: nsRDFResource(), mFolder(nsnull)
{
}
nsMessage::~nsMessage(void)
{
//Member variables are either nsCOMPtr's or ptrs we don't want to own.
}
NS_IMPL_ADDREF_INHERITED(nsMessage, nsRDFResource)
NS_IMPL_RELEASE_INHERITED(nsMessage, nsRDFResource)
NS_IMETHODIMP nsMessage::QueryInterface(REFNSIID aIID, void** aInstancePtr)
{
if (!aInstancePtr) return NS_ERROR_NULL_POINTER;
*aInstancePtr = nsnull;
if (aIID.Equals(nsCOMTypeInfo<nsIMessage>::GetIID()) || aIID.Equals(nsCOMTypeInfo<nsIDBMessage>::GetIID()))
{
*aInstancePtr = NS_STATIC_CAST(nsIDBMessage*, this);
}
if(*aInstancePtr)
{
AddRef();
return NS_OK;
}
return nsRDFResource::QueryInterface(aIID, aInstancePtr);
}
NS_IMETHODIMP
nsMessage::Init(const char* aURI)
{
return nsRDFResource::Init(aURI);
}
NS_IMETHODIMP nsMessage::GetProperty(const char *propertyName, nsString &resultProperty)
{
if(mMsgHdr)
return mMsgHdr->GetProperty(propertyName, resultProperty);
else
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsMessage::SetProperty(const char *propertyName, nsString &propertyStr)
{
if(mMsgHdr)
return mMsgHdr->SetProperty(propertyName, propertyStr);
else
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsMessage::GetUint32Property(const char *propertyName, PRUint32 *pResult)
{
if(mMsgHdr)
return mMsgHdr->GetUint32Property(propertyName, pResult);
else
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsMessage::SetUint32Property(const char *propertyName, PRUint32 propertyVal)
{
if(mMsgHdr)
return mMsgHdr->SetUint32Property(propertyName, propertyVal);
else
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsMessage::GetNumReferences(PRUint16 *result)
{
if(mMsgHdr)
return mMsgHdr->GetNumReferences(result);
else
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsMessage::GetStringReference(PRInt32 refNum, nsCString &resultReference)
{
if(mMsgHdr)
return mMsgHdr->GetStringReference(refNum, resultReference);
else
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsMessage::GetDate(PRTime *result)
{
if(mMsgHdr)
return mMsgHdr->GetDate(result);
else
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsMessage::SetDate(PRTime date)
{
if(mMsgHdr)
return mMsgHdr->SetDate(date);
else
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsMessage::SetMessageId(const char *messageId)
{
if(mMsgHdr)
return mMsgHdr->SetMessageId(messageId);
else
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsMessage::SetReferences(const char *references)
{
if(mMsgHdr)
return mMsgHdr->SetReferences(references);
else
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsMessage::SetCCList(const char *ccList)
{
if(mMsgHdr)
return mMsgHdr->SetCCList(ccList);
else
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsMessage::SetRecipients(const char *recipients, PRBool recipientsIsNewsgroup)
{
if(mMsgHdr)
return mMsgHdr->SetRecipients(recipients, recipientsIsNewsgroup);
else
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsMessage::SetRecipientsArray(const char *names, const char *addresses, PRUint32 numAddresses)
{
if(mMsgHdr)
return mMsgHdr->SetRecipientsArray(names, addresses, numAddresses);
else
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsMessage::SetCCListArray(const char *names, const char *addresses, PRUint32 numAddresses)
{
if(mMsgHdr)
return mMsgHdr->SetCCListArray(names, addresses, numAddresses);
else
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsMessage::SetAuthor(const char *author)
{
if(mMsgHdr)
return mMsgHdr->SetAuthor(author);
else
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsMessage::SetSubject(const char *subject)
{
if(mMsgHdr)
return mMsgHdr->SetSubject(subject);
else
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsMessage::SetStatusOffset(PRUint32 statusOffset)
{
if(mMsgHdr)
return mMsgHdr->SetStatusOffset(statusOffset);
else
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsMessage::GetAuthor(nsString *resultAuthor)
{
if(mMsgHdr)
return mMsgHdr->GetAuthor(resultAuthor);
else
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsMessage::GetSubject(nsString *resultSubject)
{
if(mMsgHdr)
return mMsgHdr->GetSubject(resultSubject);
else
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsMessage::GetRecipients(nsString *resultRecipients)
{
if(mMsgHdr)
return mMsgHdr->GetRecipients(resultRecipients);
else
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsMessage::GetCCList(nsString *ccList)
{
if(mMsgHdr)
return mMsgHdr->GetCCList(ccList);
else
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsMessage::GetMessageId(nsCString *resultMessageId)
{
if(mMsgHdr)
return mMsgHdr->GetMessageId(resultMessageId);
else
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsMessage::GetMime2DecodedAuthor(nsString *resultAuthor)
{
if(mMsgHdr)
return mMsgHdr->GetMime2DecodedAuthor(resultAuthor);
else
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsMessage::GetMime2DecodedSubject(nsString *resultSubject)
{
if(mMsgHdr)
return mMsgHdr->GetMime2DecodedSubject(resultSubject);
else
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsMessage::GetMime2DecodedRecipients(nsString *resultRecipients)
{
if(mMsgHdr)
return mMsgHdr->GetMime2DecodedRecipients(resultRecipients);
else
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsMessage::GetAuthorCollationKey(nsString *resultAuthor)
{
if(mMsgHdr)
return mMsgHdr->GetAuthorCollationKey(resultAuthor);
else
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsMessage::GetSubjectCollationKey(nsString *resultSubject)
{
if(mMsgHdr)
return mMsgHdr->GetSubjectCollationKey(resultSubject);
else
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsMessage::GetRecipientsCollationKey(nsString *resultRecipients)
{
if(mMsgHdr)
return mMsgHdr->GetRecipientsCollationKey(resultRecipients);
else
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsMessage::GetFlags(PRUint32 *result)
{
if(mMsgHdr)
return mMsgHdr->GetFlags(result);
else
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsMessage::SetFlags(PRUint32 flags)
{
if(mMsgHdr)
return mMsgHdr->SetFlags(flags);
else
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsMessage::OrFlags(PRUint32 flags, PRUint32 *result)
{
if(mMsgHdr)
return mMsgHdr->OrFlags(flags, result);
else
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsMessage::AndFlags(PRUint32 flags, PRUint32 *result)
{
if(mMsgHdr)
return mMsgHdr->AndFlags(flags, result);
else
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsMessage::MarkRead(PRBool bRead)
{
if(mMsgHdr)
return mMsgHdr->MarkRead(bRead);
else
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsMessage::MarkFlagged(PRBool bFlagged)
{
if(mMsgHdr)
return mMsgHdr->MarkFlagged(bFlagged);
else
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsMessage::GetMessageKey(nsMsgKey *result)
{
if(mMsgHdr)
return mMsgHdr->GetMessageKey(result);
else
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsMessage::GetThreadId(nsMsgKey *result)
{
if(mMsgHdr)
return mMsgHdr->GetThreadId(result);
else
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsMessage::SetThreadId(nsMsgKey inKey)
{
if(mMsgHdr)
return mMsgHdr->SetThreadId(inKey);
else
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsMessage::SetMessageKey(nsMsgKey inKey)
{
if(mMsgHdr)
return mMsgHdr->SetMessageKey(inKey);
else
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsMessage::GetMessageSize(PRUint32 *result)
{
if(mMsgHdr)
return mMsgHdr->GetMessageSize(result);
else
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsMessage::GetLineCount(PRUint32 *result)
{
if(mMsgHdr)
return mMsgHdr->GetLineCount(result);
else
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsMessage::SetMessageSize(PRUint32 messageSize)
{
if(mMsgHdr)
return mMsgHdr->SetMessageSize(messageSize);
else
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsMessage::SetLineCount(PRUint32 lineCount)
{
if(mMsgHdr)
return mMsgHdr->SetLineCount(lineCount);
else
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsMessage::SetPriority(nsMsgPriority priority)
{
if(mMsgHdr)
return mMsgHdr->SetPriority(priority);
else
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsMessage::SetPriority(const char *priority)
{
if(mMsgHdr)
return mMsgHdr->SetPriority(priority);
else
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsMessage::GetPriority(nsMsgPriority *result)
{
if(mMsgHdr)
return mMsgHdr->GetPriority(result);
else
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsMessage::GetMessageOffset(PRUint32 *result)
{
if(mMsgHdr)
return mMsgHdr->GetMessageOffset(result);
else
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsMessage::GetStatusOffset(PRUint32 *result)
{
if(mMsgHdr)
return mMsgHdr->GetStatusOffset(result);
else
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsMessage::GetCharSet(nsString *result)
{
if(mMsgHdr)
return mMsgHdr->GetCharSet(result);
else
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsMessage::GetThreadParent(nsMsgKey *result)
{
if(mMsgHdr)
return mMsgHdr->GetThreadParent(result);
else
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsMessage::SetThreadParent(nsMsgKey inKey)
{
if(mMsgHdr)
return mMsgHdr->SetThreadParent(inKey);
else
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsMessage::GetMsgFolder(nsIMsgFolder **folder)
{
if(!folder)
return NS_ERROR_NULL_POINTER;
*folder = mFolder;
if(mFolder)
{
NS_ADDREF(mFolder);
return NS_OK;
}
else
return NS_ERROR_NULL_POINTER;
}
NS_IMETHODIMP nsMessage::SetMsgFolder(nsIMsgFolder *folder)
{
mFolder = folder;
//We don't want to own folder, so don't AddRef
return NS_OK;
}
NS_IMETHODIMP nsMessage::SetMsgDBHdr(nsIMsgDBHdr *hdr)
{
mMsgHdr = dont_QueryInterface(hdr);
return NS_OK;
}
NS_IMETHODIMP nsMessage::GetMsgDBHdr(nsIMsgDBHdr **hdr)
{
*hdr = mMsgHdr;
if(*hdr)
{
NS_ADDREF(*hdr);
return NS_OK;
}
else
return NS_ERROR_NULL_POINTER;
}

View File

@@ -1,113 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
/********************************************************************************************************
Interface for representing Messenger folders.
*********************************************************************************************************/
#ifndef nsMessage_h__
#define nsMessage_h__
#include "msgCore.h"
#include "nsIMessage.h" /* include the interface we are going to support */
#include "nsRDFResource.h"
#include "nsIMsgHdr.h"
#include "nsCOMPtr.h"
class NS_MSG_BASE nsMessage: public nsRDFResource, public nsIDBMessage
{
public:
nsMessage(void);
virtual ~nsMessage(void);
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIMESSAGE
NS_DECL_NSIDBMESSAGE
NS_IMETHOD Init(const char *aURI);
//nsIMsgHdr
NS_IMETHOD GetProperty(const char *propertyName, nsString &resultProperty);
NS_IMETHOD SetProperty(const char *propertyName, nsString &propertyStr);
NS_IMETHOD GetUint32Property(const char *propertyName, PRUint32 *pResult);
NS_IMETHOD SetUint32Property(const char *propertyName, PRUint32 propertyVal);
NS_IMETHOD GetNumReferences(PRUint16 *result);
NS_IMETHOD GetStringReference(PRInt32 refNum, nsCString &resultReference);
NS_IMETHOD GetDate(PRTime *result);
NS_IMETHOD SetDate(PRTime date);
NS_IMETHOD SetMessageId(const char *messageId);
NS_IMETHOD SetReferences(const char *references);
NS_IMETHOD SetCCList(const char *ccList);
NS_IMETHOD SetRecipients(const char *recipients, PRBool recipientsIsNewsgroup);
NS_IMETHOD SetRecipientsArray(const char *names, const char *addresses, PRUint32 numAddresses);
NS_IMETHOD SetCCListArray(const char *names, const char *addresses, PRUint32 numAddresses);
NS_IMETHOD SetAuthor(const char *author);
NS_IMETHOD SetSubject(const char *subject);
NS_IMETHOD SetStatusOffset(PRUint32 statusOffset);
NS_IMETHOD GetAuthor(nsString *resultAuthor);
NS_IMETHOD GetSubject(nsString *resultSubject);
NS_IMETHOD GetRecipients(nsString *resultRecipients);
NS_IMETHOD GetCCList(nsString *ccList);
NS_IMETHOD GetMessageId(nsCString *resultMessageId);
NS_IMETHOD GetMime2DecodedAuthor(nsString *resultAuthor);
NS_IMETHOD GetMime2DecodedSubject(nsString *resultSubject);
NS_IMETHOD GetMime2DecodedRecipients(nsString *resultRecipients);
NS_IMETHOD GetAuthorCollationKey(nsString *resultAuthor);
NS_IMETHOD GetSubjectCollationKey(nsString *resultSubject);
NS_IMETHOD GetRecipientsCollationKey(nsString *resultRecipients);
// flag handling routines
NS_IMETHOD GetFlags(PRUint32 *result);
NS_IMETHOD SetFlags(PRUint32 flags);
NS_IMETHOD OrFlags(PRUint32 flags, PRUint32 *result);
NS_IMETHOD AndFlags(PRUint32 flags, PRUint32 *result);
// Mark message routines
NS_IMETHOD MarkRead(PRBool bRead);
NS_IMETHOD MarkFlagged(PRBool bFlagged);
NS_IMETHOD GetMessageKey(nsMsgKey *result);
NS_IMETHOD GetThreadId(nsMsgKey *result);
NS_IMETHOD SetThreadId(nsMsgKey inKey);
NS_IMETHOD SetMessageKey(nsMsgKey inKey);
NS_IMETHOD GetMessageSize(PRUint32 *result);
NS_IMETHOD SetMessageSize(PRUint32 messageSize);
NS_IMETHOD GetLineCount(PRUint32 *result);
NS_IMETHOD SetLineCount(PRUint32 lineCount);
NS_IMETHOD SetPriority(nsMsgPriority priority);
NS_IMETHOD SetPriority(const char *priority);
NS_IMETHOD GetMessageOffset(PRUint32 *result);
NS_IMETHOD GetStatusOffset(PRUint32 *result);
NS_IMETHOD GetCharSet(nsString *result);
NS_IMETHOD GetPriority(nsMsgPriority *result);
NS_IMETHOD GetThreadParent(nsMsgKey *result);
NS_IMETHOD SetThreadParent(nsMsgKey inKey);
protected:
nsIMsgFolder *mFolder;
nsCOMPtr<nsIMsgDBHdr> mMsgHdr;
};
#endif //nsMessage_h__

View File

@@ -1,530 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "msgCore.h"
#include "nsIMessage.h"
#include "nsMsgDBFolder.h"
#include "nsMsgFolderFlags.h"
#include "nsIPref.h"
#include "nsIMsgFolderCache.h"
#include "nsIMsgFolderCacheElement.h"
#include "nsIMsgMailSession.h"
#include "nsMsgBaseCID.h"
#include "nsIMsgMailNewsUrl.h"
static NS_DEFINE_CID(kPrefServiceCID, NS_PREF_CID);
static NS_DEFINE_CID(kMsgMailSessionCID, NS_MSGMAILSESSION_CID);
NS_IMPL_ADDREF_INHERITED(nsMsgDBFolder, nsMsgFolder)
NS_IMPL_RELEASE_INHERITED(nsMsgDBFolder, nsMsgFolder)
NS_IMETHODIMP nsMsgDBFolder::QueryInterface(REFNSIID aIID, void** aInstancePtr)
{
if (!aInstancePtr) return NS_ERROR_NULL_POINTER;
*aInstancePtr = nsnull;
if (aIID.Equals(nsCOMTypeInfo<nsIDBChangeListener>::GetIID()))
{
*aInstancePtr = NS_STATIC_CAST(nsIDBChangeListener*, this);
}
else if (aIID.Equals(nsCOMTypeInfo<nsIUrlListener>::GetIID()))
{
*aInstancePtr = NS_STATIC_CAST(nsIUrlListener*, this);
}
if(*aInstancePtr)
{
AddRef();
return NS_OK;
}
return nsRDFResource::QueryInterface(aIID, aInstancePtr);
}
nsMsgDBFolder::nsMsgDBFolder(void)
: mCharset(""), mAddListener(PR_TRUE)
{
}
nsMsgDBFolder::~nsMsgDBFolder(void)
{
if(mDatabase)
{
mDatabase->RemoveListener(this);
mDatabase->Close(PR_TRUE);
}
}
NS_IMETHODIMP nsMsgDBFolder::StartFolderLoading(void)
{
if(mDatabase)
mDatabase->RemoveListener(this);
mAddListener = PR_FALSE;
return NS_OK;
}
NS_IMETHODIMP nsMsgDBFolder::EndFolderLoading(void)
{
if(mDatabase)
mDatabase->AddListener(this);
mAddListener = PR_TRUE;
return NS_OK;
}
NS_IMETHODIMP nsMsgDBFolder::GetThreads(nsISimpleEnumerator** threadEnumerator)
{
nsresult rv = GetDatabase();
if(NS_SUCCEEDED(rv))
return mDatabase->EnumerateThreads(threadEnumerator);
else
return rv;
}
NS_IMETHODIMP
nsMsgDBFolder::GetThreadForMessage(nsIMessage *message, nsIMsgThread **thread)
{
nsresult rv = GetDatabase();
if(NS_SUCCEEDED(rv))
{
nsCOMPtr<nsIMsgDBHdr> msgDBHdr;
nsCOMPtr<nsIDBMessage> dbMessage(do_QueryInterface(message, &rv));
if(NS_SUCCEEDED(rv))
rv = dbMessage->GetMsgDBHdr(getter_AddRefs(msgDBHdr));
if(NS_SUCCEEDED(rv))
{
rv = mDatabase->GetThreadContainingMsgHdr(msgDBHdr, thread);
}
}
return rv;
}
NS_IMETHODIMP
nsMsgDBFolder::HasMessage(nsIMessage *message, PRBool *hasMessage)
{
if(!hasMessage)
return NS_ERROR_NULL_POINTER;
nsresult rv = GetDatabase();
if(NS_SUCCEEDED(rv))
{
nsCOMPtr<nsIMsgDBHdr> msgDBHdr, msgDBHdrForKey;
nsCOMPtr<nsIDBMessage> dbMessage(do_QueryInterface(message, &rv));
nsMsgKey key;
if(NS_SUCCEEDED(rv))
rv = dbMessage->GetMsgDBHdr(getter_AddRefs(msgDBHdr));
if(NS_SUCCEEDED(rv))
rv = msgDBHdr->GetMessageKey(&key);
if(NS_SUCCEEDED(rv))
rv = mDatabase->ContainsKey(key, hasMessage);
}
return rv;
}
NS_IMETHODIMP nsMsgDBFolder::GetCharset(PRUnichar * *aCharset)
{
nsresult rv = NS_OK;
if(!aCharset)
return NS_ERROR_NULL_POINTER;
if(mCharset == "")
{
NS_WITH_SERVICE(nsIPref, prefs, kPrefServiceCID, &rv);
char *prefCharset = nsnull;
if (NS_SUCCEEDED(rv))
{
rv = prefs->CopyCharPref("intl.character_set_name", &prefCharset);
}
nsString prefCharsetStr;
if(prefCharset)
{
prefCharsetStr = prefCharset;
PR_Free(prefCharset);
}
else
{
prefCharsetStr = "us-ascii";
}
*aCharset = prefCharsetStr.ToNewUnicode();
}
else
{
*aCharset = mCharset.ToNewUnicode();
}
return rv;
}
NS_IMETHODIMP nsMsgDBFolder::SetCharset(const PRUnichar * aCharset)
{
nsresult rv;
nsCOMPtr<nsIDBFolderInfo> folderInfo;
nsCOMPtr<nsIMsgDatabase> db;
rv = GetDBFolderInfoAndDB(getter_AddRefs(folderInfo), getter_AddRefs(db));
if(NS_SUCCEEDED(rv))
{
nsString charset(aCharset);
rv = folderInfo->SetCharacterSet(&charset);
db->Commit(nsMsgDBCommitType::kLargeCommit);
}
return rv;
}
nsresult nsMsgDBFolder::ReadDBFolderInfo(PRBool force)
{
// Since it turns out to be pretty expensive to open and close
// the DBs all the time, if we have to open it once, get everything
// we might need while we're here
nsresult result;
nsCOMPtr <nsIMsgFolderCache> folderCache;
NS_WITH_SERVICE(nsIMsgMailSession, mailSession, kMsgMailSessionCID, &result);
if(NS_SUCCEEDED(result))
{
result = mailSession->GetFolderCache(getter_AddRefs(folderCache));
if (NS_SUCCEEDED(result) && folderCache)
{
char *uri;
result = GetURI(&uri);
if (NS_SUCCEEDED(result) && uri)
{
nsCOMPtr <nsIMsgFolderCacheElement> cacheElement;
result = folderCache->GetCacheElement(uri, PR_FALSE, getter_AddRefs(cacheElement));
if (NS_SUCCEEDED(result) && cacheElement)
{
result = ReadFromFolderCache(cacheElement);
}
PR_Free(uri);
}
}
}
// if (m_master->InitFolderFromCache (this))
// return err;
if (force || !(mPrefFlags & MSG_FOLDER_PREF_CACHED))
{
nsCOMPtr<nsIDBFolderInfo> folderInfo;
nsCOMPtr<nsIMsgDatabase> db;
result = GetDBFolderInfoAndDB(getter_AddRefs(folderInfo), getter_AddRefs(db));
if(NS_SUCCEEDED(result))
{
mIsCachable = PR_TRUE;
if (folderInfo)
{
folderInfo->GetFlags(&mPrefFlags);
mPrefFlags |= MSG_FOLDER_PREF_CACHED;
folderInfo->SetFlags(mPrefFlags);
folderInfo->GetNumMessages(&mNumTotalMessages);
folderInfo->GetNumNewMessages(&mNumUnreadMessages);
//These should be put in IMAP folder only.
//folderInfo->GetImapTotalPendingMessages(&mNumPendingTotalMessages);
//folderInfo->GetImapUnreadPendingMessages(&mNumPendingUnreadMessages);
folderInfo->GetCharacterSet(&mCharset);
if (db) {
PRBool hasnew;
nsresult rv;
rv = db->HasNew(&hasnew);
if (NS_FAILED(rv)) return rv;
if (!hasnew && mNumPendingUnreadMessages <= 0) {
ClearFlag(MSG_FOLDER_FLAG_GOT_NEW);
}
}
}
}
if (db)
db->Close(PR_FALSE);
}
return result;
}
nsresult nsMsgDBFolder::SendFlagNotifications(nsISupports *item, PRUint32 oldFlags, PRUint32 newFlags)
{
nsresult rv = NS_OK;
PRUint32 changedFlags = oldFlags ^ newFlags;
if((changedFlags & MSG_FLAG_READ) || (changedFlags & MSG_FLAG_REPLIED)
|| (changedFlags & MSG_FLAG_FORWARDED)|| (changedFlags & MSG_FLAG_NEW))
{
rv = NotifyPropertyFlagChanged(item, "Status", oldFlags, newFlags);
}
else if((changedFlags & MSG_FLAG_MARKED))
{
rv = NotifyPropertyFlagChanged(item, "Flagged", oldFlags, newFlags);
}
return rv;
}
NS_IMETHODIMP
nsMsgDBFolder::GetMsgDatabase(nsIMsgDatabase** aMsgDatabase)
{
if (!aMsgDatabase || !mDatabase)
return NS_ERROR_NULL_POINTER;
*aMsgDatabase = mDatabase;
NS_ADDREF(*aMsgDatabase);
return NS_OK;
}
NS_IMETHODIMP nsMsgDBFolder::OnKeyChange(nsMsgKey aKeyChanged, PRUint32 aOldFlags, PRUint32 aNewFlags,
nsIDBChangeListener * aInstigator)
{
nsCOMPtr<nsIMsgDBHdr> pMsgDBHdr;
nsresult rv = mDatabase->GetMsgHdrForKey(aKeyChanged, getter_AddRefs(pMsgDBHdr));
if(NS_SUCCEEDED(rv) && pMsgDBHdr)
{
nsCOMPtr<nsIMessage> message;
rv = CreateMessageFromMsgDBHdr(pMsgDBHdr, getter_AddRefs(message));
if(NS_SUCCEEDED(rv))
{
nsCOMPtr<nsISupports> msgSupports(do_QueryInterface(message, &rv));
if(NS_SUCCEEDED(rv))
{
SendFlagNotifications(msgSupports, aOldFlags, aNewFlags);
}
UpdateSummaryTotals(PR_TRUE);
}
}
return NS_OK;
}
NS_IMETHODIMP nsMsgDBFolder::OnKeyDeleted(nsMsgKey aKeyChanged, nsMsgKey aParentKey, PRInt32 aFlags,
nsIDBChangeListener * aInstigator)
{
nsCOMPtr<nsIMsgDBHdr> pMsgDBHdr;
nsresult rv = mDatabase->GetMsgHdrForKey(aKeyChanged, getter_AddRefs(pMsgDBHdr));
if(NS_SUCCEEDED(rv) && pMsgDBHdr)
{
nsCOMPtr<nsIMessage> message;
rv = CreateMessageFromMsgDBHdr(pMsgDBHdr, getter_AddRefs(message));
if(NS_SUCCEEDED(rv))
{
nsCOMPtr<nsISupports> msgSupports(do_QueryInterface(message, &rv));
if(NS_SUCCEEDED(rv))
{
NotifyItemDeleted(msgSupports);
}
UpdateSummaryTotals(PR_TRUE);
}
}
return NS_OK;
}
NS_IMETHODIMP nsMsgDBFolder::OnKeyAdded(nsMsgKey aKeyChanged, nsMsgKey aParentKey , PRInt32 aFlags,
nsIDBChangeListener * aInstigator)
{
nsresult rv;
nsCOMPtr<nsIMsgDBHdr> msgDBHdr;
rv = mDatabase->GetMsgHdrForKey(aKeyChanged, getter_AddRefs(msgDBHdr));
if(NS_SUCCEEDED(rv) && msgDBHdr)
{
nsCOMPtr<nsIMessage> message;
rv = CreateMessageFromMsgDBHdr(msgDBHdr, getter_AddRefs(message));
if(NS_SUCCEEDED(rv))
{
nsCOMPtr<nsISupports> msgSupports(do_QueryInterface(message));
if(msgSupports)
{
NotifyItemAdded(msgSupports);
}
UpdateSummaryTotals(PR_TRUE);
}
}
return NS_OK;
}
NS_IMETHODIMP nsMsgDBFolder::OnParentChanged(nsMsgKey aKeyChanged, nsMsgKey oldParent, nsMsgKey newParent,
nsIDBChangeListener * aInstigator)
{
return NS_OK;
}
NS_IMETHODIMP nsMsgDBFolder::OnAnnouncerGoingAway(nsIDBChangeAnnouncer *
instigator)
{
if (mDatabase)
{
mDatabase->RemoveListener(this);
mDatabase = null_nsCOMPtr();
}
return NS_OK;
}
NS_IMETHODIMP nsMsgDBFolder::ManyHeadersToDownload(PRBool *retval)
{
PRInt32 numTotalMessages;
if (!retval)
return NS_ERROR_NULL_POINTER;
if (!mDatabase)
*retval = PR_TRUE;
else if (NS_SUCCEEDED(GetTotalMessages(PR_FALSE, &numTotalMessages)) && numTotalMessages <= 0)
*retval = PR_TRUE;
else
*retval = PR_FALSE;
return NS_OK;
}
nsresult nsMsgDBFolder::ReadFromFolderCache(nsIMsgFolderCacheElement *element)
{
nsresult rv = NS_OK;
char *charset;
element->GetInt32Property("flags", &mPrefFlags);
element->GetInt32Property("totalMsgs", &mNumTotalMessages);
element->GetInt32Property("totalUnreadMsgs", &mNumUnreadMessages);
element->GetStringProperty("charset", &charset);
#ifdef DEBUG_bienvenu1
char *uri;
GetURI(&uri);
printf("read total %ld for %s\n", mNumTotalMessages, uri);
PR_Free(uri);
#endif
mCharset = charset;
PR_FREEIF(charset);
mPrefFlags |= MSG_FOLDER_PREF_CACHED;
return rv;
}
NS_IMETHODIMP nsMsgDBFolder::WriteToFolderCache(nsIMsgFolderCache *folderCache)
{
nsCOMPtr <nsIEnumerator> aEnumerator;
nsresult rv = GetSubFolders(getter_AddRefs(aEnumerator));
if(NS_FAILED(rv))
return rv;
char *uri = nsnull;
rv = GetURI(&uri);
if (folderCache)
{
nsCOMPtr <nsIMsgFolderCacheElement> cacheElement;
rv = folderCache->GetCacheElement(uri, PR_TRUE, getter_AddRefs(cacheElement));
if (NS_SUCCEEDED(rv) && cacheElement)
rv = WriteToFolderCacheElem(cacheElement);
}
PR_FREEIF(uri);
nsCOMPtr<nsISupports> aItem;
rv = aEnumerator->First();
if (!NS_SUCCEEDED(rv))
return NS_OK; // it's OK, there are no sub-folders.
while(NS_SUCCEEDED(rv))
{
rv = aEnumerator->CurrentItem(getter_AddRefs(aItem));
if (NS_FAILED(rv)) break;
nsCOMPtr<nsIMsgFolder> aMsgFolder(do_QueryInterface(aItem, &rv));
if (NS_SUCCEEDED(rv))
{
if (folderCache)
{
rv = aMsgFolder->WriteToFolderCache(folderCache);
if (!NS_SUCCEEDED(rv))
break;
}
}
rv = aEnumerator->Next();
if (!NS_SUCCEEDED(rv))
{
rv = NS_OK;
break;
}
}
return rv;
}
NS_IMETHODIMP nsMsgDBFolder::WriteToFolderCacheElem(nsIMsgFolderCacheElement *element)
{
nsresult rv = NS_OK;
element->SetInt32Property("flags", mPrefFlags);
element->SetInt32Property("totalMsgs", mNumTotalMessages);
element->SetInt32Property("totalUnreadMsgs", mNumUnreadMessages);
element->SetStringProperty("charset", (const char *) nsCAutoString(mCharset));
#ifdef DEBUG_bienvenu1
char *uri;
GetURI(&uri);
printf("writing total %ld for %s\n", mNumTotalMessages, uri);
PR_Free(uri);
#endif
return rv;
}
NS_IMETHODIMP
nsMsgDBFolder::MarkAllMessagesRead(void)
{
nsresult rv = GetDatabase();
if(NS_SUCCEEDED(rv))
return mDatabase->MarkAllRead(nsnull);
return rv;
}
NS_IMETHODIMP
nsMsgDBFolder::OnStartRunningUrl(nsIURI *aUrl)
{
NS_PRECONDITION(aUrl, "just a sanity check");
return NS_OK;
}
NS_IMETHODIMP
nsMsgDBFolder::OnStopRunningUrl(nsIURI *aUrl, nsresult aExitCode)
{
NS_PRECONDITION(aUrl, "just a sanity check");
nsCOMPtr<nsIMsgMailNewsUrl> mailUrl = do_QueryInterface(aUrl);
if (mailUrl)
{
PRBool updatingFolder = PR_FALSE;
if (NS_SUCCEEDED(mailUrl->GetUpdatingFolder(&updatingFolder)) && updatingFolder)
{
NotifyFolderLoaded();
}
}
return NS_OK;
}

View File

@@ -1,80 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef nsMsgDBFolder_h__
#define nsMsgDBFolder_h__
#include "msgCore.h"
#include "nsMsgFolder.h"
#include "nsIDBFolderInfo.h"
#include "nsIMsgDatabase.h"
#include "nsIMessage.h"
#include "nsCOMPtr.h"
#include "nsIDBChangeListener.h"
#include "nsIUrlListener.h"
class nsIMsgFolderCacheElement;
/*
* nsMsgDBFolder
* class derived from nsMsgFolder for those folders that use an nsIMsgDatabase
*/
class NS_MSG_BASE nsMsgDBFolder: public nsMsgFolder,
public nsIDBChangeListener,
public nsIUrlListener
{
public:
nsMsgDBFolder(void);
virtual ~nsMsgDBFolder(void);
NS_DECL_NSIDBCHANGELISTENER
NS_IMETHOD StartFolderLoading(void);
NS_IMETHOD EndFolderLoading(void);
NS_IMETHOD GetThreads(nsISimpleEnumerator** threadEnumerator);
NS_IMETHOD GetThreadForMessage(nsIMessage *message, nsIMsgThread **thread);
NS_IMETHOD HasMessage(nsIMessage *message, PRBool *hasMessage);
NS_IMETHOD GetCharset(PRUnichar * *aCharset);
NS_IMETHOD SetCharset(const PRUnichar * aCharset);
NS_IMETHOD GetMsgDatabase(nsIMsgDatabase** aMsgDatabase);
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIURLLISTENER
NS_IMETHOD WriteToFolderCache(nsIMsgFolderCache *folderCache);
NS_IMETHOD WriteToFolderCacheElem(nsIMsgFolderCacheElement *element);
NS_IMETHOD ManyHeadersToDownload(PRBool *_retval);
NS_IMETHOD MarkAllMessagesRead(void);
protected:
virtual nsresult ReadDBFolderInfo(PRBool force);
virtual nsresult GetDatabase() = 0;
virtual nsresult SendFlagNotifications(nsISupports *item, PRUint32 oldFlags, PRUint32 newFlags);
nsresult ReadFromFolderCache(nsIMsgFolderCacheElement *element);
protected:
nsCOMPtr<nsIMsgDatabase> mDatabase;
nsString mCharset;
PRBool mAddListener;
};
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,268 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
/********************************************************************************************************
Interface for representing Messenger folders.
*********************************************************************************************************/
#ifndef nsMsgFolder_h__
#define nsMsgFolder_h__
#include "msgCore.h"
#include "nsIMsgFolder.h" /* include the interface we are going to support */
#include "nsRDFResource.h"
#include "nsIDBFolderInfo.h"
#include "nsIMsgDatabase.h"
#include "nsIMsgIncomingServer.h"
#include "nsCOMPtr.h"
#include "nsIURL.h"
/*
* MsgFolder
*/
class NS_MSG_BASE nsMsgFolder: public nsRDFResource, public nsIMsgFolder
{
public:
nsMsgFolder(void);
virtual ~nsMsgFolder(void);
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSICOLLECTION
NS_DECL_NSIFOLDER
// eventually this will be an instantiable class, and we should
// use this macro:
// NS_DECL_NSIMSGFOLDER
// right now a few of these methods are left abstract, and
// are commented out below
// begin NS_DECL_NSIMSGFOLDER
NS_IMETHOD AddUnique(nsISupports *element);
NS_IMETHOD ReplaceElement(nsISupports *element, nsISupports *newElement);
NS_IMETHOD GetMessages(nsISimpleEnumerator **_retval);
NS_IMETHOD GetThreads(nsISimpleEnumerator **_retval);
NS_IMETHOD StartFolderLoading(void);
NS_IMETHOD EndFolderLoading(void);
NS_IMETHOD UpdateFolder(void);
NS_IMETHOD GetThreadForMessage(nsIMessage *message, nsIMsgThread **_retval);
NS_IMETHOD HasMessage(nsIMessage *message, PRBool *_retval);
NS_IMETHOD GetVisibleSubFolders(nsIEnumerator **_retval);
NS_IMETHOD GetPrettiestName(PRUnichar * *aPrettiestName);
NS_IMETHOD GetFolderURL(char * *aFolderURL);
NS_IMETHOD GetDeleteIsMoveToTrash(PRBool *aDeleteIsMoveToTrash);
NS_IMETHOD GetShowDeletedMessages(PRBool *aShowDeletedMessages);
NS_IMETHOD GetServer(nsIMsgIncomingServer * *aServer);
NS_IMETHOD GetIsServer(PRBool *aIsServer);
NS_IMETHOD OnCloseFolder(void);
NS_IMETHOD Delete(void);
NS_IMETHOD DeleteSubFolders(nsISupportsArray *folders);
NS_IMETHOD PropagateDelete(nsIMsgFolder *folder, PRBool deleteStorage);
NS_IMETHOD RecursiveDelete(PRBool deleteStorage);
NS_IMETHOD CreateSubfolder(const char *folderName);
NS_IMETHOD Compact(void);
NS_IMETHOD EmptyTrash(void);
NS_IMETHOD Rename(const char *name);
NS_IMETHOD Adopt(nsIMsgFolder *srcFolder, PRUint32 *outPos);
NS_IMETHOD ContainsChildNamed(const char *name, PRBool *_retval);
NS_IMETHOD IsAncestorOf(nsIMsgFolder *folder, PRBool *_retval);
NS_IMETHOD GenerateUniqueSubfolderName(const char *prefix, nsIMsgFolder *otherFolder, char **_retval);
NS_IMETHOD UpdateSummaryTotals(PRBool force);
NS_IMETHOD SummaryChanged(void);
NS_IMETHOD GetNumUnread(PRBool deep, PRInt32 *_retval);
NS_IMETHOD GetTotalMessages(PRBool deep, PRInt32 *_retval);
NS_IMETHOD GetExpungedBytesCount(PRUint32 *aExpungedBytesCount);
NS_IMETHOD GetDeletable(PRBool *aDeletable);
NS_IMETHOD GetCanCreateChildren(PRBool *aCanCreateChildren);
NS_IMETHOD GetCanBeRenamed(PRBool *aCanBeRenamed);
NS_IMETHOD GetRequiresCleanup(PRBool *aRequiresCleanup);
NS_IMETHOD ClearRequiresCleanup(void);
NS_IMETHOD ManyHeadersToDownload(PRBool *_retval);
NS_IMETHOD GetKnowsSearchNntpExtension(PRBool *aKnowsSearchNntpExtension);
NS_IMETHOD GetAllowsPosting(PRBool *aAllowsPosting);
NS_IMETHOD GetDisplayRecipients(PRBool *aDisplayRecipients);
NS_IMETHOD GetRelativePathName(char * *aRelativePathName);
NS_IMETHOD GetSizeOnDisk(PRUint32 *aSizeOnDisk);
NS_IMETHOD RememberPassword(const char *password);
NS_IMETHOD GetRememberedPassword(char * *aRememberedPassword);
NS_IMETHOD UserNeedsToAuthenticateForFolder(PRBool displayOnly, PRBool *_retval);
NS_IMETHOD GetUsername(char * *aUsername);
NS_IMETHOD GetHostname(char * *aHostname);
NS_IMETHOD SetFlag(PRUint32 flag);
NS_IMETHOD ClearFlag(PRUint32 flag);
NS_IMETHOD GetFlag(PRUint32 flag, PRBool *_retval);
NS_IMETHOD ToggleFlag(PRUint32 flag);
NS_IMETHOD OnFlagChange(PRUint32 flag);
NS_IMETHOD GetFlags(PRUint32 *aFlags);
NS_IMETHOD GetFoldersWithFlag(PRUint32 flags, nsIMsgFolder **result, PRUint32 resultsize, PRUint32 *numFolders);
NS_IMETHOD GetExpansionArray(nsISupportsArray *expansionArray);
// NS_IMETHOD DeleteMessages(nsISupportsArray *message, nsITransactionManager *txnMgr, PRBool deleteStorage);
NS_IMETHOD CopyMessages(nsIMsgFolder *srcFolder, nsISupportsArray *messages, PRBool isMove, nsITransactionManager *txnMgr, nsIMsgCopyServiceListener *listener);
NS_IMETHOD CopyFileMessage(nsIFileSpec *fileSpec, nsIMessage *msgToReplace, PRBool isDraft, nsITransactionManager *txnMgr, nsIMsgCopyServiceListener *listener);
NS_IMETHOD AcquireSemaphore(nsISupports *semHolder);
NS_IMETHOD ReleaseSemaphore(nsISupports *semHolder);
NS_IMETHOD TestSemaphore(nsISupports *semHolder, PRBool *_retval);
NS_IMETHOD GetLocked(PRBool *aLocked);
// NS_IMETHOD CreateMessageFromMsgDBHdr(nsIMsgDBHdr *msgDBHdr, nsIMessage **_retval);
NS_IMETHOD GetNewMessages(void);
// NS_IMETHOD WriteToFolderCache(nsIMsgFolderCache *folderCache);
// NS_IMETHOD GetCharset(PRUnichar * *aCharset);
// NS_IMETHOD SetCharset(const PRUnichar * aCharset);
NS_IMETHOD GetBiffState(PRUint32 *aBiffState);
NS_IMETHOD SetBiffState(PRUint32 aBiffState);
NS_IMETHOD GetNumNewMessages(PRInt32 *aNumNewMessages);
NS_IMETHOD SetNumNewMessages(PRInt32 aNumNewMessages);
NS_IMETHOD GetNewMessagesNotificationDescription(PRUnichar * *aNewMessagesNotificationDescription);
NS_IMETHOD GetRootFolder(nsIMsgFolder * *aRootFolder);
NS_IMETHOD GetMsgDatabase(nsIMsgDatabase * *aMsgDatabase);
NS_IMETHOD GetPath(nsIFileSpec * *aPath);
NS_IMETHOD MarkMessagesRead(nsISupportsArray *messages, PRBool markRead);
NS_IMETHOD MarkAllMessagesRead(void);
NS_IMETHOD MarkMessagesFlagged(nsISupportsArray *messages, PRBool markFlagged);
NS_IMETHOD GetChildWithURI(const char *uri, PRBool deep, nsIMsgFolder **_retval);
// end NS_DECL_NSIMSGFOLDER
// nsRDFResource overrides
NS_IMETHOD Init(const char* aURI);
#if 0
static nsresult GetRoot(nsIMsgFolder* *result);
#endif
// Gets the URL that represents the given message. Returns a newly
// created string that must be free'd using XP_FREE().
// If the db is NULL, then returns a URL that represents the entire
// folder as a whole.
#ifdef HAVE_DB
NS_IMETHOD BuildUrl(nsMsgDatabase *db, nsMsgKey key, char ** url);
// updates num messages and num unread - should be pure virtual
// when I get around to implementing in all subclasses?
NS_IMETHOD GetTotalMessagesInDB(PRUint32 *totalMessages) const; // How many messages in database.
// These functions are used for tricking the front end into thinking that we have more
// messages than are really in the DB. This is usually after and IMAP message copy where
// we don't want to do an expensive select until the user actually opens that folder
// These functions are called when MSG_Master::GetFolderLineById is populating a MSG_FolderLine
// struct used by the FE
int32 GetNumPendingUnread(PRBool deep = PR_FALSE);
int32 GetNumPendingTotalMessages(PRBool deep = PR_FALSE);
void ChangeNumPendingUnread(int32 delta);
void ChangeNumPendingTotalMessages(int32 delta);
NS_IMETHOD SetFolderPrefFlags(PRUint32 flags);
NS_IMETHOD GetFolderPrefFlags(PRUint32 *flags);
NS_IMETHOD SetLastMessageLoaded(nsMsgKey lastMessageLoaded);
NS_IMETHOD GetLastMessageLoaded();
#endif
#ifdef HAVE_ADMINURL
NS_IMETHOD GetAdminUrl(MWContext *context, MSG_AdminURLType type);
NS_IMETHOD HaveAdminUrl(MSG_AdminURLType type, PRBool *hadAdminUrl);
#endif
#ifdef HAVE_PANE
NS_IMETHOD MarkAllRead(MSG_Pane *pane, PRBool deep);
NS_IMETHOD SetFlagInAllFolderPanes(PRUint32 which);
#endif
#ifdef HAVE_NET
NS_IMETHOD EscapeMessageId(const char *messageId, const char **escapeMessageID);
NS_IMETHOD ShouldPerformOperationOffline(PRBool *performOffline);
#endif
#ifdef HAVE_CACHE
virtual nsresult WriteToCache(XP_File);
virtual nsresult ReadFromCache(char *);
virtual PRBool IsCachable();
void SkipCacheTokens(char **ppBuf, int numTokens);
#endif
#ifdef DOES_FOLDEROPERATIONS
int DownloadToTempFileAndUpload(MessageCopyInfo *copyInfo, nsMsgKeyArray &keysToSave, MSG_FolderInfo *dstFolder, nsMsgDatabase *sourceDB);
void UpdateMoveCopyStatus(MWContext *context, PRBool isMove, int32 curMsgCount, int32 totMessages);
#endif
virtual nsresult GetDBFolderInfoAndDB(nsIDBFolderInfo **folderInfo, nsIMsgDatabase **db) = 0;
NS_IMETHOD MatchName(nsString *name, PRBool *matches);
protected:
nsresult NotifyPropertyChanged(char *property, char* oldValue, char* newValue);
nsresult NotifyPropertyFlagChanged(nsISupports *item, char *property, PRUint32 oldValue,
PRUint32 newValue);
nsresult NotifyItemAdded(nsISupports *item);
nsresult NotifyItemDeleted(nsISupports *item);
nsresult NotifyFolderLoaded();
// this is a little helper function that is not part of the public interface.
// we use it to get the IID of the incoming server for the derived folder.
// w/out a function like this we would have to implement GetServer in each
// derived folder class.
virtual const char* GetIncomingServerType() = 0;
protected:
PRUint32 mFlags;
nsIFolder *mParent; //This won't be refcounted for ownership reasons.
PRInt32 mNumUnreadMessages; /* count of unread messages (-1 means
unknown; -2 means unknown but we already
tried to find out.) */
PRInt32 mNumTotalMessages; /* count of existing messages. */
nsCOMPtr<nsISupportsArray> mSubFolders;
nsVoidArray *mListeners; //This can't be an nsISupportsArray because due to
//ownership issues, listeners can't be AddRef'd
PRInt32 mPrefFlags; // prefs like MSG_PREF_OFFLINE, MSG_PREF_ONE_PANE, etc
nsISupports *mSemaphoreHolder; // set when the folder is being written to
//Due to ownership issues, this won't be AddRef'd.
nsIMsgIncomingServer* m_server; //this won't be addrefed....ownership issue here
#ifdef HAVE_DB
nsMsgKey m_lastMessageLoaded;
#endif
// These values are used for tricking the front end into thinking that we have more
// messages than are really in the DB. This is usually after and IMAP message copy where
// we don't want to do an expensive select until the user actually opens that folder
PRInt32 mNumPendingUnreadMessages;
PRInt32 mNumPendingTotalMessages;
PRUint32 mBiffState;
PRInt32 mNumNewBiffMessages;
PRBool mIsCachable;
//
// stuff from the uri
//
PRBool mIsServer;
nsString mName;
};
#endif

View File

@@ -1,598 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "msgCore.h" // precompiled header...
#include "prlog.h"
#include "nsMsgGroupRecord.h"
#include "plstr.h"
#include "prmem.h"
#include "nsEscape.h"
#include "nsCRT.h"
// mscott: this is lame...I know....
#define MK_OUT_OF_MEMORY 1
const PRUint32 F_ISGROUP = 0x00000001;
const PRUint32 F_EXPANDED = 0x00000002;
const PRUint32 F_CATCONT = 0x00000004;
const PRUint32 F_VIRTUAL = 0x00000008;
const PRUint32 F_DIRTY = 0x00000010;
const PRUint32 F_DESCENDENTSLOADED = 0x00000020;
const PRUint32 F_HTMLOKGROUP = 0x00000040;
const PRUint32 F_HTMLOKTREE = 0x00000080;
const PRUint32 F_NEEDEXTRAINFO = 0x00000100;
const PRUint32 F_DOESNOTEXIST = 0x00000200;
const PRUint32 RUNTIMEFLAGS = // Flags to be sure *not* to write to disk.
F_DIRTY | F_DESCENDENTSLOADED | F_EXPANDED;
int
nsMsgGroupRecord::GroupNameCompare(const char* name1, const char* name2,
char delimiter, PRBool caseInsensitive)
{
if (caseInsensitive)
{
while (*name1 && (nsCRT::ToUpper(*name1) == nsCRT::ToUpper(*name2))) {
name1++;
name2++;
}
}
else
{
while (*name1 && *name1 == *name2) {
name1++;
name2++;
}
}
if (*name1 && *name2) {
if (*name1 == delimiter) return -1;
if (*name2 == delimiter) return 1;
}
if (caseInsensitive)
return int(nsCRT::ToUpper(*name1)) - int(nsCRT::ToUpper(*name2));
else
return int(*name1) - int(*name2);
}
nsMsgGroupRecord*
nsMsgGroupRecord::Create(nsMsgGroupRecord* parent, const char* partname,
PRInt64 aTime, PRInt32 uniqueid, PRInt32 fileoffset)
{
nsMsgGroupRecord* result = new nsMsgGroupRecord(parent, partname,
aTime, uniqueid, fileoffset);
if (result && partname && !result->m_partname) {
// We ran out of memory.
delete result;
result = NULL;
}
result->InitializeSibling();
return result;
}
MOZ_DECL_CTOR_COUNTER(nsMsgGroupRecord);
nsMsgGroupRecord::nsMsgGroupRecord(nsMsgGroupRecord* parent, const char* partname,
PRInt64 aTime, PRInt32 uniqueid, PRInt32 fileoffset,
char delimiter /* = '.' */)
{
MOZ_COUNT_CTOR(nsMsgGroupRecord);
int length;
m_prettyname = NULL;
m_parent = parent;
m_children = NULL;
m_sibling = NULL;
m_flags = 0;
m_partname = NULL;
m_addtime = aTime;
m_uniqueId = uniqueid;
m_fileoffset = fileoffset;
m_delimiter = delimiter;
if (partname) {
length = PL_strlen(partname);
// PR_ASSERT(parent != NULL);
m_partname = new char [length + 1];
if (!m_partname) {
m_parent = NULL;
return;
}
PL_strcpy(m_partname, partname);
}
}
nsMsgGroupRecord::~nsMsgGroupRecord()
{
MOZ_COUNT_DTOR(nsMsgGroupRecord);
delete [] m_partname;
m_partname = NULL;
delete [] m_prettyname;
m_prettyname = NULL;
while (m_children) {
delete m_children;
}
m_children = NULL;
if (m_parent) {
nsMsgGroupRecord** ptr;
for (ptr = &(m_parent->m_children);
*ptr;
ptr = &((*ptr)->m_sibling)) {
if (*ptr == this) {
*ptr = m_sibling;
break;
}
}
}
}
void nsMsgGroupRecord::InitializeSibling()
{
if (m_parent) {
PR_ASSERT(m_partname != NULL);
nsMsgGroupRecord** ptr;
for (ptr = &(m_parent->m_children) ; *ptr ; ptr = &((*ptr)->m_sibling)) {
int comp = GroupNameCompare((*ptr)->m_partname, m_partname, m_delimiter, IsIMAPGroupRecord());
PR_ASSERT(comp != 0);
if (comp >= 0) break;
}
m_sibling = *ptr;
*ptr = this;
}
}
nsMsgGroupRecord*
nsMsgGroupRecord::FindDescendant(const char* name)
{
if (!name || !*name) return this;
char* ptr = PL_strchr(name, m_delimiter);
if (ptr) *ptr = '\0';
nsMsgGroupRecord* child;
for (child = m_children ; child ; child = child->m_sibling) {
if (PL_strcmp(child->m_partname, name) == 0) {
break;
}
}
if (ptr) {
*ptr++ = m_delimiter;
if (child) {
return child->FindDescendant(ptr);
}
}
return child;
}
nsMsgGroupRecord*
nsMsgGroupRecord::GetSiblingOrAncestorSibling()
{
if (m_sibling) return m_sibling;
if (m_parent) return m_parent->GetSiblingOrAncestorSibling();
return NULL;
}
nsMsgGroupRecord*
nsMsgGroupRecord::GetNextAlphabetic()
{
nsMsgGroupRecord* result;
if (m_children) result = m_children;
else result = GetSiblingOrAncestorSibling();
#ifdef DEBUG_slowAndParanoid
if (result) {
char* ptr1 = GetFullName();
char* ptr2 = result->GetFullName();
PR_ASSERT(GroupNameCompare(ptr1, ptr2) < 0);
delete [] ptr1;
delete [] ptr2;
}
#endif
return result;
}
nsMsgGroupRecord*
nsMsgGroupRecord::GetNextAlphabeticNoCategories()
{
if (IsCategoryContainer()) {
return GetSiblingOrAncestorSibling();
} else {
return GetNextAlphabetic();
}
}
char*
nsMsgGroupRecord::GetFullName()
{
int length = 0;
nsMsgGroupRecord* ptr;
for (ptr = this ; ptr ; ptr = ptr->m_parent) {
if (ptr->m_partname) length += PL_strlen(ptr->m_partname) + 1;
}
PR_ASSERT(length > 0);
if (length <= 0) return NULL;
char* result = new char [length];
if (result) {
SuckInName(result);
PR_ASSERT(int(PL_strlen(result)) + 1 == length);
}
return result;
}
char*
nsMsgGroupRecord::SuckInName(char* ptr)
{
if (m_parent && m_parent->m_partname) {
ptr = m_parent->SuckInName(ptr);
*ptr++ = m_delimiter;
}
PL_strcpy(ptr, m_partname);
return ptr + PL_strlen(ptr);
}
int
nsMsgGroupRecord::SetPrettyName(const char* name)
{
if (name == NULL && m_prettyname == NULL) return 0;
m_flags |= F_DIRTY;
delete [] m_prettyname;
m_prettyname = NULL;
if (!name || !*name) {
return 0;
}
int length = PL_strlen(name);
m_prettyname = new char [length + 1];
if (!m_prettyname) {
return MK_OUT_OF_MEMORY;
}
PL_strcpy(m_prettyname, name);
return 1;
}
PRBool
nsMsgGroupRecord::IsCategory()
{
return GetCategoryContainer() != NULL;
}
PRBool
nsMsgGroupRecord::IsCategoryContainer()
{
return (m_flags & F_CATCONT) != 0;
}
PRBool
nsMsgGroupRecord::NeedsExtraInfo()
{
return (m_flags & F_NEEDEXTRAINFO) != 0;
}
int
nsMsgGroupRecord::SetNeedsExtraInfo(PRBool value)
{
return TweakFlag(F_NEEDEXTRAINFO, value);
}
int
nsMsgGroupRecord::SetIsCategoryContainer(PRBool value)
{
// refuse to set a group to be a category container if it has a parent
// that's a category container.
if (! (value && GetCategoryContainer()))
return TweakFlag(F_CATCONT, value);
else
return 0;
}
nsMsgGroupRecord*
nsMsgGroupRecord::GetCategoryContainer()
{
if (IsCategoryContainer()) return NULL;
for (nsMsgGroupRecord* ptr = m_parent ; ptr ; ptr = ptr->m_parent) {
if (ptr->IsCategoryContainer()) return ptr;
}
return NULL;
}
nsresult
nsMsgGroupRecord::IsVirtual(PRBool *retval)
{
*retval =( (m_flags & F_VIRTUAL) != 0);
return NS_OK;
}
nsresult
nsMsgGroupRecord::SetIsVirtual(PRBool value)
{
TweakFlag(F_VIRTUAL, value);
return NS_OK;
}
PRBool
nsMsgGroupRecord::IsExpanded()
{
return (m_flags & F_EXPANDED) != 0;
}
int
nsMsgGroupRecord::SetIsExpanded(PRBool value)
{
return TweakFlag(F_EXPANDED, value);
}
PRBool
nsMsgGroupRecord::IsHTMLOKGroup()
{
return (m_flags & F_HTMLOKGROUP) != 0;
}
int
nsMsgGroupRecord::SetIsHTMLOKGroup(PRBool value)
{
return TweakFlag(F_HTMLOKGROUP, value);
}
PRBool
nsMsgGroupRecord::IsHTMLOKTree()
{
return (m_flags & F_HTMLOKTREE) != 0;
}
int
nsMsgGroupRecord::SetIsHTMLOKTree(PRBool value)
{
return TweakFlag(F_HTMLOKTREE, value);
}
PRBool
nsMsgGroupRecord::IsGroup()
{
return (m_flags & F_ISGROUP) != 0;
}
int
nsMsgGroupRecord::SetIsGroup(PRBool value)
{
return TweakFlag(F_ISGROUP, value);
}
PRBool
nsMsgGroupRecord::IsDescendentsLoaded()
{
return (m_flags & F_DESCENDENTSLOADED) != 0;
}
int
nsMsgGroupRecord::SetIsDescendentsLoaded(PRBool value)
{
PR_ASSERT(value); // No reason we'd ever unset this.
TweakFlag(F_DESCENDENTSLOADED, PR_TRUE);
nsMsgGroupRecord* child;
for (child = m_children ; child ; child = child->m_sibling) {
child->SetIsDescendentsLoaded(value);
}
return 0;
}
PRBool nsMsgGroupRecord::DoesNotExistOnServer()
{
return (m_flags & F_DOESNOTEXIST) != 0;
}
int nsMsgGroupRecord::SetDoesNotExistOnServer(PRBool value)
{
if (value) // turn off group flag if doesn't exist on server.
TweakFlag(F_ISGROUP, PR_FALSE);
return TweakFlag(F_DOESNOTEXIST, value);
}
int
nsMsgGroupRecord::TweakFlag(PRUint32 flagbit, PRBool value)
{
if (value) {
if (!(m_flags & flagbit)) {
m_flags |= flagbit;
if (flagbit & ~RUNTIMEFLAGS)
m_flags |= F_DIRTY;
return 1;
}
} else {
if (m_flags & flagbit) {
m_flags &= ~flagbit;
if (flagbit & ~RUNTIMEFLAGS)
m_flags |= F_DIRTY;
return 1;
}
}
return 0;
}
PRInt32
nsMsgGroupRecord::GetNumKids()
{
PRInt32 result = 0;
nsMsgGroupRecord* child;
for (child = m_children ; child ; child = child->m_sibling) {
if (IsIMAPGroupRecord())
result++;
else
if (child->m_flags & F_ISGROUP) result++;
if (!IsIMAPGroupRecord())
result += child->GetNumKids();
}
return result;
}
char*
nsMsgGroupRecord::GetSaveString()
{
char* pretty = NULL;
char* result = nsnull;
if (m_prettyname) {
pretty = nsEscape(m_prettyname, url_XAlphas);
if (!pretty) return NULL;
}
char* fullname = GetFullName();
if (!fullname) return NULL; {
long nAddTime;
LL_L2I(nAddTime, m_addtime);
result = PR_smprintf("%s,%s,%lx,%lx,%lx" MSG_LINEBREAK,
fullname, pretty ? pretty : "",
(long) (m_flags & ~RUNTIMEFLAGS),
nAddTime,
(long) m_uniqueId);
}
delete [] fullname;
if (pretty) nsCRT::free(pretty);
m_flags &= ~F_DIRTY;
return result;
}
PRBool
nsMsgGroupRecord::IsDirty()
{
return (m_flags & F_DIRTY) != 0;
}
PRInt32
nsMsgGroupRecord::GetDepth()
{
PRInt32 result = 0;
nsMsgGroupRecord* tmp = m_parent;
while (tmp) {
tmp = tmp->m_parent;
result++;
}
return result;
}
nsMsgGroupRecord*
nsMsgGroupRecord::Create(nsMsgGroupRecord* parent, const char* saveline,
PRInt32 savelinelength, PRInt32 fileoffset)
{
char* tmp;
char* ptr;
char* endptr;
char* partname;
char* prettyname;
PRInt32 flags;
PRInt32 addtime;
PRInt32 uniqueid;
nsMsgGroupRecord* result = NULL;
if (savelinelength < 0) savelinelength = PL_strlen(saveline);
tmp = (char*) PR_Malloc(savelinelength + 1);
if (!tmp) return NULL;
PL_strncpy(tmp, saveline, savelinelength);
tmp[savelinelength] = '\0';
ptr = PL_strchr(tmp, ',');
PR_ASSERT(ptr);
if (!ptr) goto FAIL;
*ptr++ = '\0';
partname = PL_strrchr(tmp, '.');
if (!partname) partname = tmp;
else partname++;
#ifdef DEBUG_slowAndParanoid
if (parent->m_partname) {
char* parentname = parent->GetFullName();
PR_ASSERT(partname > tmp && partname[-1] == '.');
partname[-1] = '\0';
PR_ASSERT(PL_strcmp(parentname, tmp) == 0);
partname[-1] = '.';
delete [] parentname;
parentname = NULL;
} else {
PR_ASSERT(partname == tmp);
}
#endif
endptr = PL_strchr(ptr, ',');
PR_ASSERT(endptr);
if (!endptr) goto FAIL;
*endptr++ = '\0';
prettyname = nsUnescape(ptr);
ptr = endptr;
endptr = PL_strchr(ptr, ',');
PR_ASSERT(endptr);
if (!endptr) goto FAIL;
*endptr++ = '\0';
flags = strtol(ptr, NULL, 16);
ptr = endptr;
endptr = PL_strchr(ptr, ',');
PR_ASSERT(endptr);
if (!endptr) goto FAIL;
*endptr++ = '\0';
addtime = strtol(ptr, NULL, 16);
ptr = endptr;
uniqueid = strtol(ptr, NULL, 16);
PRInt64 llAddtime;
LL_I2L(llAddtime, addtime);
result = Create(parent, partname, llAddtime, uniqueid, fileoffset);
if (result) {
PRBool maybeCategoryContainer = flags & F_CATCONT;
flags &= ~F_CATCONT;
result->m_flags = flags;
if (maybeCategoryContainer)
result->SetIsCategoryContainer(PR_TRUE);
if (prettyname && *prettyname) result->SetPrettyName(prettyname);
}
FAIL:
PR_Free(tmp);
return result;
}

View File

@@ -1,160 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
// This class should only be used by the subscribe UI and by newshost.cpp.
// And, well, a bit by the category code. Everyone else should use the stuff
// in newshost.h.
#ifndef _nsMsgGroupRecord_h_
#define _nsMsgGroupRecord_h__
#include "msgCore.h"
#include "prtypes.h"
#include "nsISupports.h"
class nsIMAPGroupRecord;
class NS_MSG_BASE nsMsgGroupRecord {
public:
static nsMsgGroupRecord* Create(nsMsgGroupRecord* parent,
const char* partname,
PRInt64 m_addtime,
PRInt32 uniqueid,
PRInt32 fileoffset);
static nsMsgGroupRecord* Create(nsMsgGroupRecord* parent,
const char* saveline,
PRInt32 savelinelength,
PRInt32 fileoffset);
virtual void InitializeSibling();
virtual PRBool IsIMAPGroupRecord() { return PR_FALSE; }
virtual nsIMAPGroupRecord *GetIMAPGroupRecord() { return 0; }
// This is just like PL_strcmp(), except it works on news group names.
// A container groupname is always less than any contained groups.
// So, "netscape.devs-client-technical" > "netscape.devs.directory", even
// though PL_strcmp says otherwise. (YICK!)
static int GroupNameCompare(const char* name1,
const char* name2,
char delimiter = '.',
PRBool caseInsensitive = PR_FALSE);
virtual ~nsMsgGroupRecord();
nsMsgGroupRecord* FindDescendant(const char* name);
nsMsgGroupRecord* GetParent() {return m_parent;}
nsMsgGroupRecord* GetChildren() {return m_children;}
nsMsgGroupRecord* GetSibling() {return m_sibling;}
nsMsgGroupRecord* GetSiblingOrAncestorSibling();
nsMsgGroupRecord* GetNextAlphabetic();
nsMsgGroupRecord* GetNextAlphabeticNoCategories();
const char* GetPartName() {return m_partname;}
// The resulting string must be free'd using delete[].
char* GetFullName();
const char* GetPrettyName() {return m_prettyname;}
int SetPrettyName(const char* prettyname);
PRInt64 GetAddTime() {return m_addtime;}
virtual PRBool IsCategory();
virtual PRBool IsCategoryContainer();
virtual int SetIsCategoryContainer(PRBool value);
nsMsgGroupRecord* GetCategoryContainer();
// Get/Set whether this is a virtual newsgroup.
nsresult IsVirtual(PRBool *retval);
nsresult SetIsVirtual(PRBool value);
// Get/Set whether this is really a newsgroup (and not just a container
// for newsgroups).
virtual PRBool IsGroup();
int SetIsGroup(PRBool value);
PRBool IsDescendentsLoaded();
int SetIsDescendentsLoaded(PRBool value);
PRBool IsExpanded();
int SetIsExpanded(PRBool value);
PRBool IsHTMLOKGroup();
int SetIsHTMLOKGroup(PRBool value);
PRBool IsHTMLOKTree();
int SetIsHTMLOKTree(PRBool value);
PRBool NeedsExtraInfo();
int SetNeedsExtraInfo(PRBool value);
PRBool DoesNotExistOnServer();
int SetDoesNotExistOnServer(PRBool value);
PRInt32 GetUniqueID() {return m_uniqueId;}
PRInt32 GetFileOffset() {return m_fileoffset;}
int SetFileOffset(PRInt32 value) {m_fileoffset = value; return 0;}
// Get the number of descendents (not including ourself) that are
// really newsgroups.
PRInt32 GetNumKids();
// Gets the string that represents this group in the save file. The
// resulting string must be free'd with PR_Free().
char* GetSaveString();
PRBool IsDirty(); // Whether this record has had changes made
// to it. Cleared by calls to GetSaveString().
PRInt32 GetDepth(); // Returns how deep in the heirarchy we are.
// Basically, the number of dots in the full
// newsgroup name, plus 1.
virtual char GetHierarchySeparator() { return '.'; }
protected:
nsMsgGroupRecord(nsMsgGroupRecord* parent,
const char* partname,
PRInt64 m_addtime,
PRInt32 uniqueid,
PRInt32 fileoffset,
char delimiter = '.');
int TweakFlag(PRUint32 flagbit, PRBool value);
char* SuckInName(char* ptr);
char* m_partname;
char* m_prettyname;
nsMsgGroupRecord* m_parent;
nsMsgGroupRecord* m_children;
nsMsgGroupRecord* m_sibling;
PRUint32 m_flags;
PRInt64 m_addtime;
PRInt32 m_uniqueId;
PRInt32 m_fileoffset;
char m_delimiter;
};
#endif /* _grec_h_ */

View File

@@ -1,363 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
// as does this
#define NS_IMPL_IDS
#include "nsIServiceManager.h"
#include "nsICharsetConverterManager.h"
#include "nsISupports.h"
#include "nsIPref.h"
#include "nsIMimeConverter.h"
#include "msgCore.h"
#include "rosetta_mailnews.h"
#include "nsMsgI18N.h"
#include "nsFileSpec.h"
#include "nsFileStream.h"
#include "nsMsgMimeCID.h"
#include "nsMimeTypes.h"
#include "nsIEntityConverter.h"
#include "nsISaveAsCharset.h"
static NS_DEFINE_CID(kPrefCID, NS_PREF_CID);
static NS_DEFINE_CID(kCMimeConverterCID, NS_MIME_CONVERTER_CID);
static NS_DEFINE_CID(kCharsetConverterManagerCID, NS_ICHARSETCONVERTERMANAGER_CID);
static NS_DEFINE_CID(kEntityConverterCID, NS_ENTITYCONVERTER_CID);
static NS_DEFINE_CID(kSaveAsCharsetCID, NS_SAVEASCHARSET_CID);
//
// International functions necessary for composition
//
// Convert an unicode string to a C string with a given charset.
nsresult ConvertFromUnicode(const nsString& aCharset,
const nsString& inString,
char** outCString)
{
nsresult res;
NS_WITH_SERVICE(nsICharsetConverterManager, ccm, kCharsetConverterManagerCID, &res);
if(NS_SUCCEEDED(res) && (nsnull != ccm)) {
nsIUnicodeEncoder* encoder = nsnull;
nsString convCharset;
// map to converter charset
if (aCharset.EqualsIgnoreCase("us-ascii")) {
convCharset.SetString("iso-8859-1");
}
else {
convCharset = aCharset;
}
// get an unicode converter
res = ccm->GetUnicodeEncoder(&convCharset, &encoder);
if(NS_SUCCEEDED(res) && (nsnull != encoder)) {
PRUnichar *unichars = (PRUnichar *) inString.GetUnicode();
PRInt32 unicharLength = inString.Length();
PRInt32 dstLength;
res = encoder->GetMaxLength(unichars, unicharLength, &dstLength);
// allocale an output buffer
*outCString = (char *) PR_Malloc(dstLength + 1);
if (nsnull != *outCString) {
PRInt32 oldUnicharLength = unicharLength;
char *tempCString = *outCString;
PRInt32 totalCLength = 0;
while (1) {
res = encoder->Convert(unichars, &unicharLength, tempCString, &dstLength);
// increment for destination
tempCString += dstLength;
totalCLength += dstLength;
// break: this is usually the case
// source length <= zero and no error or unrecoverable error
if (0 >= unicharLength || NS_ERROR_UENC_NOMAPPING != res) {
break;
}
// could not map unicode to the destination charset, skip one unichar and continue
// increment for source unicode, skip one unichar
unichars += unicharLength + 1;
oldUnicharLength -= (unicharLength + 1);
unicharLength = oldUnicharLength;
// estimate target length again
(void) encoder->GetMaxLength(unichars, unicharLength, &dstLength);
}
(*outCString)[totalCLength] = '\0';
}
else {
res = NS_ERROR_OUT_OF_MEMORY;
}
NS_IF_RELEASE(encoder);
}
}
return res;
}
// Convert a C string to an unicode string.
nsresult ConvertToUnicode(const nsString& aCharset,
const char* inCString,
nsString& outString)
{
nsresult res;
NS_WITH_SERVICE(nsICharsetConverterManager, ccm, kCharsetConverterManagerCID, &res);
if(NS_SUCCEEDED(res) && (nsnull != ccm)) {
nsIUnicodeDecoder* decoder = nsnull;
PRUnichar *unichars;
PRInt32 unicharLength;
nsString convCharset;
// map to converter charset
if (aCharset.EqualsIgnoreCase("us-ascii")) {
convCharset.SetString("iso-8859-1");
}
else {
convCharset = aCharset;
}
// get an unicode converter
res = ccm->GetUnicodeDecoder(&convCharset, &decoder);
if(NS_SUCCEEDED(res) && (nsnull != decoder)) {
PRInt32 srcLen = PL_strlen(inCString);
res = decoder->GetMaxLength(inCString, srcLen, &unicharLength);
// allocale an output buffer
unichars = (PRUnichar *) PR_Malloc(unicharLength * sizeof(PRUnichar));
if (unichars != nsnull) {
// convert to unicode
res = decoder->Convert(inCString, &srcLen, unichars, &unicharLength);
outString.SetString(unichars, unicharLength);
PR_Free(unichars);
}
else {
res = NS_ERROR_OUT_OF_MEMORY;
}
NS_IF_RELEASE(decoder);
}
}
return res;
}
// Charset to be used for the internatl processing.
const char *msgCompHeaderInternalCharset()
{
// UTF-8 is a super set of us-ascii.
// We can use the same string manipulation methods as us-ascii without breaking non us-ascii characters.
return "UTF-8";
}
// MIME encoder, output string should be freed by PR_FREE
char * nsMsgI18NEncodeMimePartIIStr(const char *header, const char *charset, PRBool bUseMime)
{
// No MIME, just duplicate the string.
if (PR_FALSE == bUseMime) {
return PL_strdup(header);
}
char *encodedString = nsnull;
nsIMimeConverter *converter;
nsresult res = nsComponentManager::CreateInstance(kCMimeConverterCID, nsnull,
nsCOMTypeInfo<nsIMimeConverter>::GetIID(), (void **)&converter);
if (NS_SUCCEEDED(res) && nsnull != converter) {
res = converter->EncodeMimePartIIStr_UTF8(header, charset, kMIME_ENCODED_WORD_SIZE, &encodedString);
NS_RELEASE(converter);
}
return NS_SUCCEEDED(res) ? encodedString : nsnull;
}
// MIME decoder
nsresult nsMsgI18NDecodeMimePartIIStr(const nsString& header, nsString& charset, nsString& decodedString)
{
nsIMimeConverter *converter;
nsresult res = nsComponentManager::CreateInstance(kCMimeConverterCID, nsnull,
nsCOMTypeInfo<nsIMimeConverter>::GetIID(), (void **)&converter);
if (NS_SUCCEEDED(res) && nsnull != converter) {
res = converter->DecodeMimePartIIStr(header, charset, decodedString);
NS_RELEASE(converter);
}
return res;
}
// Get a default mail character set.
char * nsMsgI18NGetDefaultMailCharset()
{
nsresult res = NS_OK;
char * retVal = nsnull;
NS_WITH_SERVICE(nsIPref, prefs, kPrefCID, &res);
if (nsnull != prefs && NS_SUCCEEDED(res))
{
char *prefValue;
res = prefs->CopyCharPref("intl.character_set_name", &prefValue);
if (NS_SUCCEEDED(res))
{
//TODO: map to mail charset (e.g. Shift_JIS -> ISO-2022-JP) bug#3941.
retVal = prefValue;
}
else
retVal = PL_strdup("iso-8859-1");
}
return (nsnull != retVal) ? retVal : PL_strdup("iso-8859-1");
}
// Return True if a charset is stateful (e.g. JIS).
PRBool nsMsgI18Nstateful_charset(const char *charset)
{
//TODO: use charset manager's service
return (PL_strcasecmp(charset, "iso-2022-jp") == 0);
}
// Check 7bit in a given buffer.
// This is expensive (both memory and performance).
// The check would be very simple if applied to an unicode text (e.g. nsString or utf-8).
// Possible optimazaion is to search ESC(0x1B) in case of iso-2022-jp and iso-2022-kr.
// Or convert and check line by line.
PRBool nsMsgI18N7bit_data_part(const char *charset, const char *inString, const PRUint32 size)
{
char *aCString;
nsString aCharset(charset);
nsString outString;
nsresult res;
aCString = (char *) PR_Malloc(size + 1);
if (nsnull != aCString) {
PL_strncpy(aCString, inString, size); // make a C string
res = ConvertToUnicode(aCharset, aCString, outString);
PR_Free(aCString);
if (NS_SUCCEEDED(res)) {
for (PRInt32 i = 0; i < outString.Length(); i++) {
if (outString.CharAt(i) > 127) {
return PR_FALSE;
}
}
}
}
return PR_TRUE; // all 7 bit
}
// Simple parser to parse META charset.
// It only supports the case when the description is within one line.
const char *
nsMsgI18NParseMetaCharset(nsFileSpec* fileSpec)
{
static char charset[65];
char buffer[512];
nsInputFileStream fileStream(*fileSpec);
*charset = '\0';
while (!fileStream.eof() && !fileStream.failed() &&
fileStream.is_open()) {
fileStream.readline(buffer, 512);
if (*buffer == CR || *buffer == LF || *buffer == 0)
continue;
for (int i = 0; i < (int)PL_strlen(buffer); i++) {
buffer[i] = toupper(buffer[i]);
}
if (PL_strstr(buffer, "/HEAD"))
break;
if (PL_strstr(buffer, "META") &&
PL_strstr(buffer, "HTTP-EQUIV") &&
PL_strstr(buffer, "CONTENT-TYPE") &&
PL_strstr(buffer, "CHARSET")
)
{
char *cp = PL_strstr(PL_strstr(buffer, "CHARSET"), "=") + 1;
char seps[] = " \"\'";
char *token;
char* newStr;
token = nsCRT::strtok(cp, seps, &newStr);
if (token != NULL)
{
PL_strcpy(charset, token);
}
}
}
return charset;
}
nsresult nsMsgI18NConvertToEntity(const nsString& inString, nsString* outString)
{
nsresult res;
outString->SetString("");
nsCOMPtr <nsIEntityConverter> entityConv;
res = nsComponentManager::CreateInstance(kEntityConverterCID, NULL,
nsIEntityConverter::GetIID(), getter_AddRefs(entityConv));
if(NS_SUCCEEDED(res)) {
PRUnichar *entities = NULL;
res = entityConv->ConvertToEntities(inString.GetUnicode(), nsIEntityConverter::html40Latin1, &entities);
if (NS_SUCCEEDED(res) && (NULL != entities)) {
outString->SetString(entities);
nsAllocator::Free(entities);
}
}
return res;
}
nsresult nsMsgI18NSaveAsCharset(const char* contentType, const char *charset, const PRUnichar* inString, char** outString)
{
NS_ASSERTION(contentType, "null ptr- contentType");
NS_ASSERTION(charset, "null ptr- charset");
NS_ASSERTION(outString, "null ptr- outString");
if(!contentType || !charset || !outString)
return NS_ERROR_NULL_POINTER;
*outString = NULL;
PRBool bTEXT_HTML = PR_FALSE;
nsresult res;
if (!nsCRT::strcasecmp(contentType, TEXT_HTML)) {
bTEXT_HTML = PR_TRUE;
}
else if (nsCRT::strcasecmp(contentType, TEXT_PLAIN)) {
return NS_ERROR_ILLEGAL_VALUE; // not supported type
}
nsCOMPtr <nsISaveAsCharset> aConv; // charset converter plus entity, NCR generation
res = nsComponentManager::CreateInstance(kSaveAsCharsetCID, NULL,
nsISaveAsCharset::GetIID(), getter_AddRefs(aConv));
if(NS_SUCCEEDED(res)) {
// attribute:
// html text - charset conv then fallback to entity or NCR
// plain text - charset conv then fallback to '?'
res = aConv->Init(charset,
bTEXT_HTML ?
nsISaveAsCharset::attr_EntityAfterCharsetConv + nsISaveAsCharset::attr_FallbackDecimalNCR :
nsISaveAsCharset::attr_plainTextDefault + nsISaveAsCharset::attr_FallbackQuestionMark,
nsIEntityConverter::html40);
if (NS_SUCCEEDED(res)) {
res = aConv->Convert(inString, outString);
}
}
return res;
}
// RICHIE - not sure about this one?? need to see what it did in the old
// world.
char *
nsMsgI18NGetAcceptLanguage(void)
{
return "en";
}

View File

@@ -1,49 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _nsMsgI18N_H_
#define _nsMsgI18N_H_
#include "nscore.h"
#include "msgCore.h"
NS_MSG_BASE char *nsMsgI18NEncodeMimePartIIStr(const char *header, const char *charset, PRBool bUseMime);
NS_MSG_BASE PRBool nsMsgI18Nstateful_charset(const char *charset);
NS_MSG_BASE PRBool nsMsgI18N7bit_data_part(const char *charset, const char *string, const PRUint32 size);
NS_MSG_BASE char *nsMsgI18NGetAcceptLanguage(void);
NS_MSG_BASE const char *msgCompHeaderInternalCharset(void);
NS_MSG_BASE char * nsMsgI18NGetDefaultMailCharset(void);
NS_MSG_BASE nsresult ConvertFromUnicode(const nsString& aCharset,
const nsString& inString,
char** outCString);
NS_MSG_BASE nsresult ConvertToUnicode(const nsString& aCharset,
const char* inCString,
nsString& outString);
NS_MSG_BASE nsresult nsMsgI18NDecodeMimePartIIStr(const nsString& header, nsString& charset, nsString& decodedString);
NS_MSG_BASE const char *nsMsgI18NParseMetaCharset(nsFileSpec* fileSpec);
NS_MSG_BASE nsresult nsMsgI18NConvertToEntity(const nsString& inString, nsString* outString);
NS_MSG_BASE nsresult nsMsgI18NSaveAsCharset(const char* contentType, const char* charset, const PRUnichar* inString, char** outString);
#endif /* _nsMsgI18N_H_ */

View File

@@ -1,356 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "msgCore.h" // for pre-compiled headers
#include "nsMsgIdentity.h"
#include "nsIPref.h"
#include "nsXPIDLString.h"
static NS_DEFINE_CID(kPrefServiceCID, NS_PREF_CID);
NS_IMPL_ISUPPORTS2(nsMsgIdentity,
nsIMsgIdentity,
nsIShutdownListener)
nsMsgIdentity::nsMsgIdentity():
m_signature(0),
m_vCard(0),
m_identityKey(0),
m_prefs(0)
{
NS_INIT_REFCNT();
}
nsMsgIdentity::~nsMsgIdentity()
{
PR_FREEIF(m_identityKey);
if (m_prefs) nsServiceManager::ReleaseService(kPrefServiceCID,
m_prefs,
nsnull);
}
nsresult
nsMsgIdentity::getPrefService()
{
if (m_prefs) return NS_OK;
return nsServiceManager::GetService(kPrefServiceCID,
nsCOMTypeInfo<nsIPref>::GetIID(),
(nsISupports**)&m_prefs,
this);
}
/* called if the prefs service goes offline */
NS_IMETHODIMP
nsMsgIdentity::OnShutdown(const nsCID& aClass, nsISupports *service)
{
if (aClass.Equals(kPrefServiceCID)) {
if (m_prefs) nsServiceManager::ReleaseService(kPrefServiceCID, m_prefs);
m_prefs = nsnull;
}
return NS_OK;
}
/*
* accessors for pulling values directly out of preferences
* instead of member variables, etc
*/
/* convert an identity key and preference name
to mail.identity.<identityKey>.<prefName>
*/
char *
nsMsgIdentity::getPrefName(const char *identityKey,
const char *prefName)
{
return PR_smprintf("mail.identity.%s.%s", identityKey, prefName);
}
// this will be slightly faster than the above, and allows
// the "default" identity preference root to be set in one place
char *
nsMsgIdentity::getDefaultPrefName(const char *fullPrefName)
{
return PR_smprintf("mail.identity.default.%s", fullPrefName);
}
/* The following are equivalent to the nsIPref's Get/CopyXXXPref
except they construct the preference name with the above function
*/
nsresult
nsMsgIdentity::getBoolPref(const char *prefname,
PRBool *val)
{
nsresult rv = getPrefService();
if (NS_FAILED(rv)) return rv;
char *fullPrefName = getPrefName(m_identityKey, prefname);
rv = m_prefs->GetBoolPref(fullPrefName, val);
PR_Free(fullPrefName);
if (NS_FAILED(rv))
rv = getDefaultBoolPref(prefname, val);
return rv;
}
nsresult
nsMsgIdentity::getDefaultBoolPref(const char *prefname,
PRBool *val) {
nsresult rv = getPrefService();
if (NS_FAILED(rv)) return rv;
char *fullPrefName = getDefaultPrefName(prefname);
rv = m_prefs->GetBoolPref(fullPrefName, val);
PR_Free(fullPrefName);
if (NS_FAILED(rv)) {
*val = PR_FALSE;
rv = NS_OK;
}
return rv;
}
nsresult
nsMsgIdentity::setBoolPref(const char *prefname,
PRBool val)
{
nsresult rv = getPrefService();
if (NS_FAILED(rv)) return rv;
char *prefName = getPrefName(m_identityKey, prefname);
rv = m_prefs->SetBoolPref(prefName, val);
PR_Free(prefName);
return rv;
}
nsresult
nsMsgIdentity::getCharPref(const char *prefname,
char **val)
{
nsresult rv = getPrefService();
if (NS_FAILED(rv)) return rv;
char *fullPrefName = getPrefName(m_identityKey, prefname);
rv = m_prefs->CopyCharPref(fullPrefName, val);
PR_Free(fullPrefName);
if (NS_FAILED(rv))
rv = getDefaultCharPref(prefname, val);
return rv;
}
nsresult
nsMsgIdentity::getDefaultCharPref(const char *prefname,
char **val)
{
nsresult rv = getPrefService();
if (NS_FAILED(rv)) return rv;
char *fullPrefName = getDefaultPrefName(prefname);
rv = m_prefs->CopyCharPref(fullPrefName, val);
PR_Free(fullPrefName);
if (NS_FAILED(rv)) {
*val = nsnull; // null is ok to return here
rv = NS_OK;
}
return rv;
}
nsresult
nsMsgIdentity::setCharPref(const char *prefname,
const char *val)
{
nsresult rv = getPrefService();
if (NS_FAILED(rv)) return rv;
rv = NS_OK;
char *prefName = getPrefName(m_identityKey, prefname);
if (val)
rv = m_prefs->SetCharPref(prefName, val);
else
m_prefs->ClearUserPref(prefName);
PR_Free(prefName);
return rv;
}
nsresult
nsMsgIdentity::getIntPref(const char *prefname,
PRInt32 *val)
{
nsresult rv = getPrefService();
if (NS_FAILED(rv)) return rv;
char *fullPrefName = getPrefName(m_identityKey, prefname);
rv = m_prefs->GetIntPref(fullPrefName, val);
PR_Free(fullPrefName);
if (NS_FAILED(rv))
rv = getDefaultIntPref(prefname, val);
return rv;
}
nsresult
nsMsgIdentity::getDefaultIntPref(const char *prefname,
PRInt32 *val) {
nsresult rv = getPrefService();
if (NS_FAILED(rv)) return rv;
char *fullPrefName = getDefaultPrefName(prefname);
rv = m_prefs->GetIntPref(fullPrefName, val);
PR_Free(fullPrefName);
if (NS_FAILED(rv)) {
*val = 0;
rv = NS_OK;
}
return rv;
}
nsresult
nsMsgIdentity::setIntPref(const char *prefname,
PRInt32 val)
{
nsresult rv = getPrefService();
if (NS_FAILED(rv)) return rv;
char *prefName = getPrefName(m_identityKey, prefname);
rv = m_prefs->SetIntPref(prefName, val);
PR_Free(prefName);
return rv;
}
nsresult
nsMsgIdentity::SetKey(const char* identityKey)
{
PR_FREEIF(m_identityKey);
m_identityKey = PL_strdup(identityKey);
return NS_OK;
}
nsresult
nsMsgIdentity::GetIdentityName(char **idName) {
if (!idName) return NS_ERROR_NULL_POINTER;
*idName = nsnull;
nsresult rv = getCharPref("identityName",idName);
if (NS_FAILED(rv)) return rv;
// there's probably a better way of doing this
// thats unicode friendly?
if (!(*idName)) {
nsXPIDLCString fullName;
rv = GetFullName(getter_Copies(fullName));
if (NS_FAILED(rv)) return rv;
nsXPIDLCString email;
rv = GetEmail(getter_Copies(email));
if (NS_FAILED(rv)) return rv;
*idName = PR_smprintf("%s <%s>", (const char*)fullName,
(const char*)email);
rv = NS_OK;
}
return rv;
}
nsresult nsMsgIdentity::SetIdentityName(const char *idName) {
return setCharPref("identityName", idName);
}
NS_IMETHODIMP
nsMsgIdentity::ToString(PRUnichar **aResult)
{
nsString idname("[nsIMsgIdentity: ");
idname += m_identityKey;
idname += "]";
*aResult = idname.ToNewUnicode();
return NS_OK;
}
/* Identity attribute accessors */
// XXX - these are a COM objects, use NS_ADDREF
//NS_IMPL_GETSET(nsMsgIdentity, Signature, nsIMsgSignature*, m_signature);
NS_IMETHODIMP
nsMsgIdentity::GetSignature(nsIFileSpec **sig) {
nsresult rv = getPrefService();
if (NS_FAILED(rv)) return rv;
char *prefName = getPrefName(m_identityKey, "sig_file");
rv = m_prefs->GetFilePref(prefName, sig);
if (NS_FAILED(rv))
*sig = nsnull;
return NS_OK;
}
NS_IMETHODIMP
nsMsgIdentity::SetSignature(nsIFileSpec *sig)
{
nsresult rv = getPrefService();
if (NS_FAILED(rv)) return rv;
rv = NS_OK;
char *prefName = getPrefName(m_identityKey, "sig_file");
if (sig)
rv = m_prefs->SetFilePref(NS_CONST_CAST(const char*,prefName), sig,
PR_FALSE);
/*
else
m_prefs->ClearFilePref(prefName);
*/
PR_Free(prefName);
return rv;
return NS_OK;
}
NS_IMPL_GETSET(nsMsgIdentity, VCard, nsIMsgVCard*, m_vCard);
NS_IMPL_GETTER_STR(nsMsgIdentity::GetKey, m_identityKey);
NS_IMPL_IDPREF_STR(FullName, "fullName");
NS_IMPL_IDPREF_STR(Email, "useremail");
NS_IMPL_IDPREF_STR(ReplyTo, "reply_to");
NS_IMPL_IDPREF_STR(Organization, "organization");
NS_IMPL_IDPREF_BOOL(ComposeHtml, "compose_html");
NS_IMPL_IDPREF_BOOL(AttachVCard, "attach_vcard");
NS_IMPL_IDPREF_BOOL(AttachSignature, "attach_signature");
NS_IMPL_IDPREF_BOOL(DoFcc, "fcc");
NS_IMPL_IDPREF_STR(FccFolder, "fcc_folder");
NS_IMPL_IDPREF_BOOL(BccSelf, "bcc_self");
NS_IMPL_IDPREF_BOOL(BccOthers, "bcc_other");
NS_IMPL_IDPREF_STR (BccList, "bcc_other_list");
NS_IMPL_IDPREF_STR (DraftFolder, "draft_folder");
NS_IMPL_IDPREF_STR (StationaryFolder, "stationary_folder");
NS_IMPL_IDPREF_STR (JunkMailFolder, "spam_folder");

View File

@@ -1,110 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef nsMsgIdentity_h___
#define nsMsgIdentity_h___
#include "nsIMsgIdentity.h"
#include "nsIPref.h"
#include "msgCore.h"
///////////////////////////////////////////////////////////////////////////////////
// an identity is an object designed to encapsulate all the information we need
// to know about a user identity. I expect this interface to grow and change a lot
// as we flesh out our thoughts on multiple identities and what properties go into
// these identities.
//////////////////////////////////////////////////////////////////////////////////
class NS_MSG_BASE nsMsgIdentity : public nsIMsgIdentity,
public nsIShutdownListener
{
public:
nsMsgIdentity();
virtual ~nsMsgIdentity();
NS_DECL_ISUPPORTS
NS_DECL_NSIMSGIDENTITY
// nsIShutdownListener
NS_IMETHOD OnShutdown(const nsCID& aClass, nsISupports *service);
private:
nsIMsgSignature* m_signature;
nsIMsgVCard* m_vCard;
char *m_identityKey;
nsIPref *m_prefs;
protected:
nsresult getPrefService();
char *getPrefName(const char *identityKey, const char *pref);
char *getDefaultPrefName(const char *pref);
nsresult getCharPref(const char *pref, char **);
nsresult getDefaultCharPref(const char *pref, char **);
nsresult setCharPref(const char *pref, const char *);
nsresult getBoolPref(const char *pref, PRBool *);
nsresult getDefaultBoolPref(const char *pref, PRBool *);
nsresult setBoolPref(const char *pref, PRBool);
nsresult getIntPref(const char *pref, PRInt32 *);
nsresult getDefaultIntPref(const char *pref, PRInt32 *);
nsresult setIntPref(const char *pref, PRInt32);
};
#define NS_IMPL_IDPREF_STR(_postfix, _prefname) \
NS_IMETHODIMP \
nsMsgIdentity::Get##_postfix(char **retval) \
{ \
return getCharPref(_prefname, retval); \
} \
NS_IMETHODIMP \
nsMsgIdentity::Set##_postfix(const char *value) \
{ \
return setCharPref(_prefname, value);\
}
#define NS_IMPL_IDPREF_BOOL(_postfix, _prefname)\
NS_IMETHODIMP \
nsMsgIdentity::Get##_postfix(PRBool *retval) \
{ \
return getBoolPref(_prefname, retval); \
} \
NS_IMETHODIMP \
nsMsgIdentity::Set##_postfix(PRBool value) \
{ \
return setBoolPref(_prefname, value); \
}
#define NS_IMPL_IDPREF_INT(_postfix, _prefname) \
NS_IMETHODIMP \
nsMsgIdentity::Get##_postfix(PRInt32 *retval) \
{ \
return getIntPref(_prefname, retval); \
} \
NS_IMETHODIMP \
nsMsgIdentity::Set##_postfix(PRInt32 value) \
{ \
return setIntPref(_prefname, value); \
}
#endif /* nsMsgIdentity_h___ */

View File

@@ -1,603 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "nsMsgIncomingServer.h"
#include "nscore.h"
#include "nsCom.h"
#include "plstr.h"
#include "prmem.h"
#include "prprf.h"
#include "nsIServiceManager.h"
#include "nsIPref.h"
#include "nsCOMPtr.h"
#include "nsIMsgFolder.h"
#include "nsIMsgFolderCache.h"
#include "nsIMsgFolderCacheElement.h"
#include "nsINetSupportDialogService.h"
#include "nsIPrompt.h"
#include "nsXPIDLString.h"
#include "nsIRDFService.h"
#include "nsIMsgProtocolInfo.h"
#include "nsRDFCID.h"
static NS_DEFINE_CID(kPrefServiceCID, NS_PREF_CID);
static NS_DEFINE_CID(kNetSupportDialogCID, NS_NETSUPPORTDIALOG_CID);
static NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID);
MOZ_DECL_CTOR_COUNTER(nsMsgIncomingServer);
nsMsgIncomingServer::nsMsgIncomingServer():
m_prefs(0),
m_serverKey(0),
m_rootFolder(0)
{
MOZ_COUNT_CTOR(nsMsgIncomingServer);
NS_INIT_REFCNT();
m_serverBusy = PR_FALSE;
m_password = "";
}
nsMsgIncomingServer::~nsMsgIncomingServer()
{
MOZ_COUNT_DTOR(nsMsgIncomingServer);
if (m_prefs) nsServiceManager::ReleaseService(kPrefServiceCID,
m_prefs,
nsnull);
PR_FREEIF(m_serverKey)
}
NS_IMPL_ISUPPORTS1(nsMsgIncomingServer, nsIMsgIncomingServer)
NS_IMPL_GETSET(nsMsgIncomingServer, ServerBusy, PRBool, m_serverBusy)
NS_IMPL_GETTER_STR(nsMsgIncomingServer::GetKey, m_serverKey)
NS_IMETHODIMP
nsMsgIncomingServer::SetKey(const char * serverKey)
{
nsresult rv = NS_OK;
// in order to actually make use of the key, we need the prefs
if (!m_prefs)
rv = nsServiceManager::GetService(kPrefServiceCID,
nsCOMTypeInfo<nsIPref>::GetIID(),
(nsISupports**)&m_prefs);
PR_FREEIF(m_serverKey);
m_serverKey = PL_strdup(serverKey);
return rv;
}
NS_IMETHODIMP
nsMsgIncomingServer::SetRootFolder(nsIFolder * aRootFolder)
{
m_rootFolder = aRootFolder;
return NS_OK;
}
NS_IMETHODIMP
nsMsgIncomingServer::GetRootFolder(nsIFolder * *aRootFolder)
{
if (!aRootFolder)
return NS_ERROR_NULL_POINTER;
if (m_rootFolder) {
*aRootFolder = m_rootFolder;
NS_ADDREF(*aRootFolder);
} else {
nsresult rv = CreateRootFolder();
if (NS_FAILED(rv)) return rv;
*aRootFolder = m_rootFolder;
NS_IF_ADDREF(*aRootFolder);
}
return NS_OK;
}
NS_IMETHODIMP
nsMsgIncomingServer::PerformBiff()
{
//This had to be implemented in the derived class, but in case someone doesn't implement it
//just return not implemented.
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsMsgIncomingServer::WriteToFolderCache(nsIMsgFolderCache *folderCache)
{
nsresult rv = NS_OK;
if (m_rootFolder)
{
nsCOMPtr <nsIMsgFolder> msgFolder = do_QueryInterface(m_rootFolder, &rv);
if (NS_SUCCEEDED(rv) && msgFolder)
rv = msgFolder->WriteToFolderCache(folderCache);
}
return rv;
}
NS_IMETHODIMP
nsMsgIncomingServer::CloseCachedConnections()
{
// derived class should override if they cache connections.
return NS_OK;
}
NS_IMETHODIMP
nsMsgIncomingServer::GetServerURI(char **)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
nsresult
nsMsgIncomingServer::CreateRootFolder()
{
nsresult rv;
// get the URI from the incoming server
nsXPIDLCString serverUri;
rv = GetServerURI(getter_Copies(serverUri));
if (NS_FAILED(rv)) return rv;
NS_WITH_SERVICE(nsIRDFService, rdf,
kRDFServiceCID, &rv);
// get the corresponding RDF resource
// RDF will create the server resource if it doesn't already exist
nsCOMPtr<nsIRDFResource> serverResource;
rv = rdf->GetResource(serverUri, getter_AddRefs(serverResource));
if (NS_FAILED(rv)) return rv;
// make incoming server know about its root server folder so we
// can find sub-folders given an incoming server.
m_rootFolder = do_QueryInterface(serverResource, &rv);
return rv;
}
char *
nsMsgIncomingServer::getPrefName(const char *serverKey,
const char *fullPrefName)
{
return PR_smprintf("mail.server.%s.%s", serverKey, fullPrefName);
}
// this will be slightly faster than the above, and allows
// the "default" server preference root to be set in one place
char *
nsMsgIncomingServer::getDefaultPrefName(const char *fullPrefName)
{
return PR_smprintf("mail.server.default.%s", fullPrefName);
}
nsresult
nsMsgIncomingServer::GetBoolValue(const char *prefname,
PRBool *val)
{
char *fullPrefName = getPrefName(m_serverKey, prefname);
nsresult rv = m_prefs->GetBoolPref(fullPrefName, val);
PR_Free(fullPrefName);
if (NS_FAILED(rv))
rv = getDefaultBoolPref(prefname, val);
return rv;
}
nsresult
nsMsgIncomingServer::getDefaultBoolPref(const char *prefname,
PRBool *val) {
char *fullPrefName = getDefaultPrefName(prefname);
nsresult rv = m_prefs->GetBoolPref(fullPrefName, val);
PR_Free(fullPrefName);
if (NS_FAILED(rv)) {
*val = PR_FALSE;
rv = NS_OK;
}
return rv;
}
nsresult
nsMsgIncomingServer::SetBoolValue(const char *prefname,
PRBool val)
{
nsresult rv;
char *fullPrefName = getPrefName(m_serverKey, prefname);
PRBool defaultValue;
rv = getDefaultBoolPref(prefname, &defaultValue);
if (NS_SUCCEEDED(rv) &&
val == defaultValue)
m_prefs->ClearUserPref(fullPrefName);
else
rv = m_prefs->SetBoolPref(fullPrefName, val);
PR_Free(fullPrefName);
return rv;
}
nsresult
nsMsgIncomingServer::GetIntValue(const char *prefname,
PRInt32 *val)
{
char *fullPrefName = getPrefName(m_serverKey, prefname);
nsresult rv = m_prefs->GetIntPref(fullPrefName, val);
PR_Free(fullPrefName);
if (NS_FAILED(rv))
rv = getDefaultIntPref(prefname, val);
return rv;
}
nsresult
nsMsgIncomingServer::GetFileValue(const char* prefname,
nsIFileSpec **spec)
{
char *fullPrefName = getPrefName(m_serverKey, prefname);
nsresult rv = m_prefs->GetFilePref(fullPrefName, spec);
PR_Free(fullPrefName);
return rv;
}
nsresult
nsMsgIncomingServer::SetFileValue(const char* prefname,
nsIFileSpec *spec)
{
char *fullPrefName = getPrefName(m_serverKey, prefname);
nsresult rv = m_prefs->SetFilePref(fullPrefName, spec, PR_FALSE);
PR_Free(fullPrefName);
return rv;
}
nsresult
nsMsgIncomingServer::getDefaultIntPref(const char *prefname,
PRInt32 *val) {
char *fullPrefName = getDefaultPrefName(prefname);
nsresult rv = m_prefs->GetIntPref(fullPrefName, val);
PR_Free(fullPrefName);
if (NS_FAILED(rv)) {
*val = 0;
rv = NS_OK;
}
return rv;
}
nsresult
nsMsgIncomingServer::SetIntValue(const char *prefname,
PRInt32 val)
{
nsresult rv;
char *fullPrefName = getPrefName(m_serverKey, prefname);
PRInt32 defaultVal;
rv = getDefaultIntPref(prefname, &defaultVal);
if (NS_SUCCEEDED(rv) && defaultVal == val)
m_prefs->ClearUserPref(fullPrefName);
else
rv = m_prefs->SetIntPref(fullPrefName, val);
PR_Free(fullPrefName);
return rv;
}
nsresult
nsMsgIncomingServer::GetCharValue(const char *prefname,
char **val)
{
char *fullPrefName = getPrefName(m_serverKey, prefname);
nsresult rv = m_prefs->CopyCharPref(fullPrefName, val);
PR_Free(fullPrefName);
if (NS_FAILED(rv))
rv = getDefaultCharPref(prefname, val);
return rv;
}
nsresult
nsMsgIncomingServer::getDefaultCharPref(const char *prefname,
char **val) {
char *fullPrefName = getDefaultPrefName(prefname);
nsresult rv = m_prefs->CopyCharPref(fullPrefName, val);
PR_Free(fullPrefName);
if (NS_FAILED(rv)) {
*val = nsnull; // null is ok to return here
rv = NS_OK;
}
return rv;
}
nsresult
nsMsgIncomingServer::SetCharValue(const char *prefname,
const char * val)
{
nsresult rv;
char *fullPrefName = getPrefName(m_serverKey, prefname);
if (!val) {
m_prefs->ClearUserPref(fullPrefName);
return NS_OK;
}
char *defaultVal=nsnull;
rv = getDefaultCharPref(prefname, &defaultVal);
if (NS_SUCCEEDED(rv) &&
PL_strcmp(defaultVal, val) == 0)
m_prefs->ClearUserPref(fullPrefName);
else
rv = m_prefs->SetCharPref(fullPrefName, val);
PR_FREEIF(defaultVal);
PR_Free(fullPrefName);
return rv;
}
// pretty name is the display name to show to the user
NS_IMETHODIMP
nsMsgIncomingServer::GetPrettyName(PRUnichar **retval) {
char *val=nsnull;
nsresult rv = GetCharValue("name", &val);
if (NS_FAILED(rv)) return rv;
nsString prettyName;
// if there's no name, then just return the hostname
if (val) {
prettyName = val;
} else {
nsXPIDLCString username;
rv = GetUsername(getter_Copies(username));
if (NS_FAILED(rv)) return rv;
if ((const char*)username &&
PL_strcmp((const char*)username, "")!=0) {
prettyName = username;
prettyName += " on ";
}
nsXPIDLCString hostname;
rv = GetHostName(getter_Copies(hostname));
if (NS_FAILED(rv)) return rv;
prettyName += hostname;
}
*retval = prettyName.ToNewUnicode();
return NS_OK;
}
NS_IMETHODIMP
nsMsgIncomingServer::SetPrettyName(const PRUnichar *value) {
// this is lossy. Not sure what to do.
nsCString str(value);
return SetCharValue("name", str.GetBuffer());
}
NS_IMETHODIMP
nsMsgIncomingServer::ToString(PRUnichar** aResult) {
nsString servername("[nsIMsgIncomingServer: ");
servername += m_serverKey;
servername += "]";
*aResult = servername.ToNewUnicode();
NS_ASSERTION(*aResult, "no server name!");
return NS_OK;
}
NS_IMETHODIMP nsMsgIncomingServer::SetPassword(const char * aPassword)
{
// if remember password is turned on, write the password to preferences
// otherwise, just set the password so we remember it for the rest of the current
// session.
PRBool rememberPassword = PR_FALSE;
GetRememberPassword(&rememberPassword);
if (rememberPassword)
{
SetPrefPassword((char *) aPassword);
}
m_password = aPassword;
return NS_OK;
}
NS_IMETHODIMP nsMsgIncomingServer::GetPassword(char ** aPassword)
{
nsresult rv = NS_OK;
PRBool rememberPassword = PR_FALSE;
// okay, here's the scoop for this messs...
// (1) if we have a password already, go ahead and use it!
// (2) if remember password is turned on, try reading in from the prefs and if we have one, go ahead
// and use it
// (3) otherwise prompt the user for a password and then remember that password in the server
if (m_password.IsEmpty())
{
// case (2)
GetRememberPassword(&rememberPassword);
if (rememberPassword)
{
nsXPIDLCString password;
GetPrefPassword(getter_Copies(password));
m_password = password;
}
}
*aPassword = m_password.ToNewCString();
return rv;
}
NS_IMETHODIMP
nsMsgIncomingServer::GetPasswordWithUI(const PRUnichar * aPromptMessage, char **aPassword)
{
nsXPIDLCString prefvalue;
GetPassword(getter_Copies(prefvalue));
nsresult rv = NS_OK;
if (m_password.IsEmpty()) {
// prompt the user for the password
NS_WITH_SERVICE(nsIPrompt, dialog, kNetSupportDialogCID, &rv);
if (NS_SUCCEEDED(rv))
{
PRUnichar * uniPassword;
PRBool okayValue = PR_TRUE;
dialog->PromptPassword(aPromptMessage, &uniPassword, &okayValue);
if (!okayValue) // if the user pressed cancel, just return NULL;
{
*aPassword = nsnull;
return rv;
}
// we got a password back...so remember it
nsCString aCStr(uniPassword);
SetPassword((const char *) aCStr);
} // if we got a prompt dialog
} // if the password is empty
*aPassword = m_password.ToNewCString();
return rv;
}
NS_IMETHODIMP
nsMsgIncomingServer::SetDefaultLocalPath(nsIFileSpec *aDefaultLocalPath)
{
nsresult rv;
nsXPIDLCString type;
GetType(getter_Copies(type));
nsCAutoString progid(NS_MSGPROTOCOLINFO_PROGID_PREFIX);
progid += type;
NS_WITH_SERVICE(nsIMsgProtocolInfo, protocolInfo, progid, &rv);
if (NS_FAILED(rv)) return rv;
rv = protocolInfo->SetDefaultLocalPath(aDefaultLocalPath);
return rv;
}
NS_IMETHODIMP
nsMsgIncomingServer::GetLocalPath(nsIFileSpec **aLocalPath)
{
nsresult rv;
// if the local path has already been set, use it
rv = GetFileValue("directory", aLocalPath);
if (NS_SUCCEEDED(rv) && *aLocalPath) return rv;
// otherwise, create the path using. note we are using the
// server key instead of the hostname
//
// TODO: handle the case where they migrated a server of hostname "server4"
// and we create a server (with the account wizard) with key "server4"
// we'd get a collision.
// need to modify the code that creates keys to check for disk collision
nsXPIDLCString type;
GetType(getter_Copies(type));
nsCAutoString progid(NS_MSGPROTOCOLINFO_PROGID_PREFIX);
progid += type;
NS_WITH_SERVICE(nsIMsgProtocolInfo, protocolInfo, progid, &rv);
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIFileSpec> path;
rv = protocolInfo->GetDefaultLocalPath(getter_AddRefs(path));
if (NS_FAILED(rv)) return rv;
path->CreateDir();
nsXPIDLCString key;
rv = GetKey(getter_Copies(key));
if (NS_FAILED(rv)) return rv;
rv = path->AppendRelativeUnixPath(key);
if (NS_FAILED(rv)) return rv;
rv = SetLocalPath(path);
if (NS_FAILED(rv)) return rv;
*aLocalPath = path;
NS_ADDREF(*aLocalPath);
return NS_OK;
}
NS_IMETHODIMP
nsMsgIncomingServer::SetLocalPath(nsIFileSpec *spec)
{
if (spec) {
spec->CreateDir();
return SetFileValue("directory", spec);
}
else {
return NS_ERROR_NULL_POINTER;
}
}
NS_IMETHODIMP
nsMsgIncomingServer::SetRememberPassword(PRBool value)
{
if (value)
SetPrefPassword(m_password);
else
SetPrefPassword(nsnull);
return SetBoolValue("remember_password", value);
}
NS_IMETHODIMP
nsMsgIncomingServer::GetRememberPassword(PRBool* value)
{
return GetBoolValue("remember_password", value);
}
// use the convenience macros to implement the accessors
NS_IMPL_SERVERPREF_STR(nsMsgIncomingServer, HostName, "hostname");
NS_IMPL_SERVERPREF_STR(nsMsgIncomingServer, Username, "userName");
NS_IMPL_SERVERPREF_STR(nsMsgIncomingServer, PrefPassword, "password");
NS_IMPL_SERVERPREF_BOOL(nsMsgIncomingServer, DoBiff, "check_new_mail");
NS_IMPL_SERVERPREF_INT(nsMsgIncomingServer, BiffMinutes, "check_time");
NS_IMPL_SERVERPREF_STR(nsMsgIncomingServer, Type, "type");
/* what was this called in 4.x? */
// pref("mail.pop3_gets_new_mail", true);
NS_IMPL_SERVERPREF_BOOL(nsMsgIncomingServer, DownloadOnBiff, "download_on_biff");

View File

@@ -1,70 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef nsMsgIncomingServer_h__
#define nsMsgIncomingServer_h__
#include "nsIMsgIncomingServer.h"
#include "nsIPref.h"
#include "msgCore.h"
#include "nsIFolder.h"
#include "nsCOMPtr.h"
class nsIMsgFolderCache;
/*
* base class for nsIMsgIncomingServer - derive your class from here
* if you want to get some free implementation
*
* this particular implementation is not meant to be used directly.
*/
class NS_MSG_BASE nsMsgIncomingServer : public nsIMsgIncomingServer {
public:
nsMsgIncomingServer();
virtual ~nsMsgIncomingServer();
NS_DECL_ISUPPORTS
NS_DECL_NSIMSGINCOMINGSERVER
private:
nsIPref *m_prefs;
char *m_serverKey;
nsCString m_password;
PRBool m_serverBusy;
protected:
char *getPrefName(const char *serverKey, const char *pref);
char *getDefaultPrefName(const char *pref);
// these are private pref getters and setters for the password
// field. Callers should be using Get/Set Password
NS_IMETHOD GetPrefPassword(char * *aPassword);
NS_IMETHOD SetPrefPassword(const char * aPassword);
nsCOMPtr <nsIFolder> m_rootFolder;
nsresult getDefaultCharPref(const char *pref, char **);
nsresult getDefaultBoolPref(const char *pref, PRBool *);
nsresult getDefaultIntPref(const char *pref, PRInt32 *);
nsresult CreateRootFolder();
};
#endif // nsMsgIncomingServer_h__

File diff suppressed because it is too large Load Diff

View File

@@ -1,115 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _nsMsgKeySet_H_
#define _nsMsgKeySet_H_
#include "msgCore.h"
// nsMsgKeySet represents a set of articles. Typically, it is the set of
// read articles from a .newsrc file, but it can be used for other purposes
// too.
#if 0
// If a MSG_NewsHost* is supplied to the creation routine, then that
// MSG_NewsHost will be notified whenever a change is made to set.
class MSG_NewsHost;
#endif
class NS_MSG_BASE nsMsgKeySet {
public:
// Creates an empty set.
static nsMsgKeySet* Create(/* MSG_NewsHost* host = NULL*/);
// Creates a set from the list of numbers, as might be found in a
// newsrc file.
static nsMsgKeySet* Create(const char* str/* , MSG_NewsHost* host = NULL*/);
~nsMsgKeySet();
// FirstNonMember() returns the lowest non-member of the set that is
// greater than 0.
PRInt32 FirstNonMember();
// Output() converts to a string representation suitable for writing to a
// .newsrc file. (The result must be freed by the caller using delete[].)
char* Output();
// IsMember() returns whether the given article is a member of this set.
PRBool IsMember(PRInt32 art);
// Add() adds the given article to the set. (Returns 1 if a change was
// made, 0 if it was already there, and negative on error.)
int Add(PRInt32 art);
// Remove() removes the given article from the set.
int Remove(PRInt32 art);
// AddRange() adds the (inclusive) given range of articles to the set.
int AddRange(PRInt32 first, PRInt32 last);
// CountMissingInRange() takes an inclusive range of articles and returns
// the number of articles in that range which are not in the set.
PRInt32 CountMissingInRange(PRInt32 start, PRInt32 end);
// FirstMissingRange() takes an inclusive range and finds the first range
// of articles that are not in the set. If none, return zeros.
int FirstMissingRange(PRInt32 min, PRInt32 max, PRInt32* first, PRInt32* last);
// LastMissingRange() takes an inclusive range and finds the last range
// of articles that are not in the set. If none, return zeros.
int LastMissingRange(PRInt32 min, PRInt32 max, PRInt32* first, PRInt32* last);
PRInt32 GetLastMember();
PRInt32 GetFirstMember();
void SetLastMember(PRInt32 highWaterMark);
// For debugging only...
PRInt32 getLength() {return m_length;}
#ifdef DEBUG
static void RunTests();
#endif
protected:
nsMsgKeySet(/* MSG_NewsHost* host */);
nsMsgKeySet(const char* /* , MSG_NewsHost* host */);
PRBool Grow();
PRBool Optimize();
#ifdef DEBUG
static void test_decoder(const char*);
static void test_adder();
static void test_ranges();
static void test_member(PRBool with_cache);
#endif
PRInt32 *m_data; /* the numbers composing the `chunks' */
PRInt32 m_data_size; /* size of that malloc'ed block */
PRInt32 m_length; /* active area */
PRInt32 m_cached_value; /* a potential set member, or -1 if unset*/
PRInt32 m_cached_value_index; /* the index into `data' at which a search
to determine whether `cached_value' was
a member of the set ended. */
#ifdef NEWSRC_DOES_HOST_STUFF
MSG_NewsHost* m_host;
#endif
};
#endif /* _nsMsgKeySet_H_ */

View File

@@ -1,384 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "msgCore.h"
#include "prlog.h"
#include "nsMsgLineBuffer.h"
#include "nsIInputStream.h" // used by nsMsgLineStreamBuffer
MOZ_DECL_CTOR_COUNTER(nsByteArray);
nsByteArray::nsByteArray()
{
MOZ_COUNT_CTOR(nsByteArray);
m_buffer = NULL;
m_bufferSize = 0;
m_bufferPos = 0;
}
nsByteArray::~nsByteArray()
{
MOZ_COUNT_DTOR(nsByteArray);
PR_FREEIF(m_buffer);
}
nsresult nsByteArray::GrowBuffer(PRUint32 desired_size, PRUint32 quantum)
{
if (m_bufferSize < desired_size)
{
char *new_buf;
PRUint32 increment = desired_size - m_bufferSize;
if (increment < quantum) /* always grow by a minimum of N bytes */
increment = quantum;
new_buf = (m_buffer
? (char *) PR_REALLOC (m_buffer, (m_bufferSize + increment))
: (char *) PR_MALLOC (m_bufferSize + increment));
if (! new_buf)
return NS_ERROR_OUT_OF_MEMORY;
m_buffer = new_buf;
m_bufferSize += increment;
}
return 0;
}
nsresult nsByteArray::AppendString(const char *string)
{
PRUint32 strLength = (string) ? PL_strlen(string) : 0;
return AppendBuffer(string, strLength);
}
nsresult nsByteArray::AppendBuffer(const char *buffer, PRUint32 length)
{
nsresult ret = NS_OK;
if (m_bufferPos + length > m_bufferSize)
ret = GrowBuffer(m_bufferPos + length, 1024);
if (ret == NS_OK)
{
memcpy(m_buffer + m_bufferPos, buffer, length);
m_bufferPos += length;
}
return ret;
}
MOZ_DECL_CTOR_COUNTER(nsMsgLineBuffer);
nsMsgLineBuffer::nsMsgLineBuffer(nsMsgLineBufferHandler *handler, PRBool convertNewlinesP)
{
MOZ_COUNT_CTOR(nsMsgLineBuffer);
m_handler = handler;
m_convertNewlinesP = convertNewlinesP;
m_lookingForCRLF = PR_TRUE;
}
nsMsgLineBuffer::~nsMsgLineBuffer()
{
MOZ_COUNT_DTOR(nsMsgLineBuffer);
}
void
nsMsgLineBuffer::SetLookingForCRLF(PRBool b)
{
m_lookingForCRLF = b;
}
PRInt32 nsMsgLineBuffer::BufferInput(const char *net_buffer, PRInt32 net_buffer_size)
{
int status = 0;
if (m_bufferPos > 0 && m_buffer && m_buffer[m_bufferPos - 1] == CR &&
net_buffer_size > 0 && net_buffer[0] != LF) {
/* The last buffer ended with a CR. The new buffer does not start
with a LF. This old buffer should be shipped out and discarded. */
PR_ASSERT(m_bufferSize > m_bufferPos);
if (m_bufferSize <= m_bufferPos) return -1;
status = ConvertAndSendBuffer();
if (status < 0)
return status;
m_bufferPos = 0;
}
while (net_buffer_size > 0)
{
const char *net_buffer_end = net_buffer + net_buffer_size;
const char *newline = 0;
const char *s;
for (s = net_buffer; s < net_buffer_end; s++)
{
if (m_lookingForCRLF) {
/* Move forward in the buffer until the first newline.
Stop when we see CRLF, CR, or LF, or the end of the buffer.
*But*, if we see a lone CR at the *very end* of the buffer,
treat this as if we had reached the end of the buffer without
seeing a line terminator. This is to catch the case of the
buffers splitting a CRLF pair, as in "FOO\r\nBAR\r" "\nBAZ\r\n".
*/
if (*s == CR || *s == LF) {
newline = s;
if (newline[0] == CR) {
if (s == net_buffer_end - 1) {
/* CR at end - wait for the next character. */
newline = 0;
break;
}
else if (newline[1] == LF) {
/* CRLF seen; swallow both. */
newline++;
}
}
newline++;
break;
}
}
else {
/* if not looking for a CRLF, stop at CR or LF. (for example, when parsing the newsrc file). this fixes #9896, where we'd lose the last line of anything we'd parse that used CR as the line break. */
if (*s == CR || *s == LF) {
newline = s;
newline++;
break;
}
}
}
/* Ensure room in the net_buffer and append some or all of the current
chunk of data to it. */
{
const char *end = (newline ? newline : net_buffer_end);
PRUint32 desired_size = (end - net_buffer) + m_bufferPos + 1;
if (desired_size >= m_bufferSize)
{
status = GrowBuffer (desired_size, 1024);
if (status < 0)
return status;
}
memcpy (m_buffer + m_bufferPos, net_buffer, (end - net_buffer));
m_bufferPos += (end - net_buffer);
}
/* Now m_buffer contains either a complete line, or as complete
a line as we have read so far.
If we have a line, process it, and then remove it from `m_buffer'.
Then go around the loop again, until we drain the incoming data.
*/
if (!newline)
return 0;
status = ConvertAndSendBuffer();
if (status < 0) return status;
net_buffer_size -= (newline - net_buffer);
net_buffer = newline;
m_bufferPos = 0;
}
#ifdef DEBUG_bienvenu
printf("returning from buffer input m_bufferPos = %ld\n", m_bufferPos);
#endif
return 0;
}
PRInt32 nsMsgLineBuffer::HandleLine(char *line, PRUint32 line_length)
{
NS_ASSERTION(PR_FALSE, "must override this method if you don't provide a handler");
return 0;
}
PRInt32 nsMsgLineBuffer::ConvertAndSendBuffer()
{
/* Convert the line terminator to the native form.
*/
char *buf = m_buffer;
PRInt32 length = m_bufferPos;
char* newline;
PR_ASSERT(buf && length > 0);
if (!buf || length <= 0)
return -1;
newline = buf + length;
PR_ASSERT(newline[-1] == CR || newline[-1] == LF);
if (newline[-1] != CR && newline[-1] != LF)
return -1;
if (!m_convertNewlinesP)
{
}
#if (MSG_LINEBREAK_LEN == 1)
else if ((newline - buf) >= 2 &&
newline[-2] == CR &&
newline[-1] == LF)
{
/* CRLF -> CR or LF */
buf [length - 2] = MSG_LINEBREAK[0];
length--;
}
else if (newline > buf + 1 &&
newline[-1] != MSG_LINEBREAK[0])
{
/* CR -> LF or LF -> CR */
buf [length - 1] = MSG_LINEBREAK[0];
}
#else
else if (((newline - buf) >= 2 && newline[-2] != CR) ||
((newline - buf) >= 1 && newline[-1] != LF))
{
/* LF -> CRLF or CR -> CRLF */
length++;
buf[length - 2] = MSG_LINEBREAK[0];
buf[length - 1] = MSG_LINEBREAK[1];
}
#endif
return (m_handler) ? m_handler->HandleLine(buf, length) : HandleLine(buf, length);
}
// If there's still some data (non CRLF terminated) flush it out
PRInt32 nsMsgLineBuffer::FlushLastLine()
{
char *buf = m_buffer + m_bufferPos;
PRInt32 length = m_bufferPos - 1;
if (length > 0)
return (m_handler) ? m_handler->HandleLine(buf, length) : HandleLine(buf, length);
else
return 0;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// This is a utility class used to efficiently extract lines from an input stream by buffering
// read but unprocessed stream data in a buffer.
///////////////////////////////////////////////////////////////////////////////////////////////////
nsMsgLineStreamBuffer::nsMsgLineStreamBuffer(PRUint32 aBufferSize, const char * aEndOfLineToken,
PRBool aAllocateNewLines, PRBool aEatCRLFs)
: m_eatCRLFs(aEatCRLFs), m_allocateNewLines(aAllocateNewLines),
m_endOfLineToken(aEndOfLineToken)
{
NS_PRECONDITION(aBufferSize > 0, "invalid buffer size!!!");
m_dataBuffer = nsnull;
m_startPos = nsnull;
// used to buffer incoming data by ReadNextLineFromInput
if (aBufferSize > 0)
{
m_dataBuffer = (char *) PR_CALLOC(sizeof(char) * aBufferSize);
m_startPos = m_dataBuffer;
}
m_dataBufferSize = aBufferSize;
}
nsMsgLineStreamBuffer::~nsMsgLineStreamBuffer()
{
PR_FREEIF(m_dataBuffer); // release our buffer...
}
// the design for this method has an inherit bug: if the length of the line is greater than the size of m_dataBufferSize,
// then we'll never find the next line because we can't hold the whole line in memory.
// aInputStream - the input stream we want to read a line from
// aPauseForMoreData is returned as PR_TRUE if the stream does not yet contain a line and we must wait for more
// data to come into the stream.
// Note to people wishing to modify this function: Be *VERY CAREFUL* this is a critical function used by all of
// our mail protocols including imap, nntp, and pop. If you screw it up, you could break a lot of stuff.....
char * nsMsgLineStreamBuffer::ReadNextLine(nsIInputStream * aInputStream, PRUint32 &aNumBytesInLine, PRBool &aPauseForMoreData)
{
// try to extract a line from m_inputBuffer. If we don't have an entire line,
// then read more bytes out from the stream. If the stream is empty then wait
// on the monitor for more data to come in.
NS_PRECONDITION(m_startPos && m_dataBufferSize > 0, "invalid input arguments for read next line from input");
// initialize out values
aPauseForMoreData = PR_FALSE;
aNumBytesInLine = 0;
char * endOfLine = nsnull;
PRUint32 numBytesInBuffer = PL_strlen(m_startPos);
if (numBytesInBuffer > 0) // any data in our internal buffer?
endOfLine = PL_strstr(m_startPos, m_endOfLineToken); // see if we already have a line ending...
// it's possible that we got here before the first time we receive data from the server
// so aInputStream will be nsnull...
if (!endOfLine && aInputStream) // get some more data from the server
{
PRUint32 numBytesInStream = 0;
PRUint32 numBytesCopied = 0;
aInputStream->Available(&numBytesInStream);
// if the number of bytes we want to read from the stream, is greater than the number
// of bytes left in our buffer, then we need to shift the start pos and its contents
// down to the beginning of m_dataBuffer...
PRUint32 numFreeBytesInBuffer = (m_dataBuffer + m_dataBufferSize) - (m_startPos + numBytesInBuffer);
if (numBytesInStream >= numFreeBytesInBuffer)
{
nsCRT::memcpy(m_dataBuffer, m_startPos, numBytesInBuffer);
m_dataBuffer[numBytesInBuffer] = '\0'; // make sure the end of the buffer is terminated
m_startPos = m_dataBuffer; // update the new start position
// update the number of free bytes in the buffer
numFreeBytesInBuffer = m_dataBufferSize - numBytesInBuffer;
}
PRUint32 numBytesToCopy = PR_MIN(numFreeBytesInBuffer - 1 /* leave one for a null terminator */, numBytesInStream);
// read the data into the end of our data buffer
if (numBytesToCopy > 0)
{
aInputStream->Read(m_startPos + numBytesInBuffer, numBytesToCopy, &numBytesCopied);
m_startPos[numBytesInBuffer + numBytesCopied] = '\0';
}
// okay, now that we've tried to read in more data from the stream, look for another end of line
// character
endOfLine = PL_strstr(m_startPos, m_endOfLineToken);
}
// okay, now check again for endOfLine.
if (endOfLine)
{
if (!m_eatCRLFs)
endOfLine += PL_strlen(m_endOfLineToken); // count for CRLF
// PR_CALLOC zeros out the allocated line
char* newLine = (char*) PR_CALLOC(endOfLine-m_startPos+1);
if (!newLine)
return nsnull;
nsCRT::memcpy(newLine, m_startPos, endOfLine-m_startPos); // copy the string into the new line buffer
aNumBytesInLine = endOfLine - m_startPos;
if (m_eatCRLFs)
endOfLine += PL_strlen(m_endOfLineToken); // advance past CRLF if we haven't already done so...
// now we need to update the data buffer to go past the line we just read out.
if (PL_strlen(endOfLine) <= 0) // if no more data in the buffer, then just zero out the buffer...
m_startPos[0] = '\0';
else // advance
m_startPos = endOfLine; // move us up to the end of the line
return newLine;
}
aPauseForMoreData = PR_TRUE;
return nsnull; // if we somehow got here. we don't have another line in the buffer yet...need to wait for more data...
}

View File

@@ -1,113 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _nsMsgLineBuffer_H
#define _nsMsgLineBuffer_H
#include "msgCore.h" // precompiled header...
// I can't believe I have to have this stupid class, but I can't find
// anything suitable (nsStrImpl might be, when its done). nsIByteBuffer
// would do, if I had a stream for input, which I don't.
class NS_MSG_BASE nsByteArray
{
public:
nsByteArray();
virtual ~nsByteArray();
PRUint32 GetSize() {return m_bufferSize;}
PRUint32 GetBufferPos() {return m_bufferPos;}
nsresult GrowBuffer(PRUint32 desired_size, PRUint32 quantum = 1024);
nsresult AppendString(const char *string);
nsresult AppendBuffer(const char *buffer, PRUint32 length);
void ResetWritePos() {m_bufferPos = 0;}
char *GetBuffer() {return m_buffer;}
protected:
char *m_buffer;
PRUint32 m_bufferSize;
PRUint32 m_bufferPos; // write Pos in m_buffer - where the next byte should go.
};
class NS_MSG_BASE nsMsgLineBufferHandler : public nsByteArray
{
public:
virtual PRInt32 HandleLine(char *line, PRUint32 line_length) = 0;
};
class NS_MSG_BASE nsMsgLineBuffer : public nsByteArray
{
public:
nsMsgLineBuffer(nsMsgLineBufferHandler *handler, PRBool convertNewlinesP);
virtual ~nsMsgLineBuffer();
PRInt32 BufferInput(const char *net_buffer, PRInt32 net_buffer_size);
// Not sure why anyone cares, by NNTPHost seems to want to know the buf pos.
PRUint32 GetBufferPos() {return m_bufferPos;}
virtual PRInt32 HandleLine(char *line, PRUint32 line_length);
// flush last line, though it won't be CRLF terminated.
virtual PRInt32 FlushLastLine();
protected:
nsMsgLineBuffer(PRBool convertNewlinesP);
PRInt32 ConvertAndSendBuffer();
void SetLookingForCRLF(PRBool b);
nsMsgLineBufferHandler *m_handler;
PRBool m_convertNewlinesP;
PRBool m_lookingForCRLF;
};
// I'm adding this utility class here for lack of a better place. This utility class is similar to nsMsgLineBuffer
// except it works from an input stream. It is geared towards efficiently parsing new lines out of a stream by storing
// read but unprocessed bytes in a buffer. I envision the primary use of this to be our mail protocols such as imap, news and
// pop which need to process line by line data being returned in the form of a proxied stream from the server.
class nsIInputStream;
class NS_MSG_BASE nsMsgLineStreamBuffer
{
public:
// aBufferSize -- size of the buffer you want us to use for buffering stream data
// aEndOfLinetoken -- The delimeter string to be used for determining the end of line. This
// allows us to parse platform specific end of line endings by making it
// a parameter.
// aAllocateNewLines -- PR_TRUE if you want calls to ReadNextLine to allocate new memory for the line.
// if false, the char * returned is just a ptr into the buffer. Subsequent calls to
// ReadNextLine will alter the data so your ptr only has a life time of a per call.
// aEatCRLFs -- PR_TRUE if you don't want to see the CRLFs on the lines returned by ReadNextLine.
// PR_FALSE if you do want to see them.
nsMsgLineStreamBuffer(PRUint32 aBufferSize, const char * aEndOfLineToken, PRBool aAllocateNewLines, PRBool aEatCRLFs = PR_TRUE); // specify the size of the buffer you want the class to use....
virtual ~nsMsgLineStreamBuffer();
// Caller must free the line returned using PR_Free
// aEndOfLinetoken -- delimeter used to denote the end of a line.
// aNumBytesInLine -- The number of bytes in the line returned
// aPauseForMoreData -- There is not enough data in the stream to make a line at this time...
char * ReadNextLine(nsIInputStream * aInputStream, PRUint32 &anumBytesInLine, PRBool &aPauseForMoreData);
protected:
PRBool m_eatCRLFs;
PRBool m_allocateNewLines;
char * m_dataBuffer;
char * m_startPos;
const char * m_endOfLineToken;
PRUint32 m_dataBufferSize;
};
#endif

View File

@@ -1,399 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "msgCore.h"
#include "nsMsgMailNewsUrl.h"
#include "nsMsgBaseCID.h"
#include "nsIMsgMailSession.h"
#include "nsXPIDLString.h"
static NS_DEFINE_CID(kUrlListenerManagerCID, NS_URLLISTENERMANAGER_CID);
static NS_DEFINE_CID(kStandardUrlCID, NS_STANDARDURL_CID);
static NS_DEFINE_CID(kMsgMailSessionCID, NS_MSGMAILSESSION_CID);
nsMsgMailNewsUrl::nsMsgMailNewsUrl()
{
NS_INIT_REFCNT();
// nsIURI specific state
m_errorMessage = nsnull;
m_runningUrl = PR_FALSE;
m_updatingFolder = PR_FALSE;
nsComponentManager::CreateInstance(kUrlListenerManagerCID, nsnull, nsCOMTypeInfo<nsIUrlListenerManager>::GetIID(), (void **) getter_AddRefs(m_urlListeners));
nsComponentManager::CreateInstance(kStandardUrlCID, nsnull, nsCOMTypeInfo<nsIURL>::GetIID(), (void **) getter_AddRefs(m_baseURL));
}
nsMsgMailNewsUrl::~nsMsgMailNewsUrl()
{
PR_FREEIF(m_errorMessage);
}
NS_IMPL_ADDREF(nsMsgMailNewsUrl);
NS_IMPL_RELEASE(nsMsgMailNewsUrl);
nsresult nsMsgMailNewsUrl::QueryInterface(const nsIID &aIID, void** aInstancePtr)
{
if (NULL == aInstancePtr) {
return NS_ERROR_NULL_POINTER;
}
if (aIID.Equals(nsCOMTypeInfo<nsIURI>::GetIID())) {
*aInstancePtr = (void*) ((nsIURI*)this);
NS_ADDREF_THIS();
return NS_OK;
}
if (aIID.Equals(nsCOMTypeInfo<nsIURL>::GetIID())) {
*aInstancePtr = (void*) ((nsIURL*)this);
NS_ADDREF_THIS();
return NS_OK;
}
if (aIID.Equals(nsCOMTypeInfo<nsIMsgMailNewsUrl>::GetIID()))
{
*aInstancePtr = (void *) ((nsIMsgMailNewsUrl*) this);
NS_ADDREF_THIS();
return NS_OK;
}
if (aIID.Equals(nsCOMTypeInfo<nsISupports>::GetIID()))
{
*aInstancePtr = (void *) ((nsIMsgMailNewsUrl*) this);
NS_ADDREF_THIS();
return NS_OK;
}
#if defined(NS_DEBUG)
/*
* Check for the debug-only interface indicating thread-safety
*/
static NS_DEFINE_IID(kIsThreadsafeIID, NS_ISTHREADSAFE_IID);
if (aIID.Equals(kIsThreadsafeIID)) {
return NS_OK;
}
#endif
return NS_NOINTERFACE;
}
////////////////////////////////////////////////////////////////////////////////////
// Begin nsIMsgMailNewsUrl specific support
////////////////////////////////////////////////////////////////////////////////////
nsresult nsMsgMailNewsUrl::GetUrlState(PRBool * aRunningUrl)
{
if (aRunningUrl)
*aRunningUrl = m_runningUrl;
return NS_OK;
}
nsresult nsMsgMailNewsUrl::SetUrlState(PRBool aRunningUrl, nsresult aExitCode)
{
m_runningUrl = aRunningUrl;
nsCOMPtr <nsIMsgStatusFeedback> statusFeedback;
if (NS_SUCCEEDED(GetStatusFeedback(getter_AddRefs(statusFeedback))) && statusFeedback)
{
if (m_runningUrl)
statusFeedback->StartMeteors();
else
{
statusFeedback->ShowProgress(0);
statusFeedback->StopMeteors();
}
}
if (m_urlListeners)
{
if (m_runningUrl)
{
m_urlListeners->OnStartRunningUrl(this);
}
else
{
m_urlListeners->OnStopRunningUrl(this, aExitCode);
}
}
return NS_OK;
}
nsresult nsMsgMailNewsUrl::RegisterListener (nsIUrlListener * aUrlListener)
{
if (m_urlListeners)
m_urlListeners->RegisterListener(aUrlListener);
return NS_OK;
}
nsresult nsMsgMailNewsUrl::UnRegisterListener (nsIUrlListener * aUrlListener)
{
if (m_urlListeners)
m_urlListeners->UnRegisterListener(aUrlListener);
return NS_OK;
}
nsresult nsMsgMailNewsUrl::SetErrorMessage (const char * errorMessage)
{
// functionality has been moved to nsIMsgStatusFeedback
return NS_ERROR_NOT_IMPLEMENTED;
}
nsresult nsMsgMailNewsUrl::GetErrorMessage (char ** errorMessage)
{
// functionality has been moved to nsIMsgStatusFeedback
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsMsgMailNewsUrl::GetServer(nsIMsgIncomingServer ** aIncomingServer)
{
// mscott --> we could cache a copy of the server here....but if we did, we run
// the risk of leaking the server if any single url gets leaked....of course that
// shouldn't happen...but it could. so i'm going to look it up every time and
// we can look at caching it later.
nsXPIDLCString host;
nsXPIDLCString scheme;
nsresult rv = GetHost(getter_Copies(host));
rv = GetScheme(getter_Copies(scheme));
if (NS_SUCCEEDED(rv))
{
NS_WITH_SERVICE(nsIMsgMailSession, session, kMsgMailSessionCID, &rv);
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIMsgAccountManager> accountManager;
rv = session->GetAccountManager(getter_AddRefs(accountManager));
if(NS_FAILED(rv)) return rv;
nsCOMPtr<nsIMsgIncomingServer> server;
rv = accountManager->FindServer(GetUserName(),
host,
scheme,
aIncomingServer);
}
return rv;
}
NS_IMETHODIMP nsMsgMailNewsUrl::SetStatusFeedback(nsIMsgStatusFeedback *aMsgFeedback)
{
if (aMsgFeedback)
m_statusFeedback = do_QueryInterface(aMsgFeedback);
return NS_OK;
}
NS_IMETHODIMP nsMsgMailNewsUrl::GetStatusFeedback(nsIMsgStatusFeedback **aMsgFeedback)
{
nsresult rv = NS_OK;
// note: it is okay to return a null status feedback and not return an error
// it's possible the url really doesn't have status feedback
if (!m_statusFeedback)
{
NS_WITH_SERVICE(nsIMsgMailSession, mailSession, kMsgMailSessionCID, &rv);
if(NS_SUCCEEDED(rv))
mailSession->GetTemporaryMsgStatusFeedback(getter_AddRefs(m_statusFeedback));
}
if (aMsgFeedback)
{
*aMsgFeedback = m_statusFeedback;
NS_IF_ADDREF(*aMsgFeedback);
}
else
rv = NS_ERROR_NULL_POINTER;
return rv;
}
NS_IMETHODIMP nsMsgMailNewsUrl::GetUpdatingFolder(PRBool *aResult)
{
if (!aResult)
return NS_ERROR_NULL_POINTER;
*aResult = m_updatingFolder;
return NS_OK;
}
NS_IMETHODIMP nsMsgMailNewsUrl::SetUpdatingFolder(PRBool updatingFolder)
{
m_updatingFolder = updatingFolder;
return NS_OK;
}
////////////////////////////////////////////////////////////////////////////////////
// End nsIMsgMailNewsUrl specific support
////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////
// Begin nsIURI support
////////////////////////////////////////////////////////////////////////////////////
NS_IMETHODIMP nsMsgMailNewsUrl::GetSpec(char * *aSpec)
{
return m_baseURL->GetSpec(aSpec);
}
NS_IMETHODIMP nsMsgMailNewsUrl::SetSpec(const char * aSpec)
{
return m_baseURL->SetSpec(aSpec);
}
NS_IMETHODIMP nsMsgMailNewsUrl::GetScheme(char * *aScheme)
{
return m_baseURL->GetScheme(aScheme);
}
NS_IMETHODIMP nsMsgMailNewsUrl::SetScheme(const char * aScheme)
{
return m_baseURL->SetScheme(aScheme);
}
NS_IMETHODIMP nsMsgMailNewsUrl::GetPreHost(char * *aPreHost)
{
return m_baseURL->GetPreHost(aPreHost);
}
NS_IMETHODIMP nsMsgMailNewsUrl::SetPreHost(const char * aPreHost)
{
return m_baseURL->SetPreHost(aPreHost);
}
NS_IMETHODIMP nsMsgMailNewsUrl::GetHost(char * *aHost)
{
return m_baseURL->GetHost(aHost);
}
NS_IMETHODIMP nsMsgMailNewsUrl::SetHost(const char * aHost)
{
return m_baseURL->SetHost(aHost);
}
NS_IMETHODIMP nsMsgMailNewsUrl::GetPort(PRInt32 *aPort)
{
return m_baseURL->GetPort(aPort);
}
NS_IMETHODIMP nsMsgMailNewsUrl::SetPort(PRInt32 aPort)
{
return m_baseURL->SetPort(aPort);
}
NS_IMETHODIMP nsMsgMailNewsUrl::GetPath(char * *aPath)
{
return m_baseURL->GetPath(aPath);
}
NS_IMETHODIMP nsMsgMailNewsUrl::SetPath(const char * aPath)
{
return m_baseURL->SetPath(aPath);
}
NS_IMETHODIMP nsMsgMailNewsUrl::Equals(nsIURI *other, PRBool *_retval)
{
return m_baseURL->Equals(other, _retval);
}
NS_IMETHODIMP nsMsgMailNewsUrl::Clone(nsIURI **_retval)
{
return m_baseURL->Clone(_retval);
}
NS_IMETHODIMP nsMsgMailNewsUrl::SetRelativePath(const char *i_RelativePath)
{
return m_baseURL->SetRelativePath(i_RelativePath);
}
NS_IMETHODIMP nsMsgMailNewsUrl::GetDirectory(char * *aDirectory)
{
return m_baseURL->GetDirectory(aDirectory);
}
NS_IMETHODIMP nsMsgMailNewsUrl::SetDirectory(const char *aDirectory)
{
return m_baseURL->SetDirectory(aDirectory);
}
NS_IMETHODIMP nsMsgMailNewsUrl::GetFileName(char * *aFileName)
{
return m_baseURL->GetFileName(aFileName);
}
NS_IMETHODIMP nsMsgMailNewsUrl::GetFileBaseName(char * *aFileBaseName)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsMsgMailNewsUrl::SetFileBaseName(const char * aFileBaseName)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsMsgMailNewsUrl::GetFileExtension(char * *aFileExtension)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsMsgMailNewsUrl::SetFileExtension(const char * aFileExtension)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsMsgMailNewsUrl::SetFileName(const char * aFileName)
{
return m_baseURL->SetFileName(aFileName);
}
NS_IMETHODIMP nsMsgMailNewsUrl::GetParam(char * *aParam)
{
return m_baseURL->GetParam(aParam);
}
NS_IMETHODIMP nsMsgMailNewsUrl::SetParam(const char *aParam)
{
return m_baseURL->SetParam(aParam);
}
NS_IMETHODIMP nsMsgMailNewsUrl::GetQuery(char * *aQuery)
{
return m_baseURL->GetQuery(aQuery);
}
NS_IMETHODIMP nsMsgMailNewsUrl::SetQuery(const char *aQuery)
{
return m_baseURL->SetQuery(aQuery);
}
NS_IMETHODIMP nsMsgMailNewsUrl::GetRef(char * *aRef)
{
return m_baseURL->GetRef(aRef);
}
NS_IMETHODIMP nsMsgMailNewsUrl::SetRef(const char *aRef)
{
return m_baseURL->SetRef(aRef);
}
NS_IMETHODIMP nsMsgMailNewsUrl::GetFilePath(char **o_DirFile)
{
return m_baseURL->GetFilePath(o_DirFile);
}
NS_IMETHODIMP nsMsgMailNewsUrl::SetFilePath(const char *i_DirFile)
{
return m_baseURL->SetFilePath(i_DirFile);
}

View File

@@ -1,66 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef nsMsgMailNewsUrl_h___
#define nsMsgMailNewsUrl_h___
#include "nscore.h"
#include "nsISupports.h"
#include "nsIUrlListener.h"
#include "nsIUrlListenerManager.h"
#include "nsIMsgStatusFeedback.h"
#include "nsCOMPtr.h"
#include "nsIMsgMailNewsUrl.h"
#include "nsIURL.h"
///////////////////////////////////////////////////////////////////////////////////
// Okay, I found that all of the mail and news url interfaces needed to support
// several common interfaces (in addition to those provided through nsIURI).
// So I decided to group them all in this implementation so we don't have to
// duplicate the code.
//
//////////////////////////////////////////////////////////////////////////////////
class NS_MSG_BASE nsMsgMailNewsUrl : public nsIMsgMailNewsUrl
{
public:
nsMsgMailNewsUrl();
NS_DECL_ISUPPORTS
NS_DECL_NSIMSGMAILNEWSURL
NS_DECL_NSIURI
NS_DECL_NSIURL
protected:
virtual ~nsMsgMailNewsUrl();
// a helper function I needed from derived urls...
virtual const char * GetUserName() = 0;
nsCOMPtr<nsIURL> m_baseURL;
nsCOMPtr<nsIMsgStatusFeedback> m_statusFeedback;
char *m_errorMessage;
PRBool m_runningUrl;
PRBool m_updatingFolder;
// manager of all of current url listeners....
nsCOMPtr<nsIUrlListenerManager> m_urlListeners;
};
#endif /* nsMsgMailNewsUrl_h___ */

View File

@@ -1,369 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "msgCore.h"
#include "nsMsgProtocol.h"
#include "nsIMsgMailNewsUrl.h"
#include "nsISocketTransportService.h"
#include "nsXPIDLString.h"
#include "nsSpecialSystemDirectory.h"
#include "nsILoadGroup.h"
#include "nsIIOService.h"
static NS_DEFINE_CID(kSocketTransportServiceCID, NS_SOCKETTRANSPORTSERVICE_CID);
static NS_DEFINE_CID(kIOServiceCID, NS_IOSERVICE_CID);
NS_IMPL_ISUPPORTS3(nsMsgProtocol, nsIStreamListener, nsIStreamObserver, nsIChannel)
nsMsgProtocol::nsMsgProtocol()
{
NS_INIT_REFCNT();
m_flags = 0;
m_startPosition = 0;
m_readCount = 0;
m_socketIsOpen = PR_FALSE;
m_tempMsgFileSpec = nsSpecialSystemDirectory(nsSpecialSystemDirectory::OS_TemporaryDirectory);
m_tempMsgFileSpec += "tempMessage.eml";
}
nsMsgProtocol::~nsMsgProtocol()
{}
nsresult nsMsgProtocol::OpenNetworkSocket(nsIURI * aURL) // open a connection on this url
{
nsresult rv = NS_OK;
nsXPIDLCString hostName;
PRInt32 port = 0;
m_readCount = -1; // with socket connections we want to read as much data as arrives
m_startPosition = 0;
NS_WITH_SERVICE(nsISocketTransportService, socketService, kSocketTransportServiceCID, &rv);
if (NS_SUCCEEDED(rv) && aURL)
{
aURL->GetPort(&port);
aURL->GetHost(getter_Copies(hostName));
rv = socketService->CreateTransport(hostName, port, nsnull, getter_AddRefs(m_channel));
if (NS_SUCCEEDED(rv) && m_channel)
{
m_socketIsOpen = PR_FALSE;
rv = SetupTransportState();
}
}
return rv;
}
nsresult nsMsgProtocol::OpenFileSocket(nsIURI * aURL, const nsFileSpec * aFileSpec, PRUint32 aStartPosition, PRInt32 aReadCount)
{
// mscott - file needs to be encoded directly into aURL. I should be able to get
// rid of this method completely.
nsresult rv = NS_OK;
m_startPosition = aStartPosition;
m_readCount = aReadCount;
NS_WITH_SERVICE(nsIIOService, netService, kIOServiceCID, &rv);
if (NS_SUCCEEDED(rv) && aURL)
{
// extract the file path from the uri...
nsXPIDLCString filePath;
aURL->GetPath(getter_Copies(filePath));
char * urlSpec = PR_smprintf("file://%s", (const char *) filePath);
rv = netService->NewChannel("Load", urlSpec,
nsnull, // null base URI
nsnull, // null load group
nsnull, // null eventsink getter
getter_AddRefs(m_channel));
PR_FREEIF(urlSpec);
if (NS_SUCCEEDED(rv) && m_channel)
{
m_socketIsOpen = PR_FALSE;
// rv = SetupTransportState();
}
}
return rv;
}
nsresult nsMsgProtocol::SetupTransportState()
{
nsresult rv = NS_OK;
if (!m_socketIsOpen && m_channel)
{
rv = m_channel->OpenOutputStream(0 /* start position */, getter_AddRefs(m_outputStream));
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to create an output stream");
// we want to open the stream
} // if m_transport
return rv;
}
nsresult nsMsgProtocol::CloseSocket()
{
// release all of our socket state
m_socketIsOpen = PR_FALSE;
m_outputStream = null_nsCOMPtr();
m_channel = null_nsCOMPtr();
return NS_OK;
}
/*
* Writes the data contained in dataBuffer into the current output stream. It also informs
* the transport layer that this data is now available for transmission.
* Returns a positive number for success, 0 for failure (not all the bytes were written to the
* stream, etc). We need to make another pass through this file to install an error system (mscott)
*/
PRInt32 nsMsgProtocol::SendData(nsIURI * aURL, const char * dataBuffer)
{
PRUint32 writeCount = 0;
PRInt32 status = 0;
// NS_PRECONDITION(m_outputStream, "oops....we don't have an output stream...how did that happen?");
if (dataBuffer && m_outputStream)
{
status = m_outputStream->Write(dataBuffer, PL_strlen(dataBuffer), &writeCount);
}
return status;
}
// Whenever data arrives from the connection, core netlib notifices the protocol by calling
// OnDataAvailable. We then read and process the incoming data from the input stream.
NS_IMETHODIMP nsMsgProtocol::OnDataAvailable(nsIChannel * /* aChannel */, nsISupports *ctxt, nsIInputStream *inStr, PRUint32 sourceOffset, PRUint32 count)
{
// right now, this really just means turn around and churn through the state machine
nsCOMPtr<nsIURI> uri = do_QueryInterface(ctxt);
return ProcessProtocolState(uri, inStr, sourceOffset, count);
}
NS_IMETHODIMP nsMsgProtocol::OnStartRequest(nsIChannel * aChannel, nsISupports *ctxt)
{
nsresult rv = NS_OK;
nsCOMPtr <nsIMsgMailNewsUrl> aMsgUrl = do_QueryInterface(ctxt, &rv);
if (NS_SUCCEEDED(rv) && aMsgUrl)
rv = aMsgUrl->SetUrlState(PR_TRUE, NS_OK);
// if we are set up as a channel, we should notify our channel listener that we are starting...
// so pass in ourself as the channel and not the underlying socket or file channel the protocol
// happens to be using
if (m_channelListener)
rv = m_channelListener->OnStartRequest(this, m_channelContext);
return rv;
}
// stop binding is a "notification" informing us that the stream associated with aURL is going away.
NS_IMETHODIMP nsMsgProtocol::OnStopRequest(nsIChannel * aChannel, nsISupports *ctxt, nsresult aStatus, const PRUnichar* aMsg)
{
nsresult rv = NS_OK;
nsCOMPtr <nsIMsgMailNewsUrl> aMsgUrl = do_QueryInterface(ctxt, &rv);
if (NS_SUCCEEDED(rv) && aMsgUrl)
rv = aMsgUrl->SetUrlState(PR_FALSE, aStatus);
// if we are set up as a channel, we should notify our channel listener that we are starting...
// so pass in ourself as the channel and not the underlying socket or file channel the protocol
// happens to be using
if (m_channelListener)
rv = m_channelListener->OnStopRequest(this, m_channelContext, aStatus, aMsg);
return rv;
}
nsresult nsMsgProtocol::LoadUrl(nsIURI * aURL, nsISupports * aConsumer)
{
// okay now kick us off to the next state...
// our first state is a process state so drive the state machine...
nsresult rv = NS_OK;
nsCOMPtr <nsIMsgMailNewsUrl> aMsgUrl = do_QueryInterface(aURL);
if (NS_SUCCEEDED(rv))
{
rv = aMsgUrl->SetUrlState(PR_TRUE, NS_OK); // set the url as a url currently being run...
// if the url is given a stream consumer then we should use it to forward calls to...
if (!m_channelListener && aConsumer) // if we don't have a registered listener already
{
m_channelListener = do_QueryInterface(aConsumer);
if (!m_channelContext)
m_channelContext = do_QueryInterface(aURL);
}
if (!m_socketIsOpen)
{
nsCOMPtr<nsISupports> urlSupports = do_QueryInterface(aURL);
// put us in a state where we are always notified of incoming data
m_channel->AsyncRead(m_startPosition, m_readCount, urlSupports ,this /* stream observer */);
m_socketIsOpen = PR_TRUE; // mark the channel as open
} // if we got an event queue service
else // the connection is already open so we should begin processing our new url...
rv = ProcessProtocolState(aURL, nsnull, 0, 0);
}
return rv;
}
///////////////////////////////////////////////////////////////////////
// The rest of this file is mostly nsIChannel mumbo jumbo stuff
///////////////////////////////////////////////////////////////////////
nsresult nsMsgProtocol::SetUrl(nsIURI * aURL)
{
m_url = dont_QueryInterface(aURL);
return NS_OK;
}
nsresult nsMsgProtocol::SetLoadGroup(nsILoadGroup * aLoadGroup)
{
m_loadGroup = dont_QueryInterface(aLoadGroup);
return NS_OK;
}
NS_IMETHODIMP nsMsgProtocol::GetURI(nsIURI * *aURI)
{
nsresult rv = NS_OK;
if (aURI)
{
if (m_url)
rv = m_url->QueryInterface(NS_GET_IID(nsIURI), (void **) aURI);
else
*aURI = nsnull;
}
else
rv = NS_ERROR_NULL_POINTER;
return rv;
}
NS_IMETHODIMP nsMsgProtocol::OpenInputStream(PRUint32 startPosition, PRInt32 readCount, nsIInputStream **_retval)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsMsgProtocol::OpenOutputStream(PRUint32 startPosition, nsIOutputStream **_retval)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsMsgProtocol::AsyncOpen(nsIStreamObserver *observer, nsISupports* ctxt)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsMsgProtocol::AsyncRead(PRUint32 startPosition, PRInt32 readCount, nsISupports *ctxt, nsIStreamListener *listener)
{
// set the stream listener and then load the url
m_channelContext = ctxt;
m_channelListener = listener;
// the following load group code is completely bogus....
nsresult rv = NS_OK;
if (m_loadGroup)
{
nsCOMPtr<nsILoadGroupListenerFactory> factory;
//
// Create a load group "proxy" listener...
//
rv = m_loadGroup->GetGroupListenerFactory(getter_AddRefs(factory));
if (factory)
{
nsCOMPtr<nsIStreamListener> newListener;
rv = factory->CreateLoadGroupListener(m_channelListener, getter_AddRefs(newListener));
if (NS_SUCCEEDED(rv))
m_channelListener = newListener;
}
} // if aLoadGroup
return LoadUrl(m_url, nsnull);
}
NS_IMETHODIMP nsMsgProtocol::AsyncWrite(nsIInputStream *fromStream, PRUint32 startPosition, PRInt32 writeCount, nsISupports *ctxt, nsIStreamObserver *observer)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsMsgProtocol::GetLoadAttributes(nsLoadFlags *aLoadAttributes)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsMsgProtocol::SetLoadAttributes(nsLoadFlags aLoadAttributes)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsMsgProtocol::GetContentType(char * *aContentType)
{
*aContentType = nsCRT::strdup("message/rfc822");
return NS_OK;
}
NS_IMETHODIMP nsMsgProtocol::GetContentLength(PRInt32 * aContentLength)
{
*aContentLength = -1;
return NS_OK;
}
NS_IMETHODIMP nsMsgProtocol::GetOwner(nsISupports * *aPrincipal)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsMsgProtocol::SetOwner(nsISupports * aPrincipal)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsMsgProtocol::GetLoadGroup(nsILoadGroup * *aLoadGroup)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
////////////////////////////////////////////////////////////////////////////////
// From nsIRequest
////////////////////////////////////////////////////////////////////////////////
NS_IMETHODIMP nsMsgProtocol::IsPending(PRBool *result)
{
*result = PR_TRUE;
return NS_OK;
}
NS_IMETHODIMP nsMsgProtocol::Cancel()
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsMsgProtocol::Suspend()
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsMsgProtocol::Resume()
{
return NS_ERROR_NOT_IMPLEMENTED;
}

View File

@@ -1,108 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef nsMsgProtocol_h__
#define nsMsgProtocol_h__
#include "nsIStreamListener.h"
#include "nsIInputStream.h"
#include "nsIOutputStream.h"
#include "nsIEventQueue.h"
#include "nsIChannel.h"
#include "nsIURL.h"
#include "nsILoadGroup.h"
#include "nsCOMPtr.h"
// This is a helper class used to encapsulate code shared between all of the
// mailnews protocol objects (imap, news, pop, smtp, etc.) In particular,
// it unifies the core networking code for the protocols. My hope is that
// this will make unification with Necko easier as we'll only have to change
// this class and not all of the mailnews protocols.
class NS_MSG_BASE nsMsgProtocol : public nsIStreamListener, public nsIChannel
{
public:
nsMsgProtocol();
virtual ~nsMsgProtocol();
NS_DECL_ISUPPORTS
// nsIChannel support
NS_DECL_NSICHANNEL
NS_DECL_NSIREQUEST
NS_DECL_NSISTREAMLISTENER
NS_DECL_NSISTREAMOBSERVER
// LoadUrl -- A protocol typically overrides this function, sets up any local state for the url and
// then calls the base class which opens the socket if it needs opened. If the socket is
// already opened then we just call ProcessProtocolState to start the churning process.
// aConsumer is the consumer for the url. It can be null if this argument is not appropriate
virtual nsresult LoadUrl(nsIURI * aURL, nsISupports * aConsumer = nsnull);
virtual nsresult SetUrl(nsIURI * aURL); // sometimes we want to set the url before we load it
virtual nsresult SetLoadGroup(nsILoadGroup * aLoadGroup);
// Flag manipulators
PRBool TestFlag (PRUint32 flag) {return flag & m_flags;}
void SetFlag (PRUint32 flag) { m_flags |= flag; }
void ClearFlag (PRUint32 flag) { m_flags &= ~flag; }
protected:
// methods for opening and closing a socket with core netlib....
// mscott -okay this is lame. I should break this up into a file protocol and a socket based
// protocool class instead of cheating and putting both methods here...
virtual nsresult OpenNetworkSocket(nsIURI * aURL); // open a connection on this url
virtual nsresult OpenFileSocket(nsIURI * aURL, const nsFileSpec * aFileSpec, PRUint32 aStartPosition, PRInt32 aReadCount); // used to open a file socket connection
// a Protocol typically overrides this method. They free any of their own connection state and then
// they call up into the base class to free the generic connection objects
virtual nsresult CloseSocket();
virtual nsresult SetupTransportState(); // private method used by OpenNetworkSocket and OpenFileSocket
// ProcessProtocolState - This is the function that gets churned by calls to OnDataAvailable.
// As data arrives on the socket, OnDataAvailable calls ProcessProtocolState.
virtual nsresult ProcessProtocolState(nsIURI * url, nsIInputStream * inputStream,
PRUint32 sourceOffset, PRUint32 length) = 0;
// SendData -- Writes the data contained in dataBuffer into the current output stream.
// It also informs the transport layer that this data is now available for transmission.
// Returns a positive number for success, 0 for failure (not all the bytes were written to the
// stream, etc).
virtual PRInt32 SendData(nsIURI * aURL, const char * dataBuffer);
// Ouput stream for writing commands to the socket
nsCOMPtr<nsIChannel> m_channel;
nsCOMPtr<nsIOutputStream> m_outputStream; // this will be obtained from the transport interface
PRBool m_socketIsOpen; // mscott: we should look into keeping this state in the nsSocketTransport...
// I'm using it to make sure I open the socket the first time a URL is loaded into the connection
PRUint32 m_flags; // used to store flag information
PRUint32 m_startPosition;
PRInt32 m_readCount;
nsFileSpec m_tempMsgFileSpec; // we currently have a hack where displaying a msg involves writing it to a temp file first
// the following is a catch all for nsIChannel related data
nsCOMPtr<nsIURI> m_url; // the running url
nsCOMPtr<nsIStreamListener> m_channelListener;
nsCOMPtr<nsISupports> m_channelContext;
nsCOMPtr<nsILoadGroup> m_loadGroup;
};
#endif /* nsMsgProtocol_h__ */

View File

@@ -1,99 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998, 1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "nsMsgTxn.h"
static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID);
static NS_DEFINE_IID(kITransactionIID, NS_ITRANSACTION_IID);
NS_IMPL_ADDREF(nsMsgTxn)
NS_IMPL_RELEASE(nsMsgTxn)
// note that aEditor is not refcounted
nsMsgTxn::nsMsgTxn()
{
NS_INIT_REFCNT();
}
nsMsgTxn::~nsMsgTxn()
{
}
NS_IMETHODIMP nsMsgTxn::Do(void)
{
return NS_OK;
}
NS_IMETHODIMP nsMsgTxn::GetIsTransient(PRBool *aIsTransient)
{
if (nsnull!=aIsTransient)
*aIsTransient = PR_FALSE;
else
return NS_ERROR_NULL_POINTER;
return NS_OK;
}
NS_IMETHODIMP nsMsgTxn::Merge(PRBool *aDidMerge, nsITransaction *aTransaction)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsMsgTxn::Write(nsIOutputStream *aOutputStream)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsMsgTxn::GetUndoString(nsString *aString)
{
if (nsnull!=aString)
*aString="Undo";
else
return NS_ERROR_NULL_POINTER;
return NS_OK;
}
NS_IMETHODIMP nsMsgTxn::GetRedoString(nsString *aString)
{
if (nsnull!=aString)
*aString="Redo";
else
return NS_ERROR_NULL_POINTER;
return NS_OK;
}
NS_IMETHODIMP
nsMsgTxn::QueryInterface(REFNSIID aIID, void** aInstancePtr)
{
if (NULL == aInstancePtr) {
return NS_ERROR_NULL_POINTER;
}
if (aIID.Equals(kISupportsIID)) {
*aInstancePtr = (void*)(nsISupports*)this;
NS_ADDREF_THIS();
return NS_OK;
}
if (aIID.Equals(kITransactionIID)) {
*aInstancePtr = (void*)(nsITransaction*)this;
NS_ADDREF_THIS();
return NS_OK;
}
*aInstancePtr = 0;
return NS_NOINTERFACE;
}

View File

@@ -1,57 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998, 1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef nsMsgTxn_h__
#define nsMsgTxn_h__
#include "nsITransaction.h"
#include "msgCore.h"
#define NS_MESSAGETRANSACTION_IID \
{ /* da621b30-1efc-11d3-abe4-00805f8ac968 */ \
0xda621b30, 0x1efc, 0x11d3, \
{ 0xab, 0xe4, 0x00, 0x80, 0x5f, 0x8a, 0xc9, 0x68 } }
/**
* base class for all message undo/redo transactions.
*/
class NS_MSG_BASE nsMsgTxn : public nsITransaction
{
NS_DECL_ISUPPORTS
nsMsgTxn();
virtual ~nsMsgTxn();
NS_IMETHOD Do(void);
NS_IMETHOD Undo(void) = 0;
NS_IMETHOD Redo(void) = 0;
NS_IMETHOD GetIsTransient(PRBool *aIsTransient);
NS_IMETHOD Merge(PRBool *aDidMerge, nsITransaction *aTransaction);
NS_IMETHOD Write(nsIOutputStream *aOutputStream);
NS_IMETHOD GetUndoString(nsString *aString);
NS_IMETHOD GetRedoString(nsString *aString);
};
#endif

View File

@@ -1,326 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "msgCore.h"
#include "nsIMessage.h"
#include "nsIMsgHdr.h"
#include "nsMsgUtils.h"
#include "nsString.h"
#include "nsFileSpec.h"
#include "nsIServiceManager.h"
#include "nsCOMPtr.h"
#include "nsString.h"
#include "nsIImapUrl.h"
#include "nsIMailboxUrl.h"
#include "nsINntpUrl.h"
#include "nsMsgNewsCID.h"
#include "nsMsgLocalCID.h"
#include "nsMsgBaseCID.h"
#include "nsMsgImapCID.h"
static NS_DEFINE_CID(kImapUrlCID, NS_IMAPURL_CID);
static NS_DEFINE_CID(kCMailboxUrl, NS_MAILBOXURL_CID);
static NS_DEFINE_CID(kCNntpUrlCID, NS_NNTPURL_CID);
#if defined(DEBUG_sspitzer_) || defined(DEBUG_seth_)
#define DEBUG_NS_MsgHashIfNecessary 1
#endif
nsresult GetMessageServiceProgIDForURI(const char *uri, nsString &progID)
{
nsresult rv = NS_OK;
//Find protocol
nsString uriStr = uri;
PRInt32 pos = uriStr.FindChar(':');
if(pos == -1)
return NS_ERROR_FAILURE;
nsString protocol;
uriStr.Left(protocol, pos);
//Build message service progid
progID = "component://netscape/messenger/messageservice;type=";
progID += protocol;
return rv;
}
nsresult GetMessageServiceFromURI(const char *uri, nsIMsgMessageService **messageService)
{
nsAutoString progID;
nsresult rv;
rv = GetMessageServiceProgIDForURI(uri, progID);
if(NS_SUCCEEDED(rv))
{
rv = nsServiceManager::GetService((const char *) nsCAutoString(progID), nsCOMTypeInfo<nsIMsgMessageService>::GetIID(),
(nsISupports**)messageService, nsnull);
}
return rv;
}
nsresult ReleaseMessageServiceFromURI(const char *uri, nsIMsgMessageService *messageService)
{
nsAutoString progID;
nsresult rv;
rv = GetMessageServiceProgIDForURI(uri, progID);
if(NS_SUCCEEDED(rv))
rv = nsServiceManager::ReleaseService(nsCAutoString(progID), messageService);
return rv;
}
nsresult CreateStartupUrl(char *uri, nsIURI** aUrl)
{
nsresult rv = NS_ERROR_NULL_POINTER;
if (!uri || !*uri || !aUrl) return rv;
*aUrl = nsnull;
if (PL_strncasecmp(uri, "imap", 4) == 0)
{
nsCOMPtr<nsIImapUrl> imapUrl;
rv = nsComponentManager::CreateInstance(kImapUrlCID, nsnull,
nsIImapUrl::GetIID(),
getter_AddRefs(imapUrl));
if (NS_SUCCEEDED(rv) && imapUrl)
rv = imapUrl->QueryInterface(nsCOMTypeInfo<nsIURI>::GetIID(),
(void**) aUrl);
}
else if (PL_strncasecmp(uri, "mailbox", 7) == 0)
{
nsCOMPtr<nsIMailboxUrl> mailboxUrl;
rv = nsComponentManager::CreateInstance(kCMailboxUrl, nsnull,
nsIMailboxUrl::GetIID(),
getter_AddRefs(mailboxUrl));
if (NS_SUCCEEDED(rv) && mailboxUrl)
rv = mailboxUrl->QueryInterface(nsCOMTypeInfo<nsIURI>::GetIID(),
(void**) aUrl);
}
else if (PL_strncasecmp(uri, "news", 4) == 0)
{
nsCOMPtr<nsINntpUrl> nntpUrl;
rv = nsComponentManager::CreateInstance(kCNntpUrlCID, nsnull,
nsINntpUrl::GetIID(),
getter_AddRefs(nntpUrl));
if (NS_SUCCEEDED(rv) && nntpUrl)
rv = nntpUrl->QueryInterface(nsCOMTypeInfo<nsIURI>::GetIID(),
(void**) aUrl);
}
if (*aUrl)
(*aUrl)->SetSpec(uri);
return rv;
}
NS_IMPL_ISUPPORTS(nsMessageFromMsgHdrEnumerator, nsCOMTypeInfo<nsISimpleEnumerator>::GetIID())
nsMessageFromMsgHdrEnumerator::nsMessageFromMsgHdrEnumerator(nsISimpleEnumerator *srcEnumerator,
nsIMsgFolder *folder)
{
NS_INIT_REFCNT();
mSrcEnumerator = dont_QueryInterface(srcEnumerator);
mFolder = dont_QueryInterface(folder);
}
nsMessageFromMsgHdrEnumerator::~nsMessageFromMsgHdrEnumerator()
{
//member variables are nsCOMPtr's
}
NS_IMETHODIMP nsMessageFromMsgHdrEnumerator::GetNext(nsISupports **aItem)
{
nsCOMPtr<nsISupports> currentItem;
nsCOMPtr<nsIMsgDBHdr> msgDBHdr;
nsCOMPtr<nsIMessage> message;
nsresult rv;
rv = mSrcEnumerator->GetNext(getter_AddRefs(currentItem));
if(NS_SUCCEEDED(rv))
{
msgDBHdr = do_QueryInterface(currentItem, &rv);
}
if(NS_SUCCEEDED(rv))
{
rv = mFolder->CreateMessageFromMsgDBHdr(msgDBHdr, getter_AddRefs(message));
}
if(NS_SUCCEEDED(rv))
{
currentItem = do_QueryInterface(message, &rv);
*aItem = currentItem;
NS_IF_ADDREF(*aItem);
}
NS_ASSERTION(NS_SUCCEEDED(rv),"getnext shouldn't fail");
return rv;
}
NS_IMETHODIMP nsMessageFromMsgHdrEnumerator::HasMoreElements(PRBool *aResult)
{
return mSrcEnumerator->HasMoreElements(aResult);
}
nsresult NS_NewMessageFromMsgHdrEnumerator(nsISimpleEnumerator *srcEnumerator,
nsIMsgFolder *folder,
nsMessageFromMsgHdrEnumerator **messageEnumerator)
{
if(!messageEnumerator)
return NS_ERROR_NULL_POINTER;
*messageEnumerator = new nsMessageFromMsgHdrEnumerator(srcEnumerator, folder);
if(!messageEnumerator)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(*messageEnumerator);
return NS_OK;
}
// Where should this live? It's a utility used to convert a string priority, e.g., "High, Low, Normal" to an enum.
// Perhaps we should have an interface that groups together all these utilities...
nsresult NS_MsgGetPriorityFromString(const char *priority, nsMsgPriority *outPriority)
{
if (!outPriority)
return NS_ERROR_NULL_POINTER;
nsMsgPriority retPriority = nsMsgPriorityNormal;
if (PL_strcasestr(priority, "Normal") != NULL)
retPriority = nsMsgPriorityNormal;
else if (PL_strcasestr(priority, "Lowest") != NULL)
retPriority = nsMsgPriorityLowest;
else if (PL_strcasestr(priority, "Highest") != NULL)
retPriority = nsMsgPriorityHighest;
else if (PL_strcasestr(priority, "High") != NULL ||
PL_strcasestr(priority, "Urgent") != NULL)
retPriority = nsMsgPriorityHigh;
else if (PL_strcasestr(priority, "Low") != NULL ||
PL_strcasestr(priority, "Non-urgent") != NULL)
retPriority = nsMsgPriorityLow;
else if (PL_strcasestr(priority, "1") != NULL)
retPriority = nsMsgPriorityHighest;
else if (PL_strcasestr(priority, "2") != NULL)
retPriority = nsMsgPriorityHigh;
else if (PL_strcasestr(priority, "3") != NULL)
retPriority = nsMsgPriorityNormal;
else if (PL_strcasestr(priority, "4") != NULL)
retPriority = nsMsgPriorityLow;
else if (PL_strcasestr(priority, "5") != NULL)
retPriority = nsMsgPriorityLowest;
else
retPriority = nsMsgPriorityNormal;
*outPriority = retPriority;
return NS_OK;
//return nsMsgNoPriority;
}
nsresult NS_MsgGetUntranslatedPriorityName (nsMsgPriority p, nsString *outName)
{
if (!outName)
return NS_ERROR_NULL_POINTER;
switch (p)
{
case nsMsgPriorityNotSet:
case nsMsgPriorityNone:
*outName = "None";
break;
case nsMsgPriorityLowest:
*outName = "Lowest";
break;
case nsMsgPriorityLow:
*outName = "Low";
break;
case nsMsgPriorityNormal:
*outName = "Normal";
break;
case nsMsgPriorityHigh:
*outName = "High";
break;
case nsMsgPriorityHighest:
*outName = "Highest";
break;
default:
NS_ASSERTION(PR_FALSE, "invalid priority value");
}
return NS_OK;
}
/* this used to be XP_StringHash2 from xp_hash.c */
/* phong's linear congruential hash */
static PRUint32 StringHash(const char *ubuf)
{
unsigned char * buf = (unsigned char*) ubuf;
PRUint32 h=1;
while(*buf) {
h = 0x63c63cd9*h + 0x9c39c33d + (int32)*buf;
buf++;
}
return h;
}
nsresult NS_MsgHashIfNecessary(nsCAutoString &name)
{
#if defined(XP_WIN16) || defined(XP_OS2)
const PRUint32 MAX_LEN = 8;
#elif defined(XP_MAC)
const PRUint32 MAX_LEN = 25;
#elif defined(XP_UNIX) || defined(XP_PC) || defined(XP_BEOS)
const PRUint32 MAX_LEN = 55;
#else
#error need_to_define_your_max_filename_length
#endif
nsCAutoString str(name);
#ifdef DEBUG_NS_MsgHashIfNecessary
printf("in: %s\n",str.GetBuffer());
#endif
// Given a name, use either that name, if it fits on our
// filesystem, or a hashified version of it, if the name is too
// long to fit.
char hashedname[MAX_LEN + 1];
PRBool needshash = PL_strlen(str.GetBuffer()) > MAX_LEN;
#if defined(XP_WIN16) || defined(XP_OS2)
if (!needshash) {
needshash = PL_strchr(str.GetBuffer(), '.') != NULL ||
PL_strchr(str.GetBuffer(), ':') != NULL;
}
#endif
PL_strncpy(hashedname, str.GetBuffer(), MAX_LEN + 1);
if (needshash) {
PR_snprintf(hashedname + MAX_LEN - 8, 9, "%08lx",
(unsigned long) StringHash(str.GetBuffer()));
}
name = hashedname;
#ifdef DEBUG_NS_MsgHashIfNecessary
printf("out: %s\n",hashedname);
#endif
return NS_OK;
}

View File

@@ -1,67 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _NSMSGUTILS_H
#define _NSMSGUTILS_H
#include "nsIURL.h"
#include "nsIMsgMessageService.h"
#include "nsString.h"
#include "nsIEnumerator.h"
#include "nsIMsgFolder.h"
#include "msgCore.h"
#include "nsCOMPtr.h"
//These are utility functions that can used throughout the mailnews code
//Utilities for getting a message service.
NS_MSG_BASE nsresult GetMessageServiceProgIDForURI(const char *uri, nsString &progID);
//Use ReleaseMessageServiceFromURI to release the service.
NS_MSG_BASE nsresult GetMessageServiceFromURI(const char *uri, nsIMsgMessageService **messageService);
NS_MSG_BASE nsresult ReleaseMessageServiceFromURI(const char *uri, nsIMsgMessageService *messageService);
NS_MSG_BASE nsresult CreateStartupUrl(char *uri, nsIURI** aUrl);
//An enumerator for converting nsIMsgHdrs to nsIMessages.
class NS_MSG_BASE nsMessageFromMsgHdrEnumerator: public nsISimpleEnumerator
{
protected:
nsCOMPtr<nsISimpleEnumerator> mSrcEnumerator;
nsCOMPtr<nsIMsgFolder> mFolder;
public:
NS_DECL_ISUPPORTS
nsMessageFromMsgHdrEnumerator(nsISimpleEnumerator *srcEnumerator, nsIMsgFolder *folder);
nsMessageFromMsgHdrEnumerator(){} //Default constructor that does nothing so nsComPtr will work.
virtual ~nsMessageFromMsgHdrEnumerator();
NS_DECL_NSISIMPLEENUMERATOR
};
NS_MSG_BASE nsresult NS_NewMessageFromMsgHdrEnumerator(nsISimpleEnumerator *srcEnumerator,
nsIMsgFolder *folder,
nsMessageFromMsgHdrEnumerator **messageEnumerator);
NS_MSG_BASE nsresult NS_MsgGetPriorityFromString(const char *priority, nsMsgPriority *outPriority);
NS_MSG_BASE nsresult NS_MsgGetUntranslatedPriorityName (nsMsgPriority p, nsString *outName);
NS_MSG_BASE nsresult NS_MsgHashIfNecessary(nsCAutoString &name);
#endif

View File

@@ -1,71 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "nsNewsSummarySpec.h"
#include "plstr.h"
#include "nsString.h"
MOZ_DECL_CTOR_COUNTER(nsNewsSummarySpec);
nsNewsSummarySpec::~nsNewsSummarySpec()
{
MOZ_COUNT_DTOR(nsNewsSummarySpec);
}
nsNewsSummarySpec::nsNewsSummarySpec()
{
MOZ_COUNT_CTOR(nsNewsSummarySpec);
}
nsNewsSummarySpec::nsNewsSummarySpec(const char *folderPath)
: nsFileSpec(folderPath)
{
MOZ_COUNT_CTOR(nsNewsSummarySpec);
CreateSummaryFileName();
}
nsNewsSummarySpec::nsNewsSummarySpec(const nsFileSpec& inFolderPath)
: nsFileSpec(inFolderPath)
{
MOZ_COUNT_CTOR(nsNewsSummarySpec);
CreateSummaryFileName();
}
nsNewsSummarySpec::nsNewsSummarySpec(const nsFilePath &inFolderPath) : nsFileSpec(inFolderPath)
{
MOZ_COUNT_CTOR(nsNewsSummarySpec);
CreateSummaryFileName();
}
void nsNewsSummarySpec::SetFolderName(const char *folderPath)
{
*this = folderPath;
}
void nsNewsSummarySpec::CreateSummaryFileName()
{
char *leafName = GetLeafName();
nsCAutoString fullLeafName((const char*)leafName);
// Append .msf (message summary file)
fullLeafName += ".msf";
SetLeafName(fullLeafName.GetBuffer());
PL_strfree(leafName);
}

View File

@@ -1,45 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _nsNewsSummarySpec_H
#define _nsNewsSummarySpec_H
#include "nsFileSpec.h"
#include "msgCore.h"
// Class to name a summary file for a newsgroup,
// given a full folder file spec.
// Note this class expects the invoking code to fully specify the folder path.
// This class does NOT prepend the local folder directory, or put .sbd on the containing
// directory names.
class NS_MSG_BASE nsNewsSummarySpec : public nsFileSpec
{
public:
nsNewsSummarySpec();
nsNewsSummarySpec(const char *folderPath);
nsNewsSummarySpec(const nsFileSpec& inFolderPath);
nsNewsSummarySpec(const nsFilePath &inFolderPath);
~nsNewsSummarySpec();
void SetFolderName(const char *folderPath);
protected:
void CreateSummaryFileName();
};
#endif /* _nsNewsSummarySpec_H */

View File

@@ -1,277 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "msgCore.h" // precompiled header...
#include "prlog.h"
#include "MailNewsTypes.h"
#include "nsUInt32Array.h"
#include "nsQuickSort.h"
MOZ_DECL_CTOR_COUNTER(nsUInt32Array);
nsUInt32Array::nsUInt32Array()
{
MOZ_COUNT_CTOR(nsUInt32Array);
m_nSize = 0;
m_nMaxSize = 0;
m_nGrowBy = 0;
m_pData = NULL;
}
nsUInt32Array::~nsUInt32Array()
{
MOZ_COUNT_DTOR(nsUInt32Array);
SetSize(0);
}
/////////////////////////////////////////////////////////////////////////////
PRUint32 nsUInt32Array::GetSize() const
{
return m_nSize;
}
PRBool nsUInt32Array::SetSize(PRUint32 nSize,
PRBool adjustGrowth,
PRUint32 nGrowBy)
{
if (adjustGrowth)
m_nGrowBy = nGrowBy;
#ifdef MAX_ARR_ELEMS
if (nSize > MAX_ARR_ELEMS);
{
PR_ASSERT(nSize <= MAX_ARR_ELEMS); // Will fail
return PR_FALSE;
}
#endif
if (nSize == 0)
{
// Remove all elements
PR_Free(m_pData);
m_nSize = 0;
m_nMaxSize = 0;
m_pData = NULL;
}
else if (m_pData == NULL)
{
// Create a new array
m_nMaxSize = PR_MAX(8, nSize);
m_pData = (PRUint32 *)PR_Calloc(1, m_nMaxSize * sizeof(PRUint32));
if (m_pData)
m_nSize = nSize;
else
m_nSize = m_nMaxSize = 0;
}
else if (nSize <= m_nMaxSize)
{
// The new size is within the current maximum size, make sure new
// elements are to initialized to zero
if (nSize > m_nSize)
nsCRT::memset(&m_pData[m_nSize], 0, (nSize - m_nSize) * sizeof(PRUint32));
m_nSize = nSize;
}
else
{
// The array needs to grow, figure out how much
PRUint32 nMaxSize;
nGrowBy = PR_MAX(m_nGrowBy, PR_MIN(1024, PR_MAX(8, m_nSize / 8)));
nMaxSize = PR_MAX(nSize, m_nMaxSize + nGrowBy);
#ifdef MAX_ARR_ELEMS
nMaxSize = PR_MIN(MAX_ARR_ELEMS, nMaxSize);
#endif
PRUint32 *pNewData = (PRUint32 *)PR_Malloc(nMaxSize * sizeof(PRUint32));
if (pNewData)
{
// Copy the data from the old array to the new one
nsCRT::memcpy(pNewData, m_pData, m_nSize * sizeof(PRUint32));
// Zero out the remaining elements
nsCRT::memset(&pNewData[m_nSize], 0, (nSize - m_nSize) * sizeof(PRUint32));
m_nSize = nSize;
m_nMaxSize = nMaxSize;
// Free the old array
PR_Free(m_pData);
m_pData = pNewData;
}
}
return nSize == m_nSize;
}
/////////////////////////////////////////////////////////////////////////////
PRUint32 &nsUInt32Array::ElementAt(PRUint32 nIndex)
{
PR_ASSERT(nIndex < m_nSize);
return m_pData[nIndex];
}
PRUint32 nsUInt32Array::GetAt(PRUint32 nIndex) const
{
PR_ASSERT(nIndex < m_nSize);
return m_pData[nIndex];
}
PRUint32 *nsUInt32Array::GetData()
{
return m_pData;
}
void nsUInt32Array::SetAt(PRUint32 nIndex, PRUint32 newElement)
{
PR_ASSERT(nIndex < m_nSize);
m_pData[nIndex] = newElement;
}
/////////////////////////////////////////////////////////////////////////////
PRUint32 nsUInt32Array::Add(PRUint32 newElement)
{
PRUint32 nIndex = m_nSize;
#ifdef MAX_ARR_ELEMS
if (nIndex >= MAX_ARR_ELEMS)
return -1;
#endif
SetAtGrow(nIndex, newElement);
return nIndex;
}
PRUint32 nsUInt32Array::Add(PRUint32 *elementPtr, PRUint32 numElements)
{
if (SetSize(m_nSize + numElements))
nsCRT::memcpy(m_pData + m_nSize, elementPtr, numElements * sizeof(PRUint32));
return m_nSize;
}
PRUint32 *nsUInt32Array::CloneData()
{
PRUint32 *copyOfData = (PRUint32 *)PR_Malloc(m_nSize * sizeof(PRUint32));
if (copyOfData)
nsCRT::memcpy(copyOfData, m_pData, m_nSize * sizeof(PRUint32));
return copyOfData;
}
void nsUInt32Array::InsertAt(PRUint32 nIndex, PRUint32 newElement, PRUint32 nCount)
{
PR_ASSERT(nCount > 0);
if (nIndex >= m_nSize)
{
// If the new element is after the end of the array, grow the array
SetSize(nIndex + nCount);
}
else
{
// The element is being insert inside the array
int nOldSize = m_nSize;
SetSize(m_nSize + nCount);
// Move the data after the insertion point
nsCRT::memmove(&m_pData[nIndex + nCount], &m_pData[nIndex],
(nOldSize - nIndex) * sizeof(PRUint32));
}
// Insert the new elements
PR_ASSERT(nIndex + nCount <= m_nSize);
while (nCount--)
m_pData[nIndex++] = newElement;
}
void nsUInt32Array::InsertAt(PRUint32 nStartIndex, const nsUInt32Array *pNewArray)
{
PR_ASSERT(pNewArray != NULL);
if (pNewArray->GetSize() > 0)
{
InsertAt(nStartIndex, pNewArray->GetAt(0), pNewArray->GetSize());
for (PRUint32 i = 1; i < pNewArray->GetSize(); i++)
m_pData[nStartIndex + i] = pNewArray->GetAt(i);
}
}
void nsUInt32Array::RemoveAll()
{
SetSize(0);
}
void nsUInt32Array::RemoveAt(PRUint32 nIndex, PRUint32 nCount)
{
PR_ASSERT(nIndex + nCount <= m_nSize);
if (nCount > 0)
{
// Make sure not to overstep the end of the array
int nMoveCount = m_nSize - (nIndex + nCount);
if (nCount && nMoveCount)
nsCRT::memmove(&m_pData[nIndex], &m_pData[nIndex + nCount],
nMoveCount * sizeof(PRUint32));
m_nSize -= nCount;
}
}
void nsUInt32Array::SetAtGrow(PRUint32 nIndex, PRUint32 newElement)
{
if (nIndex >= m_nSize)
SetSize(nIndex+1);
m_pData[nIndex] = newElement;
}
/////////////////////////////////////////////////////////////////////////////
void nsUInt32Array::CopyArray(nsUInt32Array *oldA)
{
CopyArray(*oldA);
}
void nsUInt32Array::CopyArray(nsUInt32Array &oldA)
{
if (m_pData)
PR_Free(m_pData);
m_nSize = oldA.m_nSize;
m_nMaxSize = oldA.m_nMaxSize;
m_pData = (PRUint32 *)PR_Malloc(m_nSize * sizeof(PRUint32));
if (m_pData)
nsCRT::memcpy(m_pData, oldA.m_pData, m_nSize * sizeof(PRUint32));
}
/////////////////////////////////////////////////////////////////////////////
static int CompareDWord (const void *v1, const void *v2, void *)
{
// QuickSort callback to compare array values
PRUint32 i1 = *(PRUint32 *)v1;
PRUint32 i2 = *(PRUint32 *)v2;
return i1 - i2;
}
void nsUInt32Array::QuickSort (int (*compare) (const void *elem1, const void *elem2, void *data))
{
if (m_nSize > 1)
NS_QuickSort(m_pData, m_nSize, sizeof(void*), compare ? compare : CompareDWord, nsnull);
}

View File

@@ -1,73 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _nsUInt32Array_H_
#define _nsUInt32Array_H_
#include "nscore.h"
#include "nsCRT.h"
#include "prmem.h"
#include "msgCore.h"
class NS_MSG_BASE nsUInt32Array
{
public:
// Construction/destruction
nsUInt32Array();
virtual ~nsUInt32Array();
// State/attribute member functions
PRUint32 GetSize() const;
PRBool SetSize(PRUint32 nNewSize, PRBool AdjustGrowth=PR_FALSE, PRUint32 nGrowBy = 0);
// Accessor member functions
PRUint32 &ElementAt(PRUint32 nIndex);
PRUint32 GetAt(PRUint32 nIndex) const;
PRUint32 *GetData();
void SetAt(PRUint32 nIndex, PRUint32 newElement);
// Insertion/deletion member functions
PRUint32 Add(PRUint32 newElement);
PRUint32 Add(PRUint32 *elementPtr, PRUint32 numElements);
void InsertAt(PRUint32 nIndex, PRUint32 newElement, PRUint32 nCount = 1);
void InsertAt(PRUint32 nStartIndex, const nsUInt32Array *pNewArray);
void RemoveAll();
void RemoveAt(PRUint32 nIndex, PRUint32 nCount = 1);
void SetAtGrow(PRUint32 nIndex, PRUint32 newElement);
// Sorting member functions
void QuickSort(int (*compare) (const void *elem1, const void *elem2, void *) = NULL);
// Overloaded operators
PRUint32 operator[](PRUint32 nIndex) const { return GetAt(nIndex); }
PRUint32 &operator[](PRUint32 nIndex) { return ElementAt(nIndex); }
// Miscellaneous member functions
PRUint32 *CloneData();
void CopyArray(nsUInt32Array *oldA);
void CopyArray(nsUInt32Array &oldA);
protected:
// Member data
PRUint32 m_nSize;
PRUint32 m_nMaxSize;
PRUint32 m_nGrowBy;
PRUint32* m_pData;
};
#endif // _DWordArray_H_

File diff suppressed because it is too large Load Diff

38
mozilla/netwerk/cache/Makefile.in vendored Normal file
View File

@@ -0,0 +1,38 @@
#
# The contents of this file are subject to the Netscape Public
# License Version 1.1 (the "License"); you may not use this file
# except in compliance with the License. You may obtain a copy of
# the License at http://www.mozilla.org/NPL/
#
# Software distributed under the License is distributed on an "AS
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
# implied. See the License for the specific language governing
# rights and limitations under the License.
#
# The Original Code is mozilla.org code.
#
# The Initial Developer of the Original Code is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s):
#
DEPTH = ../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
DIRS = \
public \
memcache \
filecache \
mgr \
build \
$(NULL)
include $(topsrcdir)/config/rules.mk

33
mozilla/netwerk/cache/Makefile.win vendored Executable file
View File

@@ -0,0 +1,33 @@
#!gmake
#
# The contents of this file are subject to the Netscape Public
# License Version 1.1 (the "License"); you may not use this file
# except in compliance with the License. You may obtain a copy of
# the License at http://www.mozilla.org/NPL/
#
# Software distributed under the License is distributed on an "AS
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
# implied. See the License for the specific language governing
# rights and limitations under the License.
#
# The Original Code is mozilla.org code.
#
# The Initial Developer of the Original Code is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s):
DEPTH=..\..
DIRS= \
public \
mgr \
memcache \
filecache \
build \
$(NULL)
include <$(DEPTH)\config\rules.mak>

View File

@@ -22,54 +22,33 @@ VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
MODULE = msgbaseutil
LIBRARY_NAME = msgbaseutil
MODULE = nkcacke
LIBRARY_NAME = necko_cache
IS_COMPONENT = 1
CPPSRCS = \
nsMsgGroupRecord.cpp \
nsMsgLineBuffer.cpp \
nsMsgFolder.cpp \
nsMsgDBFolder.cpp \
nsUInt32Array.cpp \
nsMsgKeySet.cpp \
nsLocalFolderSummarySpec.cpp \
nsNewsSummarySpec.cpp \
nsMsgIdentity.cpp \
nsMsgIncomingServer.cpp \
nsMsgUtils.cpp \
nsMessage.cpp \
nsMsgProtocol.cpp \
nsMsgMailNewsUrl.cpp \
nsMsgTxn.cpp \
nsMsgI18N.cpp \
CPPSRCS = nsNetDataCacheModule.cpp
SHARED_LIBRARY_LIBS = \
$(DIST)/lib/libnkcachemgr_s.a \
$(DIST)/lib/libnkfilecache_s.a \
$(DIST)/lib/libnkmemcache_s.a \
$(DIST)/lib/libmozdbm_s.a \
$(DIST)/lib/libxpcomio_s.a \
$(NULL)
EXPORTS = \
nsMsgGroupRecord.h \
nsMsgLineBuffer.h \
nsUInt32Array.h \
nsMsgKeySet.h \
nsMsgFolder.h \
nsMsgDBFolder.h \
nsLocalFolderSummarySpec.h \
nsNewsSummarySpec.h \
nsMsgIdentity.h \
nsMsgIncomingServer.h \
nsMsgUtils.h \
nsMessage.h \
nsMsgProtocol.h \
nsMsgMailNewsUrl.h \
nsMsgTxn.h \
nsMsgI18N.h \
LOCAL_INCLUDES = \
-I$(DEPTH)/netwerk/cache/memcache \
-I$(DEPTH)/netwerk/cache/filecache \
-I$(DEPTH)/netwerk/cache/mgr \
$(NULL)
EXTRA_DSO_LDOPTS = \
-L$(DIST)/bin \
-L$(DIST)/lib \
-lxpcom \
-lrdfutil_s \
$(NSPR_LIBS) \
$(NULL)
$(MKSHLIB_FORCE_ALL) \
$(SHARED_LIBRARY_LIBS) \
$(MKSHLIB_UNFORCE_ALL) \
$(NULL)
include $(topsrcdir)/config/rules.mk
$(LIBRARY) $(SHARED_LIBRARY): $(SHARED_LIBRARY_LIBS) Makefile

View File

@@ -0,0 +1,51 @@
#!gmake
#
# The contents of this file are subject to the Netscape Public
# License Version 1.1 (the "License"); you may not use this file
# except in compliance with the License. You may obtain a copy of
# the License at http://www.mozilla.org/NPL/
#
# Software distributed under the License is distributed on an "AS
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
# implied. See the License for the specific language governing
# rights and limitations under the License.
#
# The Original Code is mozilla.org code.
#
# The Initial Developer of the Original Code is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All
# Rights Reserved.
#
DEPTH=..\..\..
MODULE=nkcache
MAKE_OBJ_TYPE=DLL
DLLNAME=nkcache
DLL=.\$(OBJDIR)\$(DLLNAME).dll
CPP_OBJS= \
.\$(OBJDIR)\nsNetDataCacheModule.obj \
$(NULL)
LLIBS= \
$(DIST)\lib\nkcachemgr_s.lib \
$(DIST)\lib\nkfilecache_s.lib \
$(DIST)\lib\nkmemcache_s.lib \
$(DIST)\lib\dbm32.lib \
$(DIST)\lib\xpcom.lib \
$(LIBNSPR)
INCS = $(INCS) \
-I$(DEPTH)\netwerk\cache\memcache \
-I$(DEPTH)\netwerk\cache\filecache \
-I$(DEPTH)\netwerk\cache\mgr \
$(NULL)
include <$(DEPTH)\config\rules.mak>
install:: $(DLL)
$(MAKE_INSTALL) .\$(OBJDIR)\$(DLLNAME).dll $(DIST)\bin\components
$(MAKE_INSTALL) .\$(OBJDIR)\$(DLLNAME).lib $(DIST)\lib

View File

@@ -0,0 +1,49 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator client code, released
* March 31, 1998.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
*/
#include "nsCOMPtr.h"
#include "nsIModule.h"
#include "nscore.h"
#include "nsIComponentManager.h"
#include "nsIServiceManager.h"
#include "nsIGenericFactory.h"
#include "nsINetDataCache.h"
#include "nsINetDataCacheManager.h"
#include "nsMemCacheCID.h"
#include "nsMemCache.h"
#include "nsNetDiskCache.h"
#include "nsNetDiskCacheCID.h"
#include "nsCacheManager.h"
// Factory method to create a new nsMemCache instance. Used
// by nsNetDataCacheModule
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsMemCache, Init)
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsNetDiskCache, Init)
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsCacheManager, Init)
static nsModuleComponentInfo components[] = {
{ "Memory Cache", NS_MEM_CACHE_FACTORY_CID, NS_NETWORK_MEMORY_CACHE_PROGID, nsMemCacheConstructor },
{ "File Cache", NS_NETDISKCACHE_CID, NS_NETWORK_FILE_CACHE_PROGID, nsNetDiskCacheConstructor },
{ "Cache Manager",NS_CACHE_MANAGER_CID, NS_NETWORK_CACHE_MANAGER_PROGID,nsCacheManagerConstructor }
};
NS_IMPL_NSGETMODULE("Network Data Cache", components)

View File

@@ -0,0 +1,60 @@
#
# The contents of this file are subject to the Mozilla Public
# License Version 1.1 (the "License"); you may not use this file
# except in compliance with the License. You may obtain a copy of
# the License at http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
# implied. See the License for the specific language governing
# rights and limitations under the License.
#
# The Original Code is Mozilla Communicator.
#
# The Initial Developer of the Original Code is Intel Corp.
# Portions created by Intel Corp. are
# Copyright (C) 1999, 1999 Intel Corp. All
# Rights Reserved.
#
# Contributor(s): Yixiong Zou <yixiong.zou@intel.com>
# Carl Wong <carl.wong@intel.com>
#
DEPTH = ../../..
topsrcdir = @top_srcdir@
VPATH = @srcdir@
srcdir = @srcdir@
include $(DEPTH)/config/autoconf.mk
MODULE = nkcache
LIBRARY_NAME = nkfilecache_s
REQUIRES = nspr dbm
EXTRA_DSO_LDOPTS += -L$(DIST)/lib -lmozdbm_s
EXPORTS=nsNetDiskCacheCID.h \
nsNetDiskCache.h \
nsIDBAccessor.h \
nsDBAccessor.h \
$(NULL)
CPPSRCS = \
nsDBAccessor.cpp\
nsDBEnumerator.cpp \
nsNetDiskCache.cpp \
nsDiskCacheRecord.cpp \
nsDiskCacheRecordChannel.cpp \
$(NULL)
EXTRA_LIBS = $(NSPR_LIBS)
# we don't want the shared lib, but we want to force the creation of a
# static lib.
override NO_SHARED_LIB=1
override NO_STATIC_LIB=
include $(topsrcdir)/config/rules.mk

View File

@@ -0,0 +1,44 @@
#!gmake
#
# The contents of this file are subject to the Netscape Public License
# Version 1.0 (the "NPL"); you may not use this file except in
# compliance with the NPL. You may obtain a copy of the NPL at
# http://www.mozilla.org/NPL/
#
# Software distributed under the NPL is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
# for the specific language governing rights and limitations under the
# NPL.
#
# The Initial Developer of this code under the NPL is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All Rights
# Reserved.
DEPTH=..\..\..
include <$(DEPTH)/config/config.mak>
MODULE = nkcache
LIBRARY_NAME = nkfilecache_s
CPP_OBJS= \
.\$(OBJDIR)\nsDBAccessor.obj \
.\$(OBJDIR)\nsDBEnumerator.obj \
.\$(OBJDIR)\nsNetDiskCache.obj \
.\$(OBJDIR)\nsDiskCacheRecord.obj \
.\$(OBJDIR)\nsDiskCacheRecordChannel.obj \
$(NULL)
EXPORTS=nsNetDiskCacheCID.h
include <$(DEPTH)\config\rules.mak>
install:: $(LIBRARY)
$(MAKE_INSTALL) $(LIBRARY) $(DIST)\lib
clobber::
rm -rf $(OBJDIR)
rm -f $(DIST)\lib\$(LIBRARY_NAME).lib

View File

@@ -0,0 +1,416 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator.
*
* The Initial Developer of the Original Code is Intel Corp.
* Portions created by Intel Corp. are
* Copyright (C) 1999, 1999 Intel Corp. All
* Rights Reserved.
*
* Contributor(s): Yixiong Zou <yixiong.zou@intel.com>
* Carl Wong <carl.wong@intel.com>
*/
/*
* This file is part of filecache implementation.
*
* nsIDBAccessor is a interface that shields all the direct database access
* method from nsNetDiskCache.
*
* nsDBAccessor is a implementation of the nsIDBAccessor interface. It
* uses dbm(Berkely) as the database.
*
* a nsDiskCacheRecord is mapped into two entries in the database,
* key->recordID
* recordID->metadata
*/
#include "nsDBAccessor.h"
#include "nscore.h"
#include "prtypes.h"
#include "plhash.h"
#include "nsCRT.h"
nsDBAccessor::nsDBAccessor() :
mDB(0) ,
mDBFile(0) ,
mSessionID(0) ,
mSessionCntr(0) ,
mDBFilesize(0)
{
mLastSyncTime = PR_IntervalNow() ;
NS_INIT_REFCNT();
}
nsDBAccessor::~nsDBAccessor()
{
Shutdown() ;
}
//
// Implement nsISupports methods
//
NS_IMPL_ISUPPORTS(nsDBAccessor, NS_GET_IID(nsIDBAccessor))
///////////////////////////////////////////////////////////
// nsIDBAccessor methods
NS_IMETHODIMP
nsDBAccessor::Init(nsIFileSpec* dbfile)
{
char* dbname ;
// this should cover all platforms.
dbfile->GetNativePath(&dbname) ;
mDBFile = dbfile ;
// FUR - how is page size chosen ? It's worth putting a comment
// in here about the possible usefulness of tuning these parameters
HASHINFO hash_info = {
16*1024 , /* bucket size */
0 , /* fill factor */
0 , /* number of elements */
0 , /* bytes to cache */
0 , /* hash function */
0} ; /* byte order */
mDB = dbopen(dbname,
O_RDWR | O_CREAT ,
0600 ,
DB_HASH ,
& hash_info) ;
nsCRT::free(dbname) ;
if(!mDB)
return NS_ERROR_FAILURE ;
// set mSessionID
DBT db_key, db_data ;
db_key.data = NS_CONST_CAST(char*, SessionKey) ;
db_key.size = PL_strlen(SessionKey) ;
int status = (*mDB->get)(mDB, &db_key, &db_data, 0) ;
if(status == -1) {
NS_ERROR("ERROR: failed get session id in database.") ;
return NS_ERROR_FAILURE ;
}
if(status == 0) {
// get the last session id
PRInt16 *old_ID = NS_STATIC_CAST(PRInt16*, db_data.data) ;
if(*old_ID < ini_sessionID) {
NS_ERROR("ERROR: Bad Session ID in database, corrupted db.") ;
return NS_ERROR_FAILURE ;
}
mSessionID = *old_ID + 1 ;
}
else if(status == 1) {
// must be a new db
mSessionID = ini_sessionID ;
}
db_data.data = NS_REINTERPRET_CAST(void*, &mSessionID) ;
db_data.size = sizeof(PRInt16) ;
// store the new session id
status = (*mDB->put)(mDB, &db_key, &db_data, 0) ;
if(status == 0) {
(*mDB->sync)(mDB, 0) ;
// initialize database filesize
return mDBFile->GetFileSize(&mDBFilesize) ;
}
else {
NS_ERROR("reset session ID failure.") ;
return NS_ERROR_FAILURE ;
}
}
NS_IMETHODIMP
nsDBAccessor::Shutdown(void)
{
if(mDB) {
(*mDB->sync)(mDB, 0) ;
(*mDB->close)(mDB) ;
mDB = nsnull ;
}
return NS_OK ;
}
NS_IMETHODIMP
nsDBAccessor::Get(PRInt32 aID, void** anEntry, PRUint32 *aLength)
{
if(!anEntry)
return NS_ERROR_NULL_POINTER ;
*anEntry = nsnull ;
*aLength = 0 ;
NS_ASSERTION(mDB, "no database") ;
DBT db_key, db_data ;
db_key.data = NS_REINTERPRET_CAST(void*, &aID) ;
db_key.size = sizeof(PRInt32) ;
int status = 0 ;
status = (*mDB->get)(mDB, &db_key, &db_data, 0) ;
if(status == 0) {
*anEntry = db_data.data ;
*aLength = db_data.size ;
return NS_OK ;
}
else if(status == 1)
return NS_OK ;
else
return NS_ERROR_FAILURE ;
}
NS_IMETHODIMP
nsDBAccessor::Put(PRInt32 aID, void* anEntry, PRUint32 aLength)
{
NS_ASSERTION(mDB, "no database") ;
DBT db_key, db_data ;
db_key.data = NS_REINTERPRET_CAST(void*, &aID) ;
db_key.size = sizeof(PRInt32) ;
db_data.data = anEntry ;
db_data.size = aLength ;
if(0 == (*mDB->put)(mDB, &db_key, &db_data, 0)) {
return Sync() ;
}
else {
return NS_ERROR_FAILURE ;
}
}
/*
* It's more important to remove the id->metadata entry first since
* key->id mapping is just a reference
*/
NS_IMETHODIMP
nsDBAccessor::Del(PRInt32 aID, void* anEntry, PRUint32 aLength)
{
NS_ASSERTION(mDB, "no database") ;
DBT db_key ;
// delete recordID->metadata
db_key.data = NS_REINTERPRET_CAST(void*, &aID) ;
db_key.size = sizeof(PRInt32) ;
PRInt32 status = -1 ;
status = (*mDB->del)(mDB, &db_key, 0) ;
if(-1 == status) {
return NS_ERROR_FAILURE ;
}
// delete key->recordID
db_key.data = anEntry ;
db_key.size = aLength ;
status = (*mDB->del)(mDB, &db_key, 0) ;
if(-1 == status) {
return NS_ERROR_FAILURE ;
}
return Sync() ;
}
NS_IMETHODIMP
nsDBAccessor::GetID(const char* key, PRUint32 length, PRInt32* aID)
{
NS_ASSERTION(mDB, "no database") ;
DBT db_key, db_data ;
db_key.data = NS_CONST_CAST(char*, key) ;
db_key.size = length ;
int status = (*mDB->get)(mDB, &db_key, &db_data, 0) ;
if(status == 0) {
// found recordID
*aID = *(NS_REINTERPRET_CAST(PRInt32*, db_data.data)) ;
return NS_OK ;
}
else if(status == 1) {
// create a new one
PRInt32 id = 0 ;
id = mSessionID << 16 | mSessionCntr++ ;
// add new id into mDB
db_data.data = NS_REINTERPRET_CAST(void*, &id) ;
db_data.size = sizeof(PRInt32) ;
status = (*mDB->put)(mDB, &db_key, &db_data, 0) ;
if(status != 0) {
NS_ERROR("updating db failure.") ;
return NS_ERROR_FAILURE ;
}
*aID = id ;
return Sync() ;
}
else {
NS_ERROR("ERROR: keydb failure.") ;
return NS_ERROR_FAILURE ;
}
}
NS_IMETHODIMP
nsDBAccessor::EnumEntry(void** anEntry, PRUint32* aLength, PRBool bReset)
{
if(!anEntry)
return NS_ERROR_NULL_POINTER ;
*anEntry = nsnull ;
*aLength = 0 ;
NS_ASSERTION(mDB, "no database") ;
PRUint32 flag ;
if(bReset)
flag = R_FIRST ;
else
flag = R_NEXT ;
DBT db_key, db_data ;
PRUint32 len = PL_strlen(SessionKey) ;
int status ;
do {
status = (*mDB->seq)(mDB, &db_key, &db_data, flag) ;
flag = R_NEXT ;
if(status == -1)
return NS_ERROR_FAILURE ;
// get next if it's a key->recordID
if(db_key.size > sizeof(PRInt32) && db_data.size == sizeof(PRInt32))
continue ;
// get next if it's a sessionID entry
if(db_key.size == len && db_data.size == sizeof(PRInt16))
continue ;
// recordID is always 32 bits long
if(db_key.size == sizeof(PRInt32))
break ;
} while(!status) ;
if (0 == status) {
*anEntry = db_data.data ;
*aLength = db_data.size ;
}
return NS_OK ;
}
/*
* returns the cached database file size.
* mDBFilesize will be updated during Sync().
*/
NS_IMETHODIMP
nsDBAccessor::GetDBFilesize(PRUint32* aSize)
{
*aSize = mDBFilesize ;
return NS_OK ;
}
NS_IMETHODIMP
nsDBAccessor::GetSpecialEntry(void** anEntry, PRUint32* aLength)
{
if(!anEntry)
return NS_ERROR_NULL_POINTER ;
*anEntry = nsnull ;
*aLength = 0 ;
DBT db_key, db_data ;
db_key.data = NS_CONST_CAST(char*, SpecialEntry) ;
db_key.size = PL_strlen(SpecialEntry) ;
int status = (*mDB->get)(mDB, &db_key, &db_data, 0) ;
if(status == -1) {
NS_ERROR("ERROR: failed get special entry in database.") ;
return NS_ERROR_FAILURE ;
}
if(status == 0) {
*anEntry = db_data.data ;
*aLength = db_data.size ;
}
return NS_OK ;
}
NS_IMETHODIMP
nsDBAccessor::SetSpecialEntry(void* anEntry, PRUint32 aLength)
{
DBT db_key, db_data ;
db_key.data = NS_CONST_CAST(char*, SpecialEntry) ;
db_key.size = PL_strlen(SpecialEntry) ;
db_data.data = anEntry ;
db_data.size = aLength ;
if(0 == (*mDB->put)(mDB, &db_key, &db_data, 0)) {
(*mDB->sync)(mDB, 0) ;
return NS_OK ;
}
else {
return NS_ERROR_FAILURE ;
}
}
/*
* sync routine is only called when the SyncInterval is reached. Otherwise
* it just returns. If db synced, the filesize will be updated at the
* same time.
*/
nsresult
nsDBAccessor::Sync(void)
{
PRIntervalTime time = PR_IntervalNow() ;
PRIntervalTime duration = time - mLastSyncTime ;
if (PR_IntervalToMilliseconds(duration) > SyncInterval) {
int status = (*mDB->sync)(mDB, 0) ;
if(status == 0) {
// printf("\tsynced\n") ;
mLastSyncTime = time ;
// update db filesize here
return mDBFile->GetFileSize(&mDBFilesize) ;
} else
return NS_ERROR_FAILURE ;
} else {
// printf("\tnot synced\n") ;
return NS_OK ;
}
}

View File

@@ -0,0 +1,93 @@
/*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator.
*
* The Initial Developer of the Original Code is Intel Corp.
* Portions created by Intel Corp. are
* Copyright (C) 1999, 1999 Intel Corp. All
* Rights Reserved.
*
* Contributor(s): Yixiong Zou <yixiong.zou@intel.com>
* Carl Wong <carl.wong@intel.com>
*/
/*
* This file is part of filecache implementation.
*
* nsIDBAccessor is a interface that shields all the direct database access
* method from nsNetDiskCache.
*
* nsDBAccessor is a implementation of the nsIDBAccessor interface. It
* uses dbm(Berkely) as the database.
*
*/
#ifndef _NSIDBACCESSOR_H_
#define _NSIDBACCESSOR_H_
#include "nsIDBAccessor.h"
#include "mcom_db.h"
#include "prinrval.h"
#include "nsCOMPtr.h"
// bogus string for the key of session id
static const char * const SessionKey = "SK" ;
// bogus string for the size
static const char * const SpecialEntry = "SE" ;
// initial session id number
static const PRInt16 ini_sessionID = 0xff ;
static const PRUint16 SyncInterval = 1000 ;
class nsDBAccessor : public nsIDBAccessor
{
public:
NS_DECL_ISUPPORTS
nsDBAccessor() ;
virtual ~nsDBAccessor() ;
NS_IMETHOD Init(nsIFileSpec* dbfile) ;
NS_IMETHOD Shutdown(void) ;
NS_IMETHOD Put(PRInt32 aID, void* anEntry, PRUint32 aLength) ;
NS_IMETHOD Get(PRInt32 aID, void** anEntry, PRUint32 *aLength) ;
NS_IMETHOD Del(PRInt32 aID, void* anEntry, PRUint32 aLength) ;
NS_IMETHOD GetID(const char* key, PRUint32 length, PRInt32* aID) ;
NS_IMETHOD EnumEntry(void* *anEntry, PRUint32* aLength, PRBool bReset) ;
NS_IMETHOD GetDBFilesize(PRUint32* aSize) ;
NS_IMETHOD GetSpecialEntry(void** anEntry, PRUint32 *aLength) ;
NS_IMETHOD SetSpecialEntry(void* anEntry, PRUint32 aLength) ;
protected:
nsresult Sync(void) ;
private:
DB * mDB ;
nsCOMPtr<nsIFileSpec> mDBFile ;
PRInt16 mSessionID ;
PRInt16 mSessionCntr ;
PRIntervalTime mLastSyncTime ;
PRUint32 mDBFilesize ; // cached DB filesize,
// updated on every sync for now
} ;
#endif // _NSIDBACCESSOR_H_

View File

@@ -0,0 +1,108 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator.
*
* The Initial Developer of the Original Code is Intel Corp.
* Portions created by Intel Corp. are
* Copyright (C) 1999, 1999 Intel Corp. All
* Rights Reserved.
*
* Contributor(s): Yixiong Zou <yixiong.zou@intel.com>
* Carl Wong <carl.wong@intel.com>
*/
/*
* This file is part of filecache implementation.
*
* It implements a simple iterator for the database, see nsDBAccessor.
*/
#include "nsDBEnumerator.h"
#include "nsDiskCacheRecord.h"
nsDBEnumerator::nsDBEnumerator(nsIDBAccessor* aDB, nsNetDiskCache* aCache) :
m_DB(aDB) ,
m_DiskCache(aCache) ,
m_tempEntry(0) ,
m_tempEntry_length(0) ,
m_CacheEntry(0) ,
m_bReset(PR_TRUE)
{
NS_INIT_REFCNT();
}
nsDBEnumerator::~nsDBEnumerator()
{
NS_IF_RELEASE(m_CacheEntry) ;
}
//
// Implement nsISupports methods
//
NS_IMPL_ISUPPORTS(nsDBEnumerator, NS_GET_IID(nsIEnumerator))
/////////////////////////////////////////////////////////////////
// nsISimpleEnumerator methods
NS_IMETHODIMP
nsDBEnumerator::HasMoreElements(PRBool *_retval)
{
*_retval = PR_FALSE ;
nsresult rv = m_DB->EnumEntry(&m_tempEntry, &m_tempEntry_length, m_bReset) ;
if(NS_FAILED(rv)) {
// do some error recovery
m_DiskCache->DBRecovery() ;
return rv ;
}
m_bReset = PR_FALSE ;
if(m_tempEntry && m_tempEntry_length != 0)
*_retval = PR_TRUE ;
return NS_OK ;
}
// this routine does not create a new item by itself
// Rather it reuses the item inside the object. So if you need to use the
// item later, you have to
// create a new item specifically, using copy constructor or some other dup
// function. And don't forget to release it after you're done
//
NS_IMETHODIMP
nsDBEnumerator::GetNext(nsISupports **_retval)
{
if(!m_CacheEntry) {
m_CacheEntry = new nsDiskCacheRecord(m_DB, m_DiskCache) ;
if(m_CacheEntry)
NS_ADDREF(m_CacheEntry) ;
else
return NS_ERROR_OUT_OF_MEMORY ;
}
if(!_retval)
return NS_ERROR_NULL_POINTER ;
*_retval = nsnull ;
nsresult rv = m_CacheEntry->RetrieveInfo(m_tempEntry, m_tempEntry_length) ;
if(NS_FAILED(rv))
return rv ;
*_retval = NS_STATIC_CAST(nsISupports*, m_CacheEntry) ;
NS_ADDREF(*_retval) ; // all good getter addref
return NS_OK ;
}

View File

@@ -0,0 +1,60 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator.
*
* The Initial Developer of the Original Code is Intel Corp.
* Portions created by Intel Corp. are
* Copyright (C) 1999, 1999 Intel Corp. All
* Rights Reserved.
*
* Contributor(s): Yixiong Zou <yixiong.zou@intel.com>
* Carl Wong <carl.wong@intel.com>
*/
/*
* This file is part of filecache implementation.
*
* It implements a simple iterator for the database, see nsDBAccessor.
*/
#ifndef _NS_DBENUMERATOR_H_
#define _NS_DBENUMERATOR_H_
#include "nsISimpleEnumerator.h"
#include "nsINetDataCacheRecord.h"
#include "nsIDBAccessor.h"
#include "nsCOMPtr.h"
#include "nsNetDiskCache.h"
#include "nsDiskCacheRecord.h"
class nsCachedDiskData ; /* forward decl */
class nsDBEnumerator : public nsISimpleEnumerator {
public:
NS_DECL_ISUPPORTS
NS_DECL_NSISIMPLEENUMERATOR
nsDBEnumerator(nsIDBAccessor* aDB, nsNetDiskCache* aCache) ;
virtual ~nsDBEnumerator() ;
private:
nsCOMPtr<nsIDBAccessor> m_DB ;
nsCOMPtr<nsNetDiskCache> m_DiskCache ;
void * m_tempEntry ;
PRUint32 m_tempEntry_length ;
nsDiskCacheRecord* m_CacheEntry ;
PRBool m_bReset ;
};
#endif // _NS_DBENUMERATOR_H_

View File

@@ -0,0 +1,456 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator.
*
* The Initial Developer of the Original Code is Intel Corp.
* Portions created by Intel Corp. are
* Copyright (C) 1999, 1999 Intel Corp. All
* Rights Reserved.
*
* Contributor(s): Yixiong Zou <yixiong.zou@intel.com>
* Carl Wong <carl.wong@intel.com>
*/
#include "nsDiskCacheRecord.h"
#include "nsINetDataDiskCache.h"
#include "nsNetDiskCacheCID.h"
#include "nsDiskCacheRecordChannel.h"
#include "nsFileStream.h"
#include "nsIComponentManager.h"
#include "nsIServiceManager.h"
#include "nsIProtocolHandler.h"
#include "nsIIOService.h"
#include "nsIAllocator.h"
#include "plstr.h"
#include "prprf.h"
#include "prmem.h"
#include "prlog.h"
#include "prtypes.h"
#include "netCore.h"
#include "nsDBAccessor.h"
#if !defined(IS_LITTLE_ENDIAN) && !defined(IS_BIG_ENDIAN)
ERROR! Must have a byte order
#endif
#ifdef IS_LITTLE_ENDIAN
#define COPY_INT32(_a,_b) memcpy(_a, _b, sizeof(int32))
#else
#define COPY_INT32(_a,_b) /* swap */ \
do { \
((char *)(_a))[0] = ((char *)(_b))[3]; \
((char *)(_a))[1] = ((char *)(_b))[2]; \
((char *)(_a))[2] = ((char *)(_b))[1]; \
((char *)(_a))[3] = ((char *)(_b))[0]; \
} while(0)
#endif
nsDiskCacheRecord::nsDiskCacheRecord(nsIDBAccessor* db, nsNetDiskCache* aCache) :
mKey(0) ,
mKeyLength(0) ,
mRecordID(0) ,
mMetaData(0) ,
mMetaDataLength(0) ,
mDB(db) ,
mInfo(0) ,
mInfoSize(0) ,
mNumChannels(0) ,
mDiskCache(aCache)
{
NS_INIT_REFCNT();
NS_ASSERTION(mDiskCache, "Must have an nsNetDiskCache");
NS_ADDREF(mDiskCache);
}
// mem alloced. so caller should do free() on key.
NS_IMETHODIMP
nsDiskCacheRecord::Init(const char* key, PRUint32 length, PRInt32 ID)
{
NS_NewFileSpec(getter_AddRefs(mFile));
if(!mFile)
return NS_ERROR_OUT_OF_MEMORY ;
// copy key
mKeyLength = length ;
mKey = NS_STATIC_CAST(char*, nsAllocator::Alloc(mKeyLength*sizeof(char))) ;
if(!mKey)
return NS_ERROR_OUT_OF_MEMORY ;
memcpy(mKey, key, length) ;
// get RecordID
mRecordID = ID ;
// setup the file name
nsCOMPtr<nsIFileSpec> dbFolder ;
mDiskCache->GetDiskCacheFolder(getter_AddRefs(dbFolder)) ;
nsresult rv = mFile->FromFileSpec(dbFolder) ;
if(NS_FAILED(rv))
return NS_ERROR_FAILURE ;
// dir is a hash result of mRecordID%32, hope it's enough
char filename[9], dirName[3] ;
PR_snprintf(dirName, 3, "%02x", (((PRUint32)mRecordID) % 32)) ;
mFile->AppendRelativeUnixPath(dirName) ;
PR_snprintf(filename, 9, "%08x", mRecordID) ;
mFile->AppendRelativeUnixPath(filename) ;
return NS_OK ;
}
nsDiskCacheRecord::~nsDiskCacheRecord()
{
if(mKey)
nsAllocator::Free(mKey) ;
if(mMetaData)
nsAllocator::Free(mMetaData) ;
if(mInfo)
nsAllocator::Free(mInfo) ;
NS_IF_RELEASE(mDiskCache);
}
//
// Implement nsISupports methods
//
NS_IMPL_ISUPPORTS(nsDiskCacheRecord, NS_GET_IID(nsINetDataCacheRecord))
///////////////////////////////////////////////////////////////////////
// nsINetDataCacheRecord methods
// yes, mem alloced on *_retval.
NS_IMETHODIMP
nsDiskCacheRecord::GetKey(PRUint32 *length, char** _retval)
{
if(!_retval)
return NS_ERROR_NULL_POINTER ;
*length = mKeyLength ;
*_retval = NS_STATIC_CAST(char*, nsAllocator::Alloc(mKeyLength*sizeof(char))) ;
if(!*_retval)
return NS_ERROR_OUT_OF_MEMORY ;
memcpy(*_retval, mKey, mKeyLength) ;
return NS_OK ;
}
NS_IMETHODIMP
nsDiskCacheRecord::GetRecordID(PRInt32* aRecordID)
{
*aRecordID = mRecordID ;
return NS_OK ;
}
// yes, mem alloced on *_retval.
NS_IMETHODIMP
nsDiskCacheRecord::GetMetaData(PRUint32 *length, char **_retval)
{
if(!_retval)
return NS_ERROR_NULL_POINTER ;
// always null the return value first.
*_retval = nsnull ;
*length = mMetaDataLength ;
if(mMetaDataLength) {
*_retval = NS_STATIC_CAST(char*, nsAllocator::Alloc(mMetaDataLength*sizeof(char))) ;
if(!*_retval)
return NS_ERROR_OUT_OF_MEMORY ;
memcpy(*_retval, mMetaData, mMetaDataLength) ;
}
return NS_OK ;
}
NS_IMETHODIMP
nsDiskCacheRecord::SetMetaData(PRUint32 length, const char* data)
{
// set the mMetaData
mMetaDataLength = length ;
if(mMetaData)
nsAllocator::Free(mMetaData) ;
mMetaData = NS_STATIC_CAST(char*, nsAllocator::Alloc(mMetaDataLength*sizeof(char))) ;
if(!mMetaData) {
return NS_ERROR_OUT_OF_MEMORY ;
}
memcpy(mMetaData, data, length) ;
// Generate mInfo
nsresult rv = GenInfo() ;
if(NS_FAILED(rv))
return rv ;
// write through into mDB
rv = mDB->Put(mRecordID, mInfo, mInfoSize) ;
return rv ;
}
NS_IMETHODIMP
nsDiskCacheRecord::GetStoredContentLength(PRUint32 *aStoredContentLength)
{
return mFile->GetFileSize(aStoredContentLength) ;
}
// untill nsIFileSpec::Truncate() is in, we have to do all this ugly stuff
NS_IMETHODIMP
nsDiskCacheRecord::SetStoredContentLength(PRUint32 aStoredContentLength)
{
PRUint32 len = 0 ;
nsresult rv = mFile->GetFileSize(&len) ;
if(NS_FAILED(rv))
return rv ;
if(len < aStoredContentLength)
{
NS_ERROR("Error: can not set filesize to something bigger than itself.\n") ;
return NS_ERROR_FAILURE ;
}
else {
rv = mFile->Truncate(aStoredContentLength) ;
if(NS_FAILED(rv))
return rv ;
mDiskCache->m_StorageInUse -= (len - aStoredContentLength) ;
return NS_OK ;
}
}
NS_IMETHODIMP
nsDiskCacheRecord::Delete(void)
{
if(mNumChannels)
return NS_ERROR_NOT_AVAILABLE ;
PRUint32 len ;
mFile->GetFileSize(&len) ;
nsFileSpec cache_file ;
nsresult rv = mFile->GetFileSpec(&cache_file) ;
if(NS_FAILED(rv))
return NS_ERROR_FAILURE ;
cache_file.Delete(PR_TRUE) ;
// updata the storage size
mDiskCache->m_StorageInUse -= len ;
rv = mDB->Del(mRecordID, mKey, mKeyLength) ;
if(NS_FAILED(rv))
return NS_ERROR_FAILURE ;
else
return NS_OK ;
}
NS_IMETHODIMP
nsDiskCacheRecord::GetFilename(nsIFileSpec * *aFilename)
{
if(!aFilename)
return NS_ERROR_NULL_POINTER ;
*aFilename = mFile ;
NS_ADDREF(*aFilename) ;
return NS_OK ;
}
NS_IMETHODIMP
nsDiskCacheRecord::NewChannel(nsILoadGroup *loadGroup, nsIChannel **_retval)
{
nsDiskCacheRecordChannel* channel = new nsDiskCacheRecordChannel(this, loadGroup) ;
if(!channel)
return NS_ERROR_OUT_OF_MEMORY ;
nsresult rv = channel->Init() ;
if(NS_FAILED(rv))
return rv ;
NS_ADDREF(channel) ;
*_retval = NS_STATIC_CAST(nsIChannel*, channel) ;
return NS_OK ;
}
//////////////////////////////////////////////////////////////////////////
// nsDiskCacheRecord methods
// file name is represented by a url string. I hope this would be more
// generic
nsresult
nsDiskCacheRecord::GenInfo()
{
if(mInfo)
nsAllocator::Free(mInfo) ;
char* file_url=nsnull ;
PRUint32 name_len ;
mFile->GetURLString(&file_url) ;
name_len = PL_strlen(file_url)+1 ;
mInfoSize = sizeof(PRUint32) ; // checksum for mInfoSize
mInfoSize += sizeof(PRInt32) ; // RecordID
mInfoSize += sizeof(PRUint32) ; // key length
mInfoSize += mKeyLength ; // key
mInfoSize += sizeof(PRUint32) ; // metadata length
mInfoSize += mMetaDataLength ; // metadata
mInfoSize += sizeof(PRUint32) ; // filename length
mInfoSize += name_len ; // filename
void* newInfo = nsAllocator::Alloc(mInfoSize*sizeof(char)) ;
if(!newInfo) {
return NS_ERROR_OUT_OF_MEMORY ;
}
// copy the checksum mInfoSize
char* cur_ptr = NS_STATIC_CAST(char*, newInfo) ;
COPY_INT32(cur_ptr, &mInfoSize) ;
cur_ptr += sizeof(PRUint32) ;
// copy RecordID
COPY_INT32(cur_ptr, &mRecordID) ;
cur_ptr += sizeof(PRInt32) ;
// copy key length
COPY_INT32(cur_ptr, &mKeyLength) ;
cur_ptr += sizeof(PRUint32) ;
// copy key
memcpy(cur_ptr, mKey, mKeyLength) ;
cur_ptr += mKeyLength ;
// copy metadata length
COPY_INT32(cur_ptr, &mMetaDataLength) ;
cur_ptr += sizeof(PRUint32) ;
// copy metadata
memcpy(cur_ptr, mMetaData, mMetaDataLength) ;
cur_ptr += mMetaDataLength ;
// copy file name length
COPY_INT32(cur_ptr, &name_len) ;
cur_ptr += sizeof(PRUint32) ;
// copy file name
memcpy(cur_ptr, file_url, name_len) ;
cur_ptr += name_len ;
PR_ASSERT(cur_ptr == NS_STATIC_CAST(char*, newInfo) + mInfoSize);
mInfo = newInfo ;
return NS_OK ;
}
/*
* This Method suppose to get all the info from the db record
* and set them to accroding members. the original values
* will all be overwritten. only minimal error checking is performed.
*/
NS_IMETHODIMP
nsDiskCacheRecord::RetrieveInfo(void* aInfo, PRUint32 aInfoLength)
{
// reset everything
if(mInfo) {
nsAllocator::Free(mInfo) ;
mInfo = nsnull ;
}
if(mKey) {
nsAllocator::Free(mKey) ;
mKey = nsnull ;
}
if(mMetaData) {
nsAllocator::Free(mMetaData) ;
mMetaData = nsnull ;
}
char * cur_ptr = NS_STATIC_CAST(char*, aInfo) ;
char* file_url ;
PRUint32 name_len ;
// set mInfoSize
COPY_INT32(&mInfoSize, cur_ptr) ;
cur_ptr += sizeof(PRUint32) ;
// check this at least
if(mInfoSize != aInfoLength)
return NS_ERROR_FAILURE ;
// set mRecordID
COPY_INT32(&mRecordID, cur_ptr) ;
cur_ptr += sizeof(PRInt32) ;
// set mKeyLength
COPY_INT32(&mKeyLength, cur_ptr) ;
cur_ptr += sizeof(PRUint32) ;
// set mKey
mKey = NS_STATIC_CAST(char*, nsAllocator::Alloc(mKeyLength*sizeof(char))) ;
if(!mKey)
return NS_ERROR_OUT_OF_MEMORY ;
memcpy(mKey, cur_ptr, mKeyLength) ;
cur_ptr += mKeyLength ;
PRInt32 id ;
mDB->GetID(mKey, mKeyLength, &id) ;
NS_ASSERTION(id==mRecordID, "\t ++++++ bad record, somethings wrong\n") ;
// set mMetaDataLength
COPY_INT32(&mMetaDataLength, cur_ptr) ;
cur_ptr += sizeof(PRUint32) ;
// set mMetaData
mMetaData = NS_STATIC_CAST(char*, nsAllocator::Alloc(mMetaDataLength*sizeof(char))) ;
if(!mMetaData)
return NS_ERROR_OUT_OF_MEMORY ;
memcpy(mMetaData, cur_ptr, mMetaDataLength) ;
cur_ptr += mMetaDataLength ;
// get mFile name length
COPY_INT32(&name_len, cur_ptr) ;
cur_ptr += sizeof(PRUint32) ;
// get mFile native name
file_url = NS_STATIC_CAST(char*, nsAllocator::Alloc(name_len*sizeof(char))) ;
if(!file_url)
return NS_ERROR_OUT_OF_MEMORY ;
memcpy(file_url, cur_ptr, name_len) ;
cur_ptr += name_len ;
PR_ASSERT(cur_ptr == NS_STATIC_CAST(char*, aInfo) + mInfoSize);
// create mFile if Init() isn't called
if(!mFile) {
NS_NewFileSpec(getter_AddRefs(mFile));
if(!mFile)
return NS_ERROR_OUT_OF_MEMORY ;
}
// setup mFile
mFile->SetURLString(file_url) ;
return NS_OK ;
}

View File

@@ -0,0 +1,71 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator.
*
* The Initial Developer of the Original Code is Intel Corp.
* Portions created by Intel Corp. are
* Copyright (C) 1999, 1999 Intel Corp. All
* Rights Reserved.
*
* Contributor(s): Yixiong Zou <yixiong.zou@intel.com>
* Carl Wong <carl.wong@intel.com>
*/
#ifndef _NET_CACHEDDISKDATA_H_
#define _NET_CACHEDDISKDATA_H_
#include "nsINetDataCacheRecord.h"
#include "nsCOMPtr.h"
#include "nsIDBAccessor.h"
#include "prtypes.h"
#include "nsILoadGroup.h"
#include "nsIFileChannel.h"
#include "nsNetDiskCache.h"
class nsDiskCacheRecord : public nsINetDataCacheRecord
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSINETDATACACHERECORD
protected:
nsDiskCacheRecord(nsIDBAccessor* db, nsNetDiskCache* aCache) ;
virtual ~nsDiskCacheRecord() ;
NS_IMETHOD RetrieveInfo(void* aInfo, PRUint32 aInfoLength) ;
NS_IMETHOD Init(const char* key, PRUint32 length, PRInt32 ID) ;
nsresult GenInfo(void) ;
private:
char* mKey ;
PRUint32 mKeyLength ;
PRInt32 mRecordID ;
char* mMetaData ;
PRUint32 mMetaDataLength ;
nsCOMPtr<nsIFileSpec> mFile ;
nsCOMPtr<nsIDBAccessor> mDB ;
void* mInfo ;
PRUint32 mInfoSize ;
PRUint32 mNumChannels ;
nsNetDiskCache* mDiskCache ;
friend class nsDiskCacheRecordChannel ;
friend class nsDBEnumerator ;
friend class nsNetDiskCache ;
} ;
#endif // _NET_CACHEDDISKDATA_H_

View File

@@ -0,0 +1,552 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator.
*
* The Initial Developer of the Original Code is Intel Corp.
* Portions created by Intel Corp. are
* Copyright (C) 1999, 1999 Intel Corp. All
* Rights Reserved.
*
* Contributor(s): Yixiong Zou <yixiong.zou@intel.com>
* Carl Wong <carl.wong@intel.com>
*/
/*
* Most of the code are taken from nsFileChannel.
*/
#include "nsDiskCacheRecordChannel.h"
#include "nsIFileTransportService.h"
//#include "nsIIOService.h"
#include "nsIServiceManager.h"
#include "nsIURL.h"
#include "nsIOutputStream.h"
#include "netCore.h"
#include "nsIMIMEService.h"
#include "nsISupportsUtils.h"
//static NS_DEFINE_CID(kIOServiceCID, NS_IOSERVICE_CID);
static NS_DEFINE_CID(kFileTransportServiceCID, NS_FILETRANSPORTSERVICE_CID);
static NS_DEFINE_CID(kStandardURLCID, NS_STANDARDURL_CID);
static NS_DEFINE_CID(kMIMEServiceCID, NS_MIMESERVICE_CID);
// This is copied from nsMemCacheChannel, We should consolidate these two.
class WriteStreamWrapper : public nsIOutputStream
{
public:
WriteStreamWrapper(nsDiskCacheRecordChannel* aChannel,
nsIOutputStream *aBaseStream) ;
virtual ~WriteStreamWrapper() ;
static nsresult
Create(nsDiskCacheRecordChannel* aChannel, nsIOutputStream *aBaseStream, nsIOutputStream* *aWrapper) ;
NS_DECL_ISUPPORTS
NS_DECL_NSIBASESTREAM
NS_DECL_NSIOUTPUTSTREAM
private:
nsDiskCacheRecordChannel* mChannel;
nsCOMPtr<nsIOutputStream> mBaseStream;
} ;
// implement nsISupports
NS_IMPL_ISUPPORTS(WriteStreamWrapper, NS_GET_IID(nsIOutputStream))
WriteStreamWrapper::WriteStreamWrapper(nsDiskCacheRecordChannel* aChannel,
nsIOutputStream *aBaseStream)
: mChannel(aChannel), mBaseStream(aBaseStream)
{
NS_INIT_REFCNT();
NS_ADDREF(mChannel);
}
WriteStreamWrapper::~WriteStreamWrapper()
{
NS_RELEASE(mChannel);
}
nsresult
WriteStreamWrapper::Create(nsDiskCacheRecordChannel*aChannel, nsIOutputStream *aBaseStream, nsIOutputStream* * aWrapper)
{
WriteStreamWrapper *wrapper = new WriteStreamWrapper(aChannel, aBaseStream);
if (!wrapper) return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(wrapper);
*aWrapper = wrapper;
return NS_OK;
}
NS_IMETHODIMP
WriteStreamWrapper::Write(const char *aBuffer, PRUint32 aCount, PRUint32 *aNumWritten)
{
*aNumWritten = 0;
nsresult rv = mBaseStream->Write(aBuffer, aCount, aNumWritten);
mChannel->NotifyStorageInUse(*aNumWritten);
return rv;
}
NS_IMETHODIMP
WriteStreamWrapper::Flush()
{
return mBaseStream->Flush();
}
NS_IMETHODIMP
WriteStreamWrapper::Close()
{
return mBaseStream->Close();
}
nsDiskCacheRecordChannel::nsDiskCacheRecordChannel(nsDiskCacheRecord *aRecord,
nsILoadGroup *aLoadGroup)
: mRecord(aRecord) ,
mLoadGroup(aLoadGroup)
{
NS_INIT_REFCNT() ;
NS_ADDREF(mRecord);
mRecord->mNumChannels++ ;
}
nsDiskCacheRecordChannel::~nsDiskCacheRecordChannel()
{
mRecord->mNumChannels-- ;
NS_RELEASE(mRecord);
}
// I know that I gave conflicting advice on the issue of file
// transport versus file protocol handler, but I thought that the
// last word was that we would use the raw transport, when I wrote:
//
// > I just thought of an argument for the other side of the coin, i.e. the
// > benefit of *not* reusing the file protocol handler: On the Mac, it's
// > expensive to convert from a string URL to an nsFileSpec, because the Mac
// > is brain-dead and scans every directory on the path to the file. It's
// > cheaper to create a nsFileSpec for a cache file by combining a single,
// > static nsFileSpec that corresponds to the cache directory with the
// > relative path to the cache file (using nsFileSpec's operator +). This
// > operation is optimized on the Mac to avoid the scanning operation.
//
// The Mac guys will eat us alive if we do path string to nsFileSpec
// conversions for every cache file we open.
nsresult
nsDiskCacheRecordChannel::Init(void)
{
nsresult rv = mRecord->mFile->GetFileSpec(&mSpec) ;
#ifdef XP_MAC
// Don't assume we actually created a good file spec
FSSpec theSpec = mSpec.GetFSSpec();
if (!theSpec.name[0]) {
NS_ERROR("failed to create a file spec");
// Since we didn't actually create the file spec
// we return an error
return NS_ERROR_MALFORMED_URI;
}
#endif
return rv ;
}
nsresult
nsDiskCacheRecordChannel::NotifyStorageInUse(PRInt32 aBytesUsed)
{
return mRecord->mDiskCache->m_StorageInUse += aBytesUsed ;
}
// implement nsISupports
NS_IMPL_ISUPPORTS4(nsDiskCacheRecordChannel,
nsIChannel,
nsIRequest,
nsIStreamListener,
nsIStreamObserver)
// implement nsIRequest
NS_IMETHODIMP
nsDiskCacheRecordChannel::IsPending(PRBool *aIsPending)
{
*aIsPending = PR_FALSE ;
if(!mFileTransport)
return NS_OK ;
return mFileTransport->IsPending(aIsPending) ;
}
NS_IMETHODIMP
nsDiskCacheRecordChannel::Cancel(void)
{
if(!mFileTransport)
return NS_ERROR_FAILURE ;
return mFileTransport->Cancel() ;
}
NS_IMETHODIMP
nsDiskCacheRecordChannel::Suspend(void)
{
if(!mFileTransport)
return NS_ERROR_FAILURE ;
return mFileTransport->Suspend() ;
}
NS_IMETHODIMP
nsDiskCacheRecordChannel::Resume(void)
{
if(!mFileTransport)
return NS_ERROR_FAILURE ;
return mFileTransport->Resume() ;
}
// implement nsIChannel
NS_IMETHODIMP
nsDiskCacheRecordChannel::GetOriginalURI(nsIURI* *aURI)
{
// FUR - might need to implement this - not sure
return NS_ERROR_NOT_IMPLEMENTED ;
}
NS_IMETHODIMP
nsDiskCacheRecordChannel::GetURI(nsIURI * *aURI)
{
if(!mFileTransport)
return NS_ERROR_FAILURE ;
return mFileTransport->GetURI(aURI) ;
}
NS_IMETHODIMP
nsDiskCacheRecordChannel::OpenInputStream(PRUint32 aStartPosition,
PRInt32 aReadCount,
nsIInputStream* *aResult)
{
nsresult rv ;
if(mFileTransport)
return NS_ERROR_IN_PROGRESS ;
NS_WITH_SERVICE(nsIFileTransportService, fts, kFileTransportServiceCID, &rv) ;
if(NS_FAILED(rv)) return rv ;
rv = fts->CreateTransport(mSpec, "load", 0, 0, getter_AddRefs(mFileTransport)) ;
if(NS_FAILED(rv))
return rv ;
// we don't need to worry about notification callbacks
rv = mFileTransport->OpenInputStream(aStartPosition, aReadCount, aResult) ;
if(NS_FAILED(rv))
mFileTransport = nsnull ;
return rv ;
}
NS_IMETHODIMP
nsDiskCacheRecordChannel::OpenOutputStream(PRUint32 startPosition,
nsIOutputStream* *aResult)
{
nsresult rv ;
NS_ENSURE_ARG(aResult) ;
if(mFileTransport)
return NS_ERROR_IN_PROGRESS ;
nsCOMPtr<nsIOutputStream> outputStream ;
NS_WITH_SERVICE(nsIFileTransportService, fts, kFileTransportServiceCID, &rv) ;
if(NS_FAILED(rv)) return rv ;
rv = fts->CreateTransport(mSpec, "load", 0, 0, getter_AddRefs(mFileTransport)) ;
if(NS_FAILED(rv))
return rv ;
// we don't need to worry about notification callbacks
rv = mFileTransport->OpenOutputStream(startPosition, getter_AddRefs(outputStream)) ;
if(NS_FAILED(rv)) {
mFileTransport = nsnull ;
return rv ;
}
return WriteStreamWrapper::Create(this, outputStream, aResult) ;
}
NS_IMETHODIMP
nsDiskCacheRecordChannel::AsyncOpen(nsIStreamObserver *observer,
nsISupports *ctxt)
{
return NS_ERROR_NOT_IMPLEMENTED ;
}
NS_IMETHODIMP
nsDiskCacheRecordChannel::AsyncRead(PRUint32 aStartPosition,
PRInt32 aReadCount,
nsISupports *aContext,
nsIStreamListener *aListener)
{
nsresult rv ;
if(mFileTransport)
return NS_ERROR_IN_PROGRESS ;
mRealListener = aListener;
nsCOMPtr<nsIStreamListener> tempListener = this;
if (mLoadGroup) {
nsCOMPtr<nsILoadGroupListenerFactory> factory;
//
// Create a load group "proxy" listener...
//
rv = mLoadGroup->GetGroupListenerFactory(getter_AddRefs(factory));
if (factory) {
nsIStreamListener *newListener;
rv = factory->CreateLoadGroupListener(mRealListener, &newListener);
if (NS_SUCCEEDED(rv)) {
mRealListener = newListener;
NS_RELEASE(newListener);
}
}
rv = mLoadGroup->AddChannel(this, nsnull);
if (NS_FAILED(rv)) return rv;
}
NS_WITH_SERVICE(nsIFileTransportService, fts, kFileTransportServiceCID, &rv);
if (NS_FAILED(rv)) return rv;
rv = fts->CreateTransport(mSpec, "load", 0, 0, getter_AddRefs(mFileTransport));
if (NS_FAILED(rv)) return rv;
// no callbacks
rv = mFileTransport->AsyncRead(aStartPosition,
aReadCount,
aContext,
tempListener);
if (NS_FAILED(rv)) {
// release the transport so that we don't think we're in progress
mFileTransport = nsnull;
}
return rv;
}
NS_IMETHODIMP
nsDiskCacheRecordChannel::AsyncWrite(nsIInputStream *fromStream,
PRUint32 startPosition,
PRInt32 writeCount,
nsISupports *ctxt,
nsIStreamObserver *observer)
{
/*
if(!mFileTransport)
return NS_ERROR_FAILURE ;
return mFileTransport->AsyncWrite(fromStream,
startPosition,
writeCount,
ctxt,
observer) ;
*/
// I can't do this since the write is not monitored, and I won't be
// able to updata the storage.
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsDiskCacheRecordChannel::GetLoadAttributes(nsLoadFlags *aLoadAttributes)
{
// Not required to be implemented, since it is implemented by cache manager
NS_ASSERTION(0, "nsDiskCacheRecordChannel method unexpectedly called");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsDiskCacheRecordChannel::SetLoadAttributes(nsLoadFlags aLoadAttributes)
{
// Not required to be implemented, since it is implemented by cache manager
NS_ASSERTION(0, "nsDiskCacheRecordChannel method unexpectedly called");
return NS_ERROR_NOT_IMPLEMENTED;
}
#define DUMMY_TYPE "text/html"
NS_IMETHODIMP
nsDiskCacheRecordChannel::GetContentType(char * *aContentType)
{
nsresult rv ;
if (mSpec.IsDirectory()) {
*aContentType = nsCRT::strdup("application/http-index-format");
return *aContentType ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
}
else {
// I wish I can make this simplier
char* urlStr ;
mRecord->mFile->GetURLString(&urlStr) ;
// file: URLs (currently) have no additional structure beyond that provided by standard
// URLs, so there is no "outer" given to CreateInstance
nsCOMPtr<nsIURI> url;
rv = nsComponentManager::CreateInstance(kStandardURLCID, nsnull,
NS_GET_IID(nsIURI),
//(void**)&url);
getter_AddRefs(url)) ;
if (NS_FAILED(rv)) return rv;
rv = url->SetSpec((char*)urlStr);
if (NS_FAILED(rv))
return rv;
NS_WITH_SERVICE(nsIMIMEService, MIMEService, kMIMEServiceCID, &rv);
if (NS_FAILED(rv)) return rv;
rv = MIMEService->GetTypeFromURI(url, aContentType);
if (NS_SUCCEEDED(rv)) return rv;
}
// if all else fails treat it as text/html?
*aContentType = nsCRT::strdup(DUMMY_TYPE);
if (!*aContentType) {
return NS_ERROR_OUT_OF_MEMORY;
} else {
return NS_OK;
}
}
NS_IMETHODIMP
nsDiskCacheRecordChannel::GetContentLength(PRInt32 *aContentLength)
{
nsresult rv;
PRUint32 length;
rv = mRecord->mFile->GetFileSize(&length);
if (NS_SUCCEEDED(rv)) {
*aContentLength = (PRInt32)length;
} else {
*aContentLength = -1;
}
return rv;
}
NS_IMETHODIMP
nsDiskCacheRecordChannel::GetOwner(nsISupports* *aOwner)
{
*aOwner = mOwner.get() ;
NS_IF_ADDREF(*aOwner) ;
return NS_OK ;
}
NS_IMETHODIMP
nsDiskCacheRecordChannel::SetOwner(nsISupports* aOwner)
{
mOwner = aOwner ;
return NS_OK ;
}
NS_IMETHODIMP
nsDiskCacheRecordChannel::GetLoadGroup(nsILoadGroup* *aLoadGroup)
{
// Not required to be implemented, since it is implemented by cache manager
NS_ASSERTION(0, "nsDiskCacheRecordChannel method unexpectedly called");
return NS_OK ;
}
NS_IMETHODIMP
nsDiskCacheRecordChannel::SetLoadGroup(nsILoadGroup* aLoadGroup)
{
// Not required to be implemented, since it is implemented by cache manager
NS_ASSERTION(0, "nsDiskCacheRecordChannel method unexpectedly called");
return NS_OK;
}
NS_IMETHODIMP
nsDiskCacheRecordChannel::GetNotificationCallbacks(nsIInterfaceRequestor* *aNotificationCallbacks)
{
// Not required to be implemented, since it is implemented by cache manager
NS_ASSERTION(0, "nsDiskCacheRecordChannel method unexpectedly called");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsDiskCacheRecordChannel::SetNotificationCallbacks(nsIInterfaceRequestor* aNotificationCallbacks)
{
// Not required to be implemented, since it is implemented by cache manager
NS_ASSERTION(0, "nsDiskCacheRecordChannel method unexpectedly called");
return NS_ERROR_NOT_IMPLEMENTED;
}
////////////////////////////////////////////////////////////////////////////////
// nsIStreamListener methods:
////////////////////////////////////////////////////////////////////////////////
NS_IMETHODIMP
nsDiskCacheRecordChannel::OnStartRequest(nsIChannel* transportChannel, nsISupports* context)
{
NS_ASSERTION(mRealListener, "No listener...");
return mRealListener->OnStartRequest(this, context);
}
NS_IMETHODIMP
nsDiskCacheRecordChannel::OnStopRequest(nsIChannel* transportChannel, nsISupports* context,
nsresult aStatus, const PRUnichar* aMsg)
{
nsresult rv;
rv = mRealListener->OnStopRequest(this, context, aStatus, aMsg);
if (mLoadGroup) {
if (NS_SUCCEEDED(rv)) {
mLoadGroup->RemoveChannel(this, context, aStatus, aMsg);
}
}
// Release the reference to the consumer stream listener...
mRealListener = null_nsCOMPtr();
mFileTransport = null_nsCOMPtr();
return rv;
}
NS_IMETHODIMP
nsDiskCacheRecordChannel::OnDataAvailable(nsIChannel* transportChannel, nsISupports* context,
nsIInputStream *aIStream, PRUint32 aSourceOffset,
PRUint32 aLength)
{
nsresult rv;
rv = mRealListener->OnDataAvailable(this, context, aIStream,
aSourceOffset, aLength);
//
// If the connection is being aborted cancel the transport. This will
// insure that the transport will go away even if it is blocked waiting
// for the consumer to empty the pipe...
//
if (NS_FAILED(rv)) {
mFileTransport->Cancel();
}
return rv;
}

View File

@@ -0,0 +1,76 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator.
*
* The Initial Developer of the Original Code is Intel Corp.
* Portions created by Intel Corp. are
* Copyright (C) 1999, 1999 Intel Corp. All
* Rights Reserved.
*
* Contributor(s): Yixiong Zou <yixiong.zou@intel.com>
* Carl Wong <carl.wong@intel.com>
*/
#ifndef _ns_DiskCacheRecordChannel_h_
#define _ns_DiskCacheRecordChannel_h_
#include "nsIChannel.h"
#include "nsCOMPtr.h"
#include "nsDiskCacheRecord.h"
#include "nsIStreamListener.h"
/*
* This class is plagiarized from nsMemCacheChannel
*/
class nsDiskCacheRecordChannel : public nsIChannel,
public nsIStreamListener
{
public:
nsDiskCacheRecordChannel(nsDiskCacheRecord *aRecord, nsILoadGroup *aLoadGroup);
virtual ~nsDiskCacheRecordChannel() ;
// Declare nsISupports methods
NS_DECL_ISUPPORTS
// Declare nsIRequest methods
NS_DECL_NSIREQUEST
// Declare nsIChannel methods
NS_DECL_NSICHANNEL
// Declare nsIStreamObserver methods
NS_DECL_NSISTREAMOBSERVER
// Declare nsIStreamListener methods
NS_DECL_NSISTREAMLISTENER
nsresult Init(void) ;
private:
nsresult NotifyStorageInUse(PRInt32 aBytesUsed) ;
nsDiskCacheRecord* mRecord ;
nsCOMPtr<nsILoadGroup> mLoadGroup ;
nsCOMPtr<nsISupports> mOwner ;
nsCOMPtr<nsIChannel> mFileTransport ;
nsFileSpec mSpec ;
nsCOMPtr<nsIStreamListener> mRealListener;
friend class WriteStreamWrapper ;
} ;
#endif // _ns_DiskCacheRecordChannel_h_

View File

@@ -0,0 +1,66 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator.
*
* The Initial Developer of the Original Code is Intel Corp.
* Portions created by Intel Corp. are
* Copyright (C) 1999, 1999 Intel Corp. All
* Rights Reserved.
*
* Contributor(s): Yixiong Zou <yixiong.zou@intel.com>
* Carl Wong <carl.wong@intel.com>
*/
#ifndef _NS_IDBACCESSOR_H_
#define _NS_IDBACCESSOR_H_
#include "nsISupports.h"
#include "nsIFileSpec.h"
// nsIDBAccessorIID {6AADD4D0-7785-11d3-87FE-000629D01344}
#define NS_IDBACCESSOR_IID \
{ 0x6aadd4d0, 0x7785, 0x11d3, \
{0x87, 0xfe, 0x0, 0x6, 0x29, 0xd0, 0x13, 0x44}}
// nsDBAccessorCID {6AADD4D1-7785-11d3-87FE-000629D01344}
#define NS_DBACCESSOR_CID \
{ 0x6aadd4d1, 0x7785, 0x11d3, \
{ 0x87, 0xfe, 0x0, 0x6, 0x29, 0xd0, 0x13, 0x44 }}
class nsIDBAccessor : public nsISupports
{
public:
NS_DEFINE_STATIC_IID_ACCESSOR(NS_IDBACCESSOR_IID)
NS_IMETHOD Init(nsIFileSpec* DBFile) = 0 ;
NS_IMETHOD Shutdown(void) = 0 ;
NS_IMETHOD Put(PRInt32 aID, void* anEntry, PRUint32 aLength) = 0 ;
NS_IMETHOD Get(PRInt32 aID, void** anEntry, PRUint32 *aLength) = 0 ;
NS_IMETHOD Del(PRInt32 aID, void* anEntry, PRUint32 aLength) = 0 ;
NS_IMETHOD GetID(const char* key, PRUint32 length, PRInt32* aID) = 0 ;
NS_IMETHOD EnumEntry(void* *anEntry, PRUint32* aLength, PRBool bReset) = 0 ;
NS_IMETHOD GetDBFilesize(PRUint32* aSize) = 0 ;
NS_IMETHOD GetSpecialEntry(void** anEntry, PRUint32 *aLength) = 0 ;
NS_IMETHOD SetSpecialEntry(void* anEntry, PRUint32 aLength) = 0 ;
} ;
#endif // _NS_IDBACCESSOR_H_

View File

@@ -0,0 +1,704 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator.
*
* The Initial Developer of the Original Code is Intel Corp.
* Portions created by Intel Corp. are
* Copyright (C) 1999, 1999 Intel Corp. All
* Rights Reserved.
*
* Contributor(s): Yixiong Zou <yixiong.zou@intel.com>
* Carl Wong <carl.wong@intel.com>
*/
#include "nsNetDiskCache.h"
#include "nscore.h"
#include "plstr.h"
#include "prprf.h"
#include "prtypes.h"
#include "prio.h"
#include "prsystem.h" // Directory Seperator
#include "plhash.h"
#include "prclist.h"
#include "prmem.h"
#include "prlog.h"
#include "nsIComponentManager.h"
#include "nsIServiceManager.h"
#include "nsIPref.h"
#include "mcom_db.h"
#include "nsDBEnumerator.h"
#include "nsDiskCacheRecord.h"
#include "netCore.h"
#if !defined(IS_LITTLE_ENDIAN) && !defined(IS_BIG_ENDIAN)
ERROR! Must have a byte order
#endif
#ifdef IS_LITTLE_ENDIAN
#define COPY_INT32(_a,_b) memcpy(_a, _b, sizeof(int32))
#else
#define COPY_INT32(_a,_b) /* swap */ \
do { \
((char *)(_a))[0] = ((char *)(_b))[3]; \
((char *)(_a))[1] = ((char *)(_b))[2]; \
((char *)(_a))[2] = ((char *)(_b))[1]; \
((char *)(_a))[3] = ((char *)(_b))[0]; \
} while(0)
#endif
static NS_DEFINE_CID(kPrefCID, NS_PREF_CID) ;
static NS_DEFINE_CID(kDBAccessorCID, NS_DBACCESSOR_CID) ;
static const PRUint32 DISK_CACHE_SIZE_DEFAULT = 5*1024*1024 ; // 5MB
static const char * const DISK_CACHE_PREF = "browser.cache.disk_cache_size";
static const char * const CACHE_DIR_PREF = "browser.cache.directory";
class nsDiskCacheRecord ;
nsNetDiskCache::nsNetDiskCache() :
m_Enabled(PR_TRUE) ,
m_NumEntries(0) ,
m_pNextCache(0) ,
m_pDiskCacheFolder(0) ,
m_StorageInUse(0) ,
m_DB(0) ,
m_DBCorrupted(PR_FALSE)
{
// set it to INF for now
m_MaxEntries = (PRUint32)-1 ;
NS_INIT_REFCNT();
}
nsNetDiskCache::~nsNetDiskCache()
{
SetSpecialEntry() ;
NS_IF_RELEASE(m_DB) ;
// FUR
// I think that, eventually, we also want a distinguished key in the DB which
// means "clean cache shutdown". You clear this flag when the db is first
// opened and set it just before the db is closed. If the db wasn't shutdown
// cleanly in a prior session, i.e. because the app crashed, on startup you
// scan all the individual files in directories and look for "orphans",
// i.e. cache files which don't have corresponding entries in the db. That's
// also when storage-in-use and number of entries would be recomputed.
//
// We don't necessarily need all this functionality immediately, though.
if(m_DBCorrupted) {
nsFileSpec cacheFolder ;
m_pDiskCacheFolder->GetFileSpec(&cacheFolder) ;
char nameInt[6] ;
for(nsDirectoryIterator di(cacheFolder, PR_FALSE); di.Exists(); di++) {
char* filename = di.Spec().GetLeafName() ;
char* pname = nameInt ;
pname = PL_strncpyz(pname, filename, 6) ;
if(PL_strcmp(pname, "trash") == 0)
RemoveFolder(di.Spec()) ;
nsCRT::free(filename) ;
}
}
}
NS_IMETHODIMP
nsNetDiskCache::Init(void)
{
nsresult rv ;
// don't initialize if no cache folder is set.
if(!m_pDiskCacheFolder) return NS_OK ;
if(!m_DB) {
m_DB = new nsDBAccessor() ;
if(!m_DB)
return NS_ERROR_OUT_OF_MEMORY ;
else
NS_ADDREF(m_DB) ;
}
// create cache sub directories
nsCOMPtr<nsIFileSpec> cacheSubDir;
rv = NS_NewFileSpec(getter_AddRefs(cacheSubDir));
for (int i=0; i < 32; i++) {
rv = cacheSubDir->FromFileSpec(m_pDiskCacheFolder) ;
if(NS_FAILED(rv))
return rv ;
char dirName[3];
PR_snprintf (dirName, 3, "%0.2x", i);
cacheSubDir->AppendRelativeUnixPath (dirName) ;
CreateDir(cacheSubDir);
}
return InitDB() ;
}
NS_IMETHODIMP
nsNetDiskCache::InitDB(void)
{
nsresult rv ;
if(!m_DBFile) {
NS_NewFileSpec(getter_AddRefs(m_DBFile)) ;
if(!m_DBFile)
return NS_ERROR_OUT_OF_MEMORY ;
}
rv = m_DBFile->FromFileSpec(m_pDiskCacheFolder) ;
if(NS_FAILED(rv))
return rv ;
m_DBFile->AppendRelativeUnixPath("cache.db") ;
rv = m_DB->Init(m_DBFile) ;
if(rv == NS_ERROR_FAILURE) {
// try recovery if error
DBRecovery() ;
}
rv = GetSpecialEntry() ;
if(rv == NS_ERROR_FAILURE) {
// try recovery if error
DBRecovery() ;
}
return rv ;
}
//////////////////////////////////////////////////////////////////////////
// nsISupports methods
NS_IMPL_ISUPPORTS3(nsNetDiskCache,
nsINetDataDiskCache,
nsINetDataCache,
nsISupports)
///////////////////////////////////////////////////////////////////////////
// nsINetDataCache Method
NS_IMETHODIMP
nsNetDiskCache::GetDescription(PRUnichar* *aDescription)
{
nsAutoString description("Disk Cache") ;
*aDescription = description.ToNewUnicode() ;
if(!*aDescription)
return NS_ERROR_OUT_OF_MEMORY ;
return NS_OK ;
}
/* don't alloc mem for nsICachedNetData.
* RecordID is generated using the same scheme in nsCacheDiskData,
* see GetCachedNetData() for detail.
*/
NS_IMETHODIMP
nsNetDiskCache::Contains(const char* key, PRUint32 length, PRBool *_retval)
{
*_retval = PR_FALSE ;
NS_ASSERTION(m_DB, "no db.") ;
PRInt32 id = 0 ;
nsresult rv = m_DB->GetID(key, length, &id) ;
if(NS_FAILED(rv)) {
// try recovery if error
DBRecovery() ;
return rv ;
}
void* info = 0 ;
PRUint32 info_size = 0 ;
rv = m_DB->Get(id, &info, &info_size) ;
if(NS_SUCCEEDED(rv) && info)
*_retval = PR_TRUE ;
if(NS_FAILED(rv)) {
// try recovery if error
DBRecovery() ;
}
return rv ;
}
/* regardless if it's cached or not, a copy of nsNetDiskCache would
* always be returned. so release it appropriately.
* if mem alloced, updata m_NumEntries also.
* for now, the new nsCachedNetData is not written into db yet since
* we have nothing to write.
*/
NS_IMETHODIMP
nsNetDiskCache::GetCachedNetData(const char* key, PRUint32 length, nsINetDataCacheRecord **_retval)
{
NS_ASSERTION(m_DB, "no db.") ;
nsresult rv = 0 ;
if (!_retval)
return NS_ERROR_NULL_POINTER ;
*_retval = nsnull ;
PRInt32 id = 0 ;
rv = m_DB->GetID(key, length, &id) ;
if(NS_FAILED(rv)) {
// try recovery if error
DBRecovery() ;
return rv ;
}
// construct an empty record
nsDiskCacheRecord* newRecord = new nsDiskCacheRecord(m_DB, this) ;
if(!newRecord)
return NS_ERROR_OUT_OF_MEMORY ;
rv = newRecord->Init(key, length, id) ;
if(NS_FAILED(rv)) {
delete newRecord ;
return rv ;
}
NS_ADDREF(newRecord) ; // addref for _retval
*_retval = (nsINetDataCacheRecord*) newRecord ;
void* info = 0 ;
PRUint32 info_size = 0 ;
rv = m_DB->Get(id, &info, &info_size) ;
if(NS_SUCCEEDED(rv) && info) {
// this is a previously cached record
nsresult r1 ;
r1 = newRecord->RetrieveInfo(info, info_size) ;
if(NS_SUCCEEDED(rv))
return NS_OK ;
else {
// probably a bad one
NS_RELEASE(newRecord) ;
*_retval = nsnull ;
return r1;
}
} else if (NS_SUCCEEDED(rv) && !info) {
// this is a new record.
m_NumEntries ++ ;
return NS_OK ;
} else {
// database error.
DBRecovery() ;
return rv ;
}
}
/* get an nsICachedNetData, mem needs to be de-alloced if not found. */
NS_IMETHODIMP
nsNetDiskCache::GetCachedNetDataByID(PRInt32 RecordID, nsINetDataCacheRecord **_retval)
{
NS_ASSERTION(m_DB, "no db.") ;
if (!_retval)
return NS_ERROR_NULL_POINTER ;
*_retval = nsnull ;
nsresult rv ;
void* info = 0 ;
PRUint32 info_size = 0 ;
rv = m_DB->Get(RecordID, &info, &info_size) ;
if(NS_SUCCEEDED(rv) && info) {
// construct an empty record if only found in db
nsDiskCacheRecord* newRecord = new nsDiskCacheRecord(m_DB, this) ;
if(!newRecord)
return NS_ERROR_OUT_OF_MEMORY ;
NS_ADDREF(newRecord) ; // addref for _retval
rv = newRecord->RetrieveInfo(info, info_size) ;
if(NS_SUCCEEDED(rv)) {
*_retval = (nsINetDataCacheRecord*) newRecord ;
return NS_OK ;
}
else {
// bad record, I guess
NS_RELEASE(newRecord) ; // release if bad things happen
return rv ;
}
} else {
NS_ERROR("Error: RecordID not in DB\n") ;
DBRecovery() ;
return rv ;
}
}
NS_IMETHODIMP
nsNetDiskCache::GetEnabled(PRBool *aEnabled)
{
*aEnabled = m_Enabled ;
return NS_OK ;
}
NS_IMETHODIMP
nsNetDiskCache::SetEnabled(PRBool aEnabled)
{
m_Enabled = aEnabled ;
return NS_OK ;
}
NS_IMETHODIMP
nsNetDiskCache::GetFlags(PRUint32 *aFlags)
{
*aFlags = FILE_PER_URL_CACHE;
return NS_OK ;
}
NS_IMETHODIMP
nsNetDiskCache::GetNumEntries(PRUint32 *aNumEntries)
{
*aNumEntries = m_NumEntries ;
return NS_OK ;
}
NS_IMETHODIMP
nsNetDiskCache::GetMaxEntries(PRUint32 *aMaxEntries)
{
*aMaxEntries = m_MaxEntries ;
return NS_OK ;
}
NS_IMETHODIMP
nsNetDiskCache::NewCacheEntryIterator(nsISimpleEnumerator **_retval)
{
NS_ASSERTION(m_DB, "no db.") ;
if(!_retval)
return NS_ERROR_NULL_POINTER ;
*_retval = nsnull ;
nsISimpleEnumerator* enumerator = new nsDBEnumerator(m_DB, this) ;
if(enumerator) {
NS_ADDREF(enumerator) ;
*_retval = enumerator ;
return NS_OK ;
}
else
return NS_ERROR_OUT_OF_MEMORY ;
}
NS_IMETHODIMP
nsNetDiskCache::GetNextCache(nsINetDataCache * *aNextCache)
{
if(!aNextCache)
return NS_ERROR_NULL_POINTER ;
*aNextCache = m_pNextCache ;
return NS_OK ;
}
NS_IMETHODIMP
nsNetDiskCache::SetNextCache(nsINetDataCache *aNextCache)
{
m_pNextCache = aNextCache ;
return NS_OK ;
}
// db size can always be measured at the last minute. Since it's hard
// to know before hand.
NS_IMETHODIMP
nsNetDiskCache::GetStorageInUse(PRUint32 *aStorageInUse)
{
NS_ASSERTION(m_DB, "no db.") ;
PRUint32 total_size = m_StorageInUse ;
/*
PRUint32 len = 0 ;
// add the size of the db.
m_DB->GetDBFilesize(&len) ;
total_size += len ;
*/
// we need size in kB
total_size = total_size >> 10 ;
*aStorageInUse = total_size ;
return NS_OK ;
}
/*
* The whole cache dirs can be whiped clean since all the cache
* files are resides in seperate hashed dirs. It's safe to do so.
*/
NS_IMETHODIMP
nsNetDiskCache::RemoveAll(void)
{
NS_ASSERTION(m_DB, "no db.") ;
NS_ASSERTION(m_pDiskCacheFolder, "no cache folder.") ;
// remove all the sub folders
nsFileSpec cacheSubDir;
for (int i=0; i < 32; i++) {
m_pDiskCacheFolder->GetFileSpec(&cacheSubDir) ;
char dirName[3];
PR_snprintf (dirName, 3, "%0.2x", i);
cacheSubDir += dirName ;
RemoveFolder(cacheSubDir) ;
}
// don't forget the db file itself
m_DB->Shutdown() ;
nsFileSpec dbfile ;
m_DBFile->GetFileSpec(&dbfile) ;
dbfile.Delete(PR_TRUE) ;
// reinitilize
return Init() ;
}
//////////////////////////////////////////////////////////////////
// nsINetDataDiskCache methods
NS_IMETHODIMP
nsNetDiskCache::GetDiskCacheFolder(nsIFileSpec * *aDiskCacheFolder)
{
*aDiskCacheFolder = nsnull ;
NS_ASSERTION(m_pDiskCacheFolder, "no cache folder.") ;
*aDiskCacheFolder = m_pDiskCacheFolder ;
NS_ADDREF(*aDiskCacheFolder) ;
return NS_OK ;
}
NS_IMETHODIMP
nsNetDiskCache::SetDiskCacheFolder(nsIFileSpec * aDiskCacheFolder)
{
if(!m_pDiskCacheFolder) {
NS_NewFileSpec(getter_AddRefs(m_pDiskCacheFolder));
if(!m_pDiskCacheFolder)
return NS_ERROR_OUT_OF_MEMORY ;
m_pDiskCacheFolder = aDiskCacheFolder ;
return Init() ;
}
else {
char *newfolder, *oldfolder ;
m_pDiskCacheFolder->GetNativePath(&oldfolder) ;
aDiskCacheFolder->GetNativePath(&newfolder) ;
if(PL_strcmp(newfolder, oldfolder) != 0) {
m_pDiskCacheFolder = aDiskCacheFolder ;
// do we need to blow away old cache before building a new one?
// return RemoveAll() ;
m_DB->Shutdown() ;
return Init() ;
} else
return NS_OK ;
}
}
//////////////////////////////////////////////////////////////////
// nsNetDiskCache methods
// create a directory (recursively)
NS_IMETHODIMP
nsNetDiskCache::CreateDir(nsIFileSpec* dir_spec)
{
PRBool does_exist ;
nsCOMPtr<nsIFileSpec> p_spec ;
dir_spec->Exists(&does_exist) ;
if(does_exist)
return NS_OK ;
nsresult rv = dir_spec->GetParent(getter_AddRefs(p_spec)) ;
if(NS_FAILED(rv))
return rv ;
p_spec->Exists(&does_exist) ;
if(!does_exist) {
CreateDir(p_spec) ;
rv = dir_spec->CreateDir() ;
if(NS_FAILED(rv))
return rv ;
}
else {
rv = dir_spec->CreateDir() ;
if(NS_FAILED(rv))
return rv ;
}
return NS_OK ;
}
// We can't afford to make a *separate* pass over the whole db on every
// startup, just to figure out m_NumEntries and m_StorageInUse. (This is a
// several second operation on a large db). We'll likely need to store
// distinguished keys in the db that contain these values and update them
// incrementally, except when failure to shut down the db cleanly is detected.
NS_IMETHODIMP
nsNetDiskCache::GetSpecialEntry(void)
{
void* pInfo ;
PRUint32 InfoSize ;
nsresult rv = m_DB->GetSpecialEntry(&pInfo, &InfoSize) ;
if(NS_FAILED(rv))
return rv ;
if(!pInfo && InfoSize == 0) {
// must be a new DB
m_NumEntries = 0 ;
m_StorageInUse = 0 ;
}
else {
char * cur_ptr = NS_STATIC_CAST(char*, pInfo) ;
// get m_NumEntries
COPY_INT32(&m_NumEntries, cur_ptr) ;
cur_ptr += sizeof(PRUint32) ;
// get m_StorageInUse
COPY_INT32(&m_StorageInUse, cur_ptr) ;
cur_ptr += sizeof(PRUint32) ;
PR_ASSERT(cur_ptr == NS_STATIC_CAST(char*, pInfo) + InfoSize);
}
return NS_OK ;
}
NS_IMETHODIMP
nsNetDiskCache::SetSpecialEntry(void)
{
PRUint32 InfoSize ;
InfoSize = sizeof m_NumEntries ;
InfoSize += sizeof m_StorageInUse ;
void* pInfo = nsAllocator::Alloc(InfoSize*sizeof(char)) ;
if(!pInfo)
return NS_ERROR_OUT_OF_MEMORY ;
char* cur_ptr = NS_STATIC_CAST(char*, pInfo) ;
COPY_INT32(cur_ptr, &m_NumEntries) ;
cur_ptr += sizeof(PRUint32) ;
COPY_INT32(cur_ptr, &m_StorageInUse) ;
cur_ptr += sizeof(PRUint32) ;
PR_ASSERT(cur_ptr == NS_STATIC_CAST(char*, pInfo) + InfoSize);
return m_DB->SetSpecialEntry(pInfo, InfoSize) ;
}
// this routine will be called everytime we have a db corruption.
// m_DB will be re-initialized, m_StorageInUse and m_NumEntries will
// be reset.
NS_IMETHODIMP
nsNetDiskCache::DBRecovery(void)
{
// rename all the sub cache dirs and remove them later during dtor.
nsresult rv = RenameCacheSubDirs() ;
if(NS_FAILED(rv))
return rv ;
// remove corrupted db file, don't care if db->shutdown fails or not.
m_DB->Shutdown() ;
nsFileSpec dbfile ;
m_DBFile->GetFileSpec(&dbfile) ;
dbfile.Delete(PR_TRUE) ;
// make sure it's not there any more
PRBool exists = dbfile.Exists() ;
if(exists) {
NS_ERROR("can't remove old db.") ;
return NS_ERROR_FAILURE ;
}
// reinitilize DB
return InitDB() ;
}
// this routine will add string "trash" to current CacheSubDir names.
// e.g. 00->trash00, 1f->trash1f. and update the m_DBCorrupted.
NS_IMETHODIMP
nsNetDiskCache::RenameCacheSubDirs(void)
{
nsCOMPtr<nsIFileSpec> cacheSubDir;
nsresult rv = NS_NewFileSpec(getter_AddRefs(cacheSubDir)) ;
for (int i=0; i < 32; i++) {
rv = cacheSubDir->FromFileSpec(m_pDiskCacheFolder) ;
if(NS_FAILED(rv))
return rv ;
char oldName[3], newName[8];
PR_snprintf(oldName, 3, "%0.2x", i) ;
cacheSubDir->AppendRelativeUnixPath(oldName) ;
// re-name the directory
PR_snprintf(newName, 8, "trash%0.2x", i) ;
rv = cacheSubDir->Rename(newName) ;
if(NS_FAILED(rv))
// TODO, error checking
return NS_ERROR_FAILURE ;
}
// update m_DBCorrupted
m_DBCorrupted = PR_TRUE ;
return NS_OK ;
}
// this routine is used by dtor and RemoveAll() to clean up dirs.
NS_IMETHODIMP
nsNetDiskCache::RemoveFolder(nsFileSpec aFolder)
{
for(nsDirectoryIterator di(aFolder, PR_FALSE); di.Exists(); di++) {
di.Spec().Delete(PR_TRUE) ;
}
aFolder.Delete(PR_FALSE) ; // recursive delete
return NS_OK ;
}

View File

@@ -0,0 +1,91 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator.
*
* The Initial Developer of the Original Code is Intel Corp.
* Portions created by Intel Corp. are
* Copyright (C) 1999, 1999 Intel Corp. All
* Rights Reserved.
*
* Contributor(s): Yixiong Zou <yixiong.zou@intel.com>
* Carl Wong <carl.wong@intel.com>
*/
/*
* This file is part of filecache implementation.
*
* nsNetDiskCache is the main disk cache module that will create
* the cache database, and then store and retrieve nsDiskCacheRecord
* objects from it. It also contains some basic error recovery procedure.
*/
#ifndef __gen_nsNetDiskCache_h__
#define __gen_nsNetDiskCache_h__
#include "nsINetDataDiskCache.h"
#include "nsNetDiskCacheCID.h"
#include "nsCOMPtr.h"
#include "nsIPref.h"
#include "nsDBAccessor.h"
class nsIURI; /* forward decl */
class nsICachedNetData; /* forward decl */
class nsISimpleEnumerator; /* forward decl */
class nsIFileSpec; /* forward decl */
/* starting interface: nsNetDiskCache */
class nsNetDiskCache : public nsINetDataDiskCache {
public:
NS_DECL_ISUPPORTS
NS_DECL_NSINETDATACACHE
NS_DECL_NSINETDATADISKCACHE
NS_IMETHOD Init(void) ;
nsNetDiskCache() ;
virtual ~nsNetDiskCache() ;
protected:
NS_IMETHOD InitDB(void) ;
NS_IMETHOD CreateDir(nsIFileSpec* dir_spec) ;
NS_IMETHOD GetSpecialEntry(void) ;
NS_IMETHOD SetSpecialEntry(void) ;
NS_IMETHOD RenameCacheSubDirs(void) ;
NS_IMETHOD DBRecovery(void) ;
NS_IMETHOD RemoveFolder(nsFileSpec aFolder) ;
private:
PRBool m_Enabled ;
PRUint32 m_NumEntries ;
nsCOMPtr<nsINetDataCache> m_pNextCache ;
nsCOMPtr<nsIFileSpec> m_pDiskCacheFolder ;
nsCOMPtr<nsIFileSpec> m_DBFile ;
PRUint32 m_MaxEntries ;
PRUint32 m_StorageInUse ;
nsIDBAccessor* m_DB ;
// this is used to indicate a db corruption
PRBool m_DBCorrupted ;
friend class nsDiskCacheRecord ;
friend class nsDiskCacheRecordChannel ;
friend class nsDBEnumerator ;
} ;
#endif /* __gen_nsNetDiskCache_h__ */

View File

@@ -0,0 +1,32 @@
/*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator.
*
* The Initial Developer of the Original Code is Intel Corp.
* Portions created by Intel Corp. are
* Copyright (C) 1999, 1999 Intel Corp. All
* Rights Reserved.
*
* Contributor(s): Yixiong Zou <yixiong.zou@intel.com>
* Carl Wong <carl.wong@intel.com>
*/
#ifndef _nsNetDiskCacheCID_h_
#define _nsNetDiskCacheCID_h_
#define NS_NETDISKCACHE_CID_STR "ECFEEA00-7201-11d3-87FE-000629D01344"
#define NS_NETDISKCACHE_CID \
{ 0xecfeea00, 0x7201, 0x11d3, \
{ 0x87, 0xfe, 0x0, 0x6, 0x29, 0xd0, 0x13, 0x44 }}
#endif /* _nsNetDiskCacheCID_h_ */

View File

@@ -0,0 +1,50 @@
#
# The contents of this file are subject to the Netscape Public License
# Version 1.0 (the "NPL"); you may not use this file except in
# compliance with the NPL. You may obtain a copy of the NPL at
# http://www.mozilla.org/NPL/
#
# Software distributed under the NPL is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
# for the specific language governing rights and limitations under the
# NPL.
#
# The Initial Developer of this code under the NPL is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All Rights
# Reserved.
#
DEPTH = ../../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
REQUIRES = libreg xpcom
CPPSRCS = \
diskcache.cpp \
$(NULL)
SIMPLE_PROGRAMS = $(CPPSRCS:.cpp=)
ifdef NO_LD_ARCHIVE_FLAGS
LOST_SYM_LIBS = -lxpcomds_s -lxptinfo -lmozreg_s
endif
LIBS = \
-lmozjs \
-lxpcom \
-lmozdbm_s \
$(MOZ_NECKO_UTIL_LIBS) \
$(LOST_SYM_LIBS) \
$(NSPR_LIBS) \
$(NULL)
include $(topsrcdir)/config/rules.mk
LOCAL_INCLUDES = -I$(srcdir)/..
DEFINES += -DUSE_NSREG -DCACHE

View File

@@ -0,0 +1,836 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "nsIStreamListener.h"
#include "nsIStreamObserver.h"
#include "nsIServiceManager.h"
#include "nsIInputStream.h"
#include "nsIOutputStream.h"
#include "nsIEventQueue.h"
#include "nsIEventQueueService.h"
#include "nsIChannel.h"
#include "nsCOMPtr.h"
#include "nsString.h"
#include <stdio.h>
#include <unistd.h>
#include "nsINetDataCache.h"
#include "nsINetDataCacheRecord.h"
//#include "nsMemCacheCID.h"
#include "nsNetDiskCache.h"
#include "nsIPref.h"
#include "prenv.h"
#include "nsIFileStream.h"
// Number of test entries to be placed in the cache
#define NUM_CACHE_ENTRIES 250
// Cache content stream length will have random length between zero and
// MAX_CONTENT_LENGTH bytes
#define MAX_CONTENT_LENGTH 20000
// Length of random-data cache entry key
#define CACHE_KEY_LENGTH 15
// Length of random-data cache entry meta-data
#define CACHE_METADATA_LENGTH 100
//static NS_DEFINE_CID(kMemCacheCID, NS_MEM_CACHE_FACTORY_CID);
static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
static NS_DEFINE_CID(kDiskCacheCID, NS_NETDISKCACHE_CID) ;
static NS_DEFINE_CID(kPrefCID, NS_PREF_CID);
static NS_DEFINE_IID(kIPrefIID, NS_IPREF_IID);
// Mapping from test case number to RecordID
static PRInt32 recordID[NUM_CACHE_ENTRIES];
static PRInt32
mapRecordIdToTestNum(PRInt32 aRecordID)
{
int i;
for (i = 0; i < NUM_CACHE_ENTRIES; i++) {
if (recordID[i] == aRecordID)
return i;
}
return -1;
}
// A supply of stream data to either store or compare with
class nsITestDataStream {
public:
virtual ~nsITestDataStream() {};
virtual PRUint32 Next() = 0;
virtual void Read(char* aBuf, PRUint32 aCount) = 0;
virtual PRBool Match(char* aBuf, PRUint32 aCount) = 0;
virtual void Skip(PRUint32 aCount) = 0;
};
// A reproducible stream of random data.
class RandomStream : public nsITestDataStream {
public:
RandomStream(PRUint32 aSeed) {
mStartSeed = mState = aSeed;
}
PRUint32 GetStartSeed() {
return mStartSeed;
}
PRUint32 Next() {
mState = 1103515245 * mState + 12345;
return mState;
}
void Read(char* aBuf, PRUint32 aCount) {
PRUint32 i;
for (i = 0; i < aCount; i++) {
*aBuf++ = Next();
}
}
PRBool
Match(char* aBuf, PRUint32 aCount) {
PRUint32 i;
for (i = 0; i < aCount; i++) {
if (*aBuf++ != (char)(Next() & 0xff))
return PR_FALSE;
}
return PR_TRUE;
}
void
Skip(PRUint32 aCount) {
while (aCount--)
Next();
}
protected:
PRUint32 mState;
PRUint32 mStartSeed;
};
// A stream of data that increments on each byte that is read, modulo 256
class CounterStream : public nsITestDataStream {
public:
CounterStream(PRUint32 aSeed) {
mStartSeed = mState = aSeed;
}
PRUint32 GetStartSeed() {
return mStartSeed;
}
PRUint32 Next() {
mState += 1;
mState &= 0xff;
return mState;
}
void Read(char* aBuf, PRUint32 aCount) {
PRUint32 i;
for (i = 0; i < aCount; i++) {
*aBuf++ = Next();
}
}
PRBool
Match(char* aBuf, PRUint32 aCount) {
PRUint32 i;
for (i = 0; i < aCount; i++) {
if (*aBuf++ != (char)Next())
return PR_FALSE;
}
return PR_TRUE;
}
void
Skip(PRUint32 aCount) {
mState += aCount;
mState &= 0xff;
}
protected:
PRUint32 mState;
PRUint32 mStartSeed;
};
static int gNumReaders = 0;
static PRUint32 gTotalBytesRead = 0;
static PRUint32 gTotalDuration = 0;
class nsReader : public nsIStreamListener {
public:
NS_DECL_ISUPPORTS
nsReader()
: mStartTime(0), mBytesRead(0)
{
NS_INIT_REFCNT();
gNumReaders++;
}
virtual ~nsReader() {
delete mTestDataStream;
gNumReaders--;
}
nsresult
Init(nsIChannel *aChannel, nsITestDataStream* aRandomStream, PRUint32 aExpectedStreamLength) {
mChannel = aChannel;
mTestDataStream = aRandomStream;
mExpectedStreamLength = aExpectedStreamLength;
mRefCnt = 1;
return NS_OK;
}
NS_IMETHOD OnStartRequest(nsIChannel* channel,
nsISupports* context) {
mStartTime = PR_IntervalNow();
return NS_OK;
}
NS_IMETHOD OnDataAvailable(nsIChannel* channel,
nsISupports* context,
nsIInputStream *aIStream,
PRUint32 aSourceOffset,
PRUint32 aLength) {
char buf[1025];
while (aLength > 0) {
PRUint32 amt;
PRBool match;
aIStream->Read(buf, sizeof buf, &amt);
if (amt == 0) break;
aLength -= amt;
mBytesRead += amt;
match = mTestDataStream->Match(buf, amt);
NS_ASSERTION(match, "Stored data was corrupted on read");
}
return NS_OK;
}
NS_IMETHOD OnStopRequest(nsIChannel* channel,
nsISupports* context,
nsresult aStatus,
const PRUnichar* aMsg) {
PRIntervalTime endTime;
PRIntervalTime duration;
endTime = PR_IntervalNow();
duration = (endTime - mStartTime);
if (NS_FAILED(aStatus)) printf("channel failed.\n");
// printf("read %d bytes\n", mBytesRead);
NS_ASSERTION(mBytesRead == mExpectedStreamLength,
"Stream in cache is wrong length");
gTotalBytesRead += mBytesRead;
gTotalDuration += duration;
// Release channel
mChannel = 0;
return NS_OK;
}
protected:
PRIntervalTime mStartTime;
PRUint32 mBytesRead;
nsITestDataStream* mTestDataStream;
PRUint32 mExpectedStreamLength;
nsCOMPtr<nsIChannel> mChannel;
};
NS_IMPL_ISUPPORTS2(nsReader, nsIStreamListener, nsIStreamObserver)
static nsIEventQueue* eventQueue;
nsresult
InitQueue() {
nsresult rv;
NS_WITH_SERVICE(nsIEventQueueService, eventQService, kEventQueueServiceCID, &rv);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get event queue service");
rv = eventQService->CreateThreadEventQueue();
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't create event queue");
rv = eventQService->GetThreadEventQueue(PR_CurrentThread(), &eventQueue);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get event queue for main thread");
return NS_OK;
}
// Process events until all streams are OnStopRequest'ed
nsresult
WaitForEvents() {
while (gNumReaders) {
eventQueue->ProcessPendingEvents();
}
return NS_OK;
}
// Read data for a single cache record and compare against testDataStream
nsresult
TestReadStream(nsINetDataCacheRecord *record, nsITestDataStream *testDataStream,
PRUint32 expectedStreamLength)
{
nsCOMPtr<nsIChannel> channel;
nsresult rv;
PRUint32 actualContentLength;
rv = record->NewChannel(0, getter_AddRefs(channel));
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
rv = record->GetStoredContentLength(&actualContentLength);
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
NS_ASSERTION(actualContentLength == expectedStreamLength,
"nsINetDataCacheRecord::GetContentLength() busted ?");
nsReader *reader = new nsReader;
reader->AddRef();
rv = reader->Init(channel, testDataStream, expectedStreamLength);
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
rv = channel->AsyncRead(0, -1, 0, reader);
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
reader->Release();
return NS_OK;
}
// Check that records can be retrieved using their record-ID, in addition
// to using the opaque key.
nsresult
TestRecordID(nsINetDataCache *cache)
{
nsresult rv;
nsCOMPtr<nsINetDataCacheRecord> record;
RandomStream *randomStream;
PRUint32 metaDataLength;
char cacheKey[CACHE_KEY_LENGTH];
char *metaData;
PRUint32 testNum;
PRBool match;
for (testNum = 0; testNum < NUM_CACHE_ENTRIES; testNum++) {
randomStream = new RandomStream(testNum);
randomStream->Read(cacheKey, sizeof cacheKey);
rv = cache->GetCachedNetDataByID(recordID[testNum], getter_AddRefs(record));
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't obtain record using record ID");
// Match against previously stored meta-data
rv = record->GetMetaData(&metaDataLength, &metaData);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get record meta-data");
match = randomStream->Match(metaData, metaDataLength);
NS_ASSERTION(match, "Meta-data corrupted or incorrect");
nsAllocator::Free(metaData);
delete randomStream;
}
return NS_OK;
}
// Check that all cache entries in the database are enumerated and that
// no duplicates appear.
nsresult
TestEnumeration(nsINetDataCache *cache)
{
nsresult rv;
nsCOMPtr<nsINetDataCacheRecord> record;
nsCOMPtr<nsISupports> tempISupports;
nsCOMPtr<nsISimpleEnumerator> iterator;
RandomStream *randomStream;
PRUint32 metaDataLength;
char cacheKey[CACHE_KEY_LENGTH];
char *metaData;
PRUint32 testNum;
PRBool match;
PRInt32 recID;
int numRecords = 0;
// Iterate over all records in the cache
rv = cache->NewCacheEntryIterator(getter_AddRefs(iterator));
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't create new cache entry iterator");
PRBool notDone;
while (1) {
// Done iterating ?
rv = iterator->HasMoreElements(&notDone);
if (NS_FAILED(rv)) return rv;
if (!notDone)
break;
// Get next record in iteration
rv = iterator->GetNext(getter_AddRefs(tempISupports));
NS_ASSERTION(NS_SUCCEEDED(rv), "iterator bustage");
record = do_QueryInterface(tempISupports);
numRecords++;
// Get record ID
rv = record->GetRecordID(&recID);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get Record ID");
testNum = mapRecordIdToTestNum(recID);
NS_ASSERTION(testNum != -1, "Corrupted Record ID ?");
// Erase mapping from table, so that duplicate enumerations are detected
recordID[testNum] = -1;
// Make sure stream matches test data
randomStream = new RandomStream(testNum);
randomStream->Read(cacheKey, sizeof cacheKey);
// Match against previously stored meta-data
rv = record->GetMetaData(&metaDataLength, &metaData);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get record meta-data");
match = randomStream->Match(metaData, metaDataLength);
NS_ASSERTION(match, "Meta-data corrupted or incorrect");
nsAllocator::Free(metaData);
delete randomStream;
}
NS_ASSERTION(numRecords == NUM_CACHE_ENTRIES, "Iteration bug");
return NS_OK;
}
// Read the test data that was written in FillCache(), checking for
// corruption, truncation.
nsresult
TestRead(nsINetDataCache *cache)
{
nsresult rv;
PRBool inCache;
nsCOMPtr<nsINetDataCacheRecord> record;
RandomStream *randomStream;
PRUint32 metaDataLength;
char cacheKey[CACHE_KEY_LENGTH];
char *metaData, *storedCacheKey;
PRUint32 testNum, storedCacheKeyLength;
PRBool match;
for (testNum = 0; testNum < NUM_CACHE_ENTRIES; testNum++) {
randomStream = new RandomStream(testNum);
randomStream->Read(cacheKey, sizeof cacheKey);
// Ensure that entry is in the cache
rv = cache->Contains(cacheKey, sizeof cacheKey, &inCache);
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
NS_ASSERTION(inCache, "nsINetDataCache::Contains error");
rv = cache->GetCachedNetData(cacheKey, sizeof cacheKey, getter_AddRefs(record));
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
// Match against previously stored meta-data
match = record->GetMetaData(&metaDataLength, &metaData);
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
match = randomStream->Match(metaData, metaDataLength);
NS_ASSERTION(match, "Meta-data corrupted or incorrect");
nsAllocator::Free(metaData);
// Test GetKey() method
rv = record->GetKey(&storedCacheKeyLength, &storedCacheKey);
NS_ASSERTION(NS_SUCCEEDED(rv) &&
(storedCacheKeyLength == sizeof cacheKey) &&
!memcmp(storedCacheKey, &cacheKey[0], sizeof cacheKey),
"nsINetDataCacheRecord::GetKey failed");
nsAllocator::Free(storedCacheKey);
PRUint32 expectedStreamLength = randomStream->Next() & 0xffff;
TestReadStream(record, randomStream, expectedStreamLength);
}
WaitForEvents();
// Compute rate in MB/s
double rate = gTotalBytesRead / PR_IntervalToMilliseconds(gTotalDuration);
rate *= NUM_CACHE_ENTRIES;
rate *= 1000;
rate /= (1024 * 1024);
printf("Read %d bytes at a rate of %5.1f MB per second \n",
gTotalBytesRead, rate);
return NS_OK;
}
// Repeatedly call SetStoredContentLength() on a cache entry and make
// read the stream's data to ensure that it's not corrupted by the effect
nsresult
TestTruncation(nsINetDataCache *cache)
{
nsresult rv;
nsCOMPtr<nsINetDataCacheRecord> record;
RandomStream *randomStream;
char cacheKey[CACHE_KEY_LENGTH];
randomStream = new RandomStream(0);
randomStream->Read(cacheKey, sizeof cacheKey);
rv = cache->GetCachedNetData(cacheKey, sizeof cacheKey, getter_AddRefs(record));
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
randomStream->Skip(CACHE_METADATA_LENGTH);
PRUint32 initialStreamLength = randomStream->Next() & 0xffff;
delete randomStream;
PRUint32 i;
PRUint32 delta = initialStreamLength / 64;
for (i = initialStreamLength; i >= delta; i -= delta) {
PRUint32 expectedStreamLength = i;
// Do the truncation
record->SetStoredContentLength(expectedStreamLength);
randomStream = new RandomStream(0);
randomStream->Skip(CACHE_KEY_LENGTH + CACHE_METADATA_LENGTH + 1);
TestReadStream(record, randomStream, expectedStreamLength);
WaitForEvents();
}
return NS_OK;
}
// Write known data to random offsets in a single cache entry and test
// resulting stream for correctness.
nsresult
TestOffsetWrites(nsINetDataCache *cache)
{
nsresult rv;
nsCOMPtr<nsINetDataCacheRecord> record;
nsCOMPtr<nsIChannel> channel;
nsCOMPtr<nsIOutputStream> outStream;
char buf[512];
char cacheKey[CACHE_KEY_LENGTH];
RandomStream *randomStream;
randomStream = new RandomStream(0);
randomStream->Read(cacheKey, sizeof cacheKey);
rv = cache->GetCachedNetData(cacheKey, sizeof cacheKey, getter_AddRefs(record));
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't access record via opaque cache key");
nsCOMPtr<nsIFileSpec> file ;
record->GetFilename(getter_AddRefs(file)) ;
char* name ;
file->GetUnixStyleFilePath(&name) ;
printf(" file name is %s \n", name) ;
// Write buffer-fulls of data at random offsets into the cache entry.
// Data written is (offset % 0xff)
PRUint32 startingOffset;
PRUint32 streamLength = 0;
PRUint32 len = 0 ;
CounterStream *counterStream;
int i = 0;
for (i = 0; i < 257; i++) {
rv = record->NewChannel(0, getter_AddRefs(channel));
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
startingOffset = streamLength ? streamLength - (randomStream->Next() % sizeof buf): 0;
rv = channel->OpenOutputStream(startingOffset, getter_AddRefs(outStream));
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
truncate(name, startingOffset) ;
counterStream = new CounterStream(startingOffset);
counterStream->Read(buf, sizeof buf);
nsresult status ;
nsCOMPtr<nsIRandomAccessStore> ras = do_QueryInterface(outStream, &status);
if (NS_FAILED(status)) {
// mState = END_WRITE;
return NS_ERROR_FAILURE;
}
PRIntn offset ;
ras->Tell(&offset) ;
// printf(" offset is %d \n", offset) ;
PRUint32 numWritten;
rv = outStream->Write(buf, sizeof buf, &numWritten);
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
NS_ASSERTION(numWritten == sizeof buf, "Write() bug?");
streamLength = startingOffset + sizeof buf;
rv = outStream->Close();
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't close channel");
delete counterStream;
record->GetStoredContentLength(&len) ;
if(len != streamLength)
printf(" offset = %d is wrong, filesize = %d\n", startingOffset, len) ;
}
/*
rv = record->NewChannel(0, getter_AddRefs(channel));
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
startingOffset = 208;
rv = channel->OpenOutputStream(startingOffset, getter_AddRefs(outStream));
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
counterStream = new CounterStream(startingOffset);
counterStream->Read(buf, sizeof buf);
nsresult status ;
nsCOMPtr<nsIRandomAccessStore> ras = do_QueryInterface(outStream, &status);
if (NS_FAILED(status)) {
// mState = END_WRITE;
return NS_ERROR_FAILURE;
}
PRIntn offset = 0 ;
ras->Tell(&offset) ;
printf(" offset is %d \n", offset) ;
PRUint32 numWritten;
rv = outStream->Write(buf, sizeof buf, &numWritten);
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
NS_ASSERTION(numWritten == sizeof buf, "Write() bug?");
streamLength = startingOffset + sizeof buf;
rv = outStream->Close();
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't close channel");
delete counterStream;
record->GetStoredContentLength(&len) ;
if(len != streamLength)
printf(" offset = %d is wrong, filesize = %d\n", startingOffset, len) ;
*/
delete randomStream;
counterStream = new CounterStream(0);
TestReadStream(record, counterStream, streamLength);
WaitForEvents();
return NS_OK;
}
// Create entries in the network data cache, using random data for the
// key, the meta-data and the stored content data.
nsresult
FillCache(nsINetDataCache *cache)
{
nsresult rv;
PRBool inCache;
nsCOMPtr<nsINetDataCacheRecord> record;
nsCOMPtr<nsIChannel> channel;
nsCOMPtr<nsIOutputStream> outStream;
char buf[1000];
PRUint32 metaDataLength;
char cacheKey[CACHE_KEY_LENGTH];
char metaData[CACHE_METADATA_LENGTH];
PRUint32 testNum;
char *data;
RandomStream *randomStream;
PRIntervalTime startTime = PR_IntervalNow();
for (testNum = 0; testNum < NUM_CACHE_ENTRIES; testNum++) {
randomStream = new RandomStream(testNum);
randomStream->Read(cacheKey, sizeof cacheKey);
// No entry should be in cache until we add it
rv = cache->Contains(cacheKey, sizeof cacheKey, &inCache);
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
NS_ASSERTION(!inCache, "nsINetDataCache::Contains error");
rv = cache->GetCachedNetData(cacheKey, sizeof cacheKey, getter_AddRefs(record));
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't access record via opaque cache key");
// Test nsINetDataCacheRecord::GetRecordID()
rv = record->GetRecordID(&recordID[testNum]);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get Record ID");
// Test nsINetDataCache::GetNumEntries()
PRUint32 numEntries = (PRUint32)-1;
rv = cache->GetNumEntries(&numEntries);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get number of cache entries");
NS_ASSERTION(numEntries == testNum + 1, "GetNumEntries failure");
// Record meta-data should be initially empty
rv = record->GetMetaData(&metaDataLength, &data);
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
if ((metaDataLength != 0) || (data != 0))
return NS_ERROR_FAILURE;
// Store random data as meta-data
randomStream->Read(metaData, sizeof metaData);
record->SetMetaData(sizeof metaData, metaData);
rv = record->NewChannel(0, getter_AddRefs(channel));
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
rv = channel->OpenOutputStream(0, getter_AddRefs(outStream));
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
PRUint32 beforeOccupancy;
rv = cache->GetStorageInUse(&beforeOccupancy);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get cache occupancy");
int streamLength = randomStream->Next() & 0xffff;
int remaining = streamLength;
while (remaining) {
PRUint32 numWritten;
int amount = PR_MIN(sizeof buf, remaining);
randomStream->Read(buf, amount);
rv = outStream->Write(buf, amount, &numWritten);
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
NS_ASSERTION(numWritten == (PRUint32)amount, "Write() bug?");
remaining -= amount;
}
outStream->Close();
PRUint32 afterOccupancy;
rv = cache->GetStorageInUse(&afterOccupancy);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get cache occupancy");
PRUint32 streamLengthInKB = streamLength >> 10;
NS_ASSERTION((afterOccupancy - beforeOccupancy) >= streamLengthInKB,
"nsINetDataCache::GetStorageInUse() is busted");
// *Now* there should be an entry in the cache
rv = cache->Contains(cacheKey, sizeof cacheKey, &inCache);
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
NS_ASSERTION(inCache, "nsINetDataCache::Contains error");
delete randomStream;
}
PRIntervalTime endTime = PR_IntervalNow();
return NS_OK;
}
nsresult NS_AutoregisterComponents()
{
nsresult rv = nsComponentManager::AutoRegister(nsIComponentManager::NS_Startup,
NULL /* default */);
return rv;
}
PRBool initPref ()
{
nsresult rv;
NS_WITH_SERVICE(nsIPref, prefPtr, kPrefCID, &rv);
if (NS_FAILED(rv))
return false;
nsCOMPtr<nsIFileSpec> fileSpec;
rv = NS_NewFileSpec (getter_AddRefs(fileSpec));
if (NS_FAILED(rv))
return false;
nsCString defaultPrefFile = PR_GetEnv ("MOZILLA_FIVE_HOME");
if (defaultPrefFile.Length())
defaultPrefFile += "/";
else
defaultPrefFile = "./";
defaultPrefFile += "default_prefs.js";
fileSpec->SetUnixStyleFilePath (defaultPrefFile.GetBuffer());
PRBool exists = false;
fileSpec->Exists(&exists);
if (exists)
prefPtr->ReadUserPrefsFrom(fileSpec);
else
return false;
return true;
}
int
main(int argc, char* argv[])
{
initPref() ;
nsresult rv;
nsCOMPtr<nsINetDataCache> cache;
rv = NS_AutoregisterComponents();
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't register XPCOM components");
rv = nsComponentManager::CreateInstance(kDiskCacheCID, nsnull,
NS_GET_IID(nsINetDataCache),
getter_AddRefs(cache));
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't create memory cache factory");
InitQueue();
PRUnichar* description;
rv = cache->GetDescription(&description);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get cache description");
nsCAutoString descStr(description);
printf("Testing: %s\n", descStr.GetBuffer());
rv = cache->RemoveAll();
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't clear cache");
PRUint32 startOccupancy;
rv = cache->GetStorageInUse(&startOccupancy);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get cache occupancy");
PRUint32 numEntries = (PRUint32)-1;
rv = cache->GetNumEntries(&numEntries);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get number of cache entries");
NS_ASSERTION(numEntries == 0, "Couldn't clear cache");
rv = FillCache(cache);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't fill cache with random test data");
rv = TestRead(cache);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't read random test data from cache");
rv = TestRecordID(cache);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't index records using record ID");
rv = TestEnumeration(cache);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't successfully enumerate records");
rv = TestTruncation(cache);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't successfully truncate records");
rv = TestOffsetWrites(cache);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't successfully write to records using non-zero offsets");
rv = cache->RemoveAll();
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't clear cache");
rv = cache->GetNumEntries(&numEntries);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get number of cache entries");
NS_ASSERTION(numEntries == 0, "Couldn't clear cache");
PRUint32 endOccupancy;
rv = cache->GetStorageInUse(&endOccupancy);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get cache occupancy");
NS_ASSERTION(startOccupancy == endOccupancy, "Cache occupancy not correctly computed ?");
return 0;
}

View File

@@ -0,0 +1,48 @@
# Generated automatically from Makefile.in by configure.
#
# The contents of this file are subject to the Netscape Public License
# Version 1.0 (the "NPL"); you may not use this file except in
# compliance with the NPL. You may obtain a copy of the NPL at
# http://www.mozilla.org/NPL/
#
# Software distributed under the NPL is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
# for the specific language governing rights and limitations under the
# NPL.
#
# The Initial Developer of this code under the NPL is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All Rights
# Reserved.
#
DEPTH = ../../..
topsrcdir = @top_srcdir@
VPATH = @srcdir@
srcdir = @srcdir@
include $(DEPTH)/config/autoconf.mk
MODULE = nkcache
LIBRARY_NAME = nkmemcache_s
REQUIRES = nspr dbm
EXPORTS=nsMemCacheCID.h \
nsMemCache.h \
$(NULL)
CPPSRCS = \
nsMemCache.cpp \
nsMemCacheRecord.cpp \
nsMemCacheChannel.cpp \
$(NULL)
# we don't want the shared lib, but we want to force the creation of a
# static lib.
override NO_SHARED_LIB=1
override NO_STATIC_LIB=
include $(topsrcdir)/config/rules.mk

View File

@@ -1,3 +1,5 @@
#!nmake
#
# The contents of this file are subject to the Netscape Public License
# Version 1.0 (the "NPL"); you may not use this file except in
# compliance with the NPL. You may obtain a copy of the NPL at
@@ -12,24 +14,29 @@
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All Rights
# Reserved.
#
# This is a list of local files which get copied to the mozilla:dist:mailnews directory
#
nsMsgLineBuffer.h
nsMsgGroupRecord.h
nsUInt32Array.h
nsMsgKeySet.h
nsMsgFolder.h
nsMsgDBFolder.h
nsLocalFolderSummarySpec.h
nsMsgIdentity.h
nsMsgIncomingServer.h
nsNewsSummarySpec.h
nsMsgUtils.h
nsMessage.h
nsMsgProtocol.h
nsMsgTxn.h
nsMsgMailNewsUrl.h
nsMsgI18N.h
DEPTH=..\..\..
include <$(DEPTH)/config/config.mak>
MODULE = nkcache
LIBRARY_NAME = nkmemcache_s
CPP_OBJS = \
.\$(OBJDIR)\nsMemCache.obj \
.\$(OBJDIR)\nsMemCacheRecord.obj \
.\$(OBJDIR)\nsMemCacheChannel.obj \
$(NULL)
EXPORTS=nsMemCacheCID.h
include <$(DEPTH)\config\rules.mak>
install:: $(LIBRARY)
$(MAKE_INSTALL) $(LIBRARY) $(DIST)\lib
clobber::
rm -rf $(OBJDIR)
rm -f $(DIST)\lib\$(LIBRARY_NAME).lib

View File

@@ -0,0 +1,334 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator client code, released
* March 31, 1998.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
*/
/**
* nsMemCache is the implementation of an in-memory network-data
* cache, used to cache the responses to network retrieval commands.
* Each cache entry may contain both content, e.g. GIF image data, and
* associated metadata, e.g. HTTP headers. Each entry is indexed by
* two different keys: a record id number and an opaque key, which is
* created by the cache manager by combining the URI with a "secondary
* key", e.g. HTTP post data.
*/
#include "nsMemCache.h"
#include "nsMemCacheRecord.h"
#include "nsIGenericFactory.h"
#include "nsString.h"
#include "nsHashtable.h"
#include "nsHashtableEnumerator.h"
#include "nsEnumeratorUtils.h"
PRInt32 nsMemCache::gRecordSerialNumber = 0;
nsMemCache::nsMemCache()
: mNumEntries(0), mOccupancy(0), mEnabled(PR_TRUE),
mHashTable(0)
{
NS_INIT_REFCNT();
}
nsMemCache::~nsMemCache()
{
nsresult rv;
rv = RemoveAll();
NS_ASSERTION(NS_SUCCEEDED(rv) && (mNumEntries == 0),
"Failure to shut down memory cache. "
"Somewhere, someone is holding references to at least one cache record");
delete mHashTable;
}
nsresult
nsMemCache::Init()
{
mHashTable = new nsHashtable(256);
if (!mHashTable)
return NS_ERROR_OUT_OF_MEMORY;
return NS_OK;
}
NS_IMPL_ISUPPORTS(nsMemCache, NS_GET_IID(nsINetDataCache))
NS_IMETHODIMP
nsMemCache::GetDescription(PRUnichar * *aDescription)
{
nsAutoString description("Memory Cache");
*aDescription = description.ToNewUnicode();
if (!*aDescription)
return NS_ERROR_OUT_OF_MEMORY;
return NS_OK;
}
NS_IMETHODIMP
nsMemCache::Contains(const char *aKey, PRUint32 aKeyLength, PRBool *aFound)
{
nsOpaqueKey *opaqueKey = new nsOpaqueKey(aKey, aKeyLength);
if (!opaqueKey)
return NS_ERROR_OUT_OF_MEMORY;
*aFound = mHashTable->Exists(opaqueKey);
delete opaqueKey;
return NS_OK;
}
NS_IMETHODIMP
nsMemCache::GetCachedNetData(const char *aKey, PRUint32 aKeyLength,
nsINetDataCacheRecord* *aRecord)
{
nsresult rv;
nsMemCacheRecord* record = 0;
nsOpaqueKey *opaqueKey2 = 0;
nsOpaqueKey *opaqueKey3 = 0;
nsOpaqueKey *opaqueKey;
opaqueKey = new nsOpaqueKey(aKey, aKeyLength);
if (!opaqueKey)
goto out_of_memory;
record = (nsMemCacheRecord*)mHashTable->Get(opaqueKey);
delete opaqueKey;
// No existing cache database entry was found. Create a new one.
// This requires two mappings in the hash table:
// Record ID ==> record
// Opaque key ==> record
if (!record) {
record = new nsMemCacheRecord;
if (!record)
goto out_of_memory;
rv = record->Init(aKey, aKeyLength, ++gRecordSerialNumber, this);
if (NS_FAILED(rv)) goto out_of_memory;
// Index the record by opaque key
opaqueKey2 = new nsOpaqueKey(record->mKey, record->mKeyLength);
if (!opaqueKey2) goto out_of_memory;
mHashTable->Put(opaqueKey2, record);
// Index the record by it's record ID
char *recordIDbytes = NS_REINTERPRET_CAST(char *, &record->mRecordID);
opaqueKey3 = new nsOpaqueKey(recordIDbytes,
sizeof record->mRecordID);
if (!opaqueKey3) {
// Clean up the first record from the hash table
mHashTable->Remove(opaqueKey);
goto out_of_memory;
}
mHashTable->Put(opaqueKey3, record);
// The hash table holds on to the record
record->AddRef();
delete opaqueKey2;
delete opaqueKey3;
mNumEntries++;
}
record->AddRef();
*aRecord = record;
return NS_OK;
out_of_memory:
delete opaqueKey2;
delete opaqueKey3;
delete record;
return NS_ERROR_OUT_OF_MEMORY;
}
NS_IMETHODIMP
nsMemCache::GetCachedNetDataByID(PRInt32 RecordID,
nsINetDataCacheRecord* *aRecord)
{
nsOpaqueKey opaqueKey(NS_REINTERPRET_CAST(const char *, &RecordID),
sizeof RecordID);
*aRecord = (nsINetDataCacheRecord*)mHashTable->Get(&opaqueKey);
if (*aRecord) {
NS_ADDREF(*aRecord);
return NS_OK;
}
return NS_ERROR_FAILURE;
}
NS_METHOD
nsMemCache::Delete(nsMemCacheRecord* aRecord)
{
nsMemCacheRecord *removedRecord;
char *recordIDbytes = NS_REINTERPRET_CAST(char *, &aRecord->mRecordID);
nsOpaqueKey opaqueRecordIDKey(recordIDbytes,
sizeof aRecord->mRecordID);
removedRecord = (nsMemCacheRecord*)mHashTable->Remove(&opaqueRecordIDKey);
NS_ASSERTION(removedRecord == aRecord, "memory cache database inconsistent");
nsOpaqueKey opaqueKey(aRecord->mKey, aRecord->mKeyLength);
removedRecord = (nsMemCacheRecord*)mHashTable->Remove(&opaqueKey);
NS_ASSERTION(removedRecord == aRecord, "memory cache database inconsistent");
aRecord->Release();
mNumEntries--;
return NS_OK;
}
NS_IMETHODIMP
nsMemCache::GetEnabled(PRBool *aEnabled)
{
NS_ENSURE_ARG(aEnabled);
*aEnabled = mEnabled;
return NS_OK;
}
NS_IMETHODIMP
nsMemCache::SetEnabled(PRBool aEnabled)
{
mEnabled = aEnabled;
return NS_OK;
}
NS_IMETHODIMP
nsMemCache::GetFlags(PRUint32 *aFlags)
{
NS_ENSURE_ARG(aFlags);
*aFlags = MEMORY_CACHE;
return NS_OK;
}
NS_IMETHODIMP
nsMemCache::GetNumEntries(PRUint32 *aNumEntries)
{
NS_ENSURE_ARG(aNumEntries);
*aNumEntries = mNumEntries;
return NS_OK;
}
NS_IMETHODIMP
nsMemCache::GetMaxEntries(PRUint32 *aMaxEntries)
{
NS_ENSURE_ARG(aMaxEntries);
*aMaxEntries = MEM_CACHE_MAX_ENTRIES;
return NS_OK;
}
static NS_METHOD
HashEntryConverter(nsHashKey *aKey, void *aValue,
void *unused, nsISupports **retval)
{
nsMemCacheRecord *record;
nsOpaqueKey *opaqueKey;
record = (nsMemCacheRecord*)aValue;
opaqueKey = (nsOpaqueKey*)aKey;
// Hash table keys that index cache entries by their record ID
// shouldn't be enumerated.
if ((opaqueKey->GetKeyLength() == sizeof(PRInt32))) {
#ifdef DEBUG
PRInt32 recordID;
record->GetRecordID(&recordID);
NS_ASSERTION(*((PRInt32*)opaqueKey->GetKey()) == recordID,
"Key has incorrect key length");
#endif
return NS_ERROR_FAILURE;
}
NS_IF_ADDREF(record);
*retval = NS_STATIC_CAST(nsISupports*, record);
return NS_OK;
}
NS_IMETHODIMP
nsMemCache::NewCacheEntryIterator(nsISimpleEnumerator* *aIterator)
{
nsCOMPtr<nsIEnumerator> iterator;
NS_ENSURE_ARG(aIterator);
NS_NewHashtableEnumerator(mHashTable, HashEntryConverter,
mHashTable, getter_AddRefs(iterator));
return NS_NewAdapterEnumerator(aIterator, iterator);
}
NS_IMETHODIMP
nsMemCache::GetNextCache(nsINetDataCache* *aNextCache)
{
NS_ENSURE_ARG(aNextCache);
*aNextCache = mNextCache;
NS_ADDREF(*aNextCache);
return NS_OK;
}
NS_IMETHODIMP
nsMemCache::SetNextCache(nsINetDataCache* aNextCache)
{
mNextCache = aNextCache;
return NS_OK;
}
NS_IMETHODIMP
nsMemCache::GetStorageInUse(PRUint32 *aStorageInUse)
{
NS_ENSURE_ARG(aStorageInUse);
// Convert from bytes to KB
*aStorageInUse = (mOccupancy >> 10);
return NS_OK;
}
NS_IMETHODIMP
nsMemCache::RemoveAll(void)
{
PRBool failed;
nsCOMPtr<nsISimpleEnumerator> iterator;
nsCOMPtr<nsISupports> recordSupports;
nsCOMPtr<nsINetDataCacheRecord> record;
nsresult rv;
failed = PR_FALSE;
rv = NewCacheEntryIterator(getter_AddRefs(iterator));
if (NS_FAILED(rv))
return rv;
PRBool notDone;
while (1) {
rv = iterator->HasMoreElements(&notDone);
if (NS_FAILED(rv)) return rv;
if (!notDone)
break;
iterator->GetNext(getter_AddRefs(recordSupports));
record = do_QueryInterface(recordSupports);
recordSupports = 0;
PRUint32 bytesUsed;
record->GetStoredContentLength(&bytesUsed);
rv = record->Delete();
if (NS_FAILED(rv)) {
failed = PR_TRUE;
continue;
}
mOccupancy -= bytesUsed;
}
if (failed)
return NS_ERROR_FAILURE;
return NS_OK;
}

View File

@@ -0,0 +1,83 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator client code, released
* March 31, 1998.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
*/
/**
* nsMemCache is the implementation of an in-memory network-data
* cache, used to cache the responses to network retrieval commands.
* Each cache entry may contain both content, e.g. GIF image data, and
* associated metadata, e.g. HTTP headers. Each entry is indexed by
* two different keys: a record id number and an opaque key, which is
* created by the cache manager by combining the URI with a "secondary
* key", e.g. HTTP post data.
*/
#ifndef _nsMemCache_h_
#define _nsMemCache_h_
#include "nsINetDataCache.h"
// Maximum number of URIs that may be resident in the cache
#define MEM_CACHE_MAX_ENTRIES 1000
#define MEM_CACHE_SEGMENT_SIZE (1 << 12)
#define MEM_CACHE_MAX_ENTRY_SIZE (1 << 20)
class nsHashtable;
class nsMemCacheRecord;
class nsMemCache : public nsINetDataCache
{
public:
nsMemCache();
virtual ~nsMemCache();
nsresult Init();
// nsISupports methods
NS_DECL_ISUPPORTS
// nsINetDataCache methods
NS_DECL_NSINETDATACACHE
// Factory
static NS_METHOD nsMemCacheConstructor(nsISupports *aOuter, REFNSIID aIID,
void **aResult);
protected:
PRUint32 mNumEntries;
PRUint32 mOccupancy; // Memory used, in bytes
PRBool mEnabled; // If false, bypass mem cache
nsINetDataCache* mNextCache;
// Mapping from either opaque key or record ID to nsMemCacheRecord
nsHashtable* mHashTable;
// Used to assign record ID's
static PRInt32 gRecordSerialNumber;
NS_METHOD Delete(nsMemCacheRecord* aRecord);
friend class nsMemCacheRecord;
friend class nsMemCacheChannel;
};
#endif // _nsMemCache_h_

View File

@@ -0,0 +1,36 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator client code, released
* March 31, 1998.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
*/
// XPCOM Class ID for the network data in-memory cache
#ifndef nsMEMCACHECID_h__
#define nsMEMCACHECID_h__
// {e4710560-7de2-11d3-90cb-0040056a906e}
#define NS_MEM_CACHE_FACTORY_CID \
{ \
0xe4710560, \
0x7de2, \
0x11d3, \
{0x90, 0xcb, 0x00, 0x40, 0x05, 0x6a, 0x90, 0x6e} \
}
#endif // nsMEMCACHECID_h__

View File

@@ -0,0 +1,462 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator client code, released
* March 31, 1998.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
*/
#include "nsMemCache.h"
#include "nsMemCacheChannel.h"
#include "nsIStreamListener.h"
#include "nsIChannel.h"
#include "nsIStorageStream.h"
#include "nsIOutputStream.h"
#include "nsIServiceManager.h"
#include "nsIEventQueueService.h"
#include "nsNetUtil.h"
#include "nsILoadGroup.h"
static NS_DEFINE_CID(kIOServiceCID, NS_IOSERVICE_CID);
static NS_DEFINE_CID(kEventQueueService, NS_EVENTQUEUESERVICE_CID);
NS_IMPL_ISUPPORTS(nsMemCacheChannel, NS_GET_IID(nsIChannel))
void
nsMemCacheChannel::NotifyStorageInUse(PRInt32 aBytesUsed)
{
mRecord->mCache->mOccupancy += aBytesUsed;
}
/**
* This class acts as an adaptor around a synchronous input stream to add async
* read capabilities. It adds methods for initiating, suspending, resuming and
* cancelling async reads.
*/
class AsyncReadStreamAdaptor : public nsIInputStream {
public:
AsyncReadStreamAdaptor(nsMemCacheChannel* aChannel, nsIInputStream *aSyncStream):
mSyncStream(aSyncStream), mDataAvailCursor(0),
mRemaining(0), mAvailable(0), mChannel(aChannel), mAborted(PR_FALSE), mSuspended(PR_FALSE)
{
NS_INIT_REFCNT();
NS_ADDREF(mChannel);
}
virtual ~AsyncReadStreamAdaptor() {
mChannel->mAsyncReadStream = 0;
NS_RELEASE(mChannel);
}
NS_DECL_ISUPPORTS
nsresult
IsPending(PRBool* aIsPending) {
*aIsPending = (mRemaining != 0) && !mAborted;
return NS_OK;
}
nsresult
Cancel(void) {
mAborted = PR_TRUE;
return mStreamListener->OnStopRequest(mChannel, mContext, NS_BINDING_ABORTED, nsnull);
}
nsresult
Suspend(void) { mSuspended = PR_TRUE; return NS_OK; }
nsresult
Resume(void) {
if (!mSuspended)
return NS_ERROR_FAILURE;
mSuspended = PR_FALSE;
return NextListenerEvent();
}
NS_IMETHOD
Available(PRUint32 *aNumBytes) { return mAvailable; }
NS_IMETHOD
Read(char* aBuf, PRUint32 aCount, PRUint32 *aBytesRead) {
if (mAborted)
return NS_ERROR_ABORT;
*aBytesRead = 0;
aCount = PR_MIN(aCount, mAvailable);
nsresult rv = mSyncStream->Read(aBuf, aCount, aBytesRead);
mAvailable -= *aBytesRead;
if (NS_FAILED(rv) && (rv != NS_BASE_STREAM_WOULD_BLOCK)) {
Fail();
return rv;
}
if (!mSuspended && !mAvailable) {
rv = NextListenerEvent();
if (NS_FAILED(rv)) {
Fail();
return rv;
}
}
return NS_OK;
}
NS_IMETHOD
Close() {
nsresult rv = mSyncStream->Close();
mSyncStream = 0;
mContext = 0;
mStreamListener = 0;
return rv;
}
nsresult
AsyncRead(PRUint32 aStartPosition, PRInt32 aReadCount,
nsISupports* aContext, nsIStreamListener* aListener) {
nsresult rv;
nsIEventQueue *eventQ;
mContext = aContext;
mStreamListener = aListener;
mRemaining = aReadCount;
NS_WITH_SERVICE(nsIIOService, serv, kIOServiceCID, &rv);
if (NS_FAILED(rv)) return rv;
NS_WITH_SERVICE(nsIEventQueueService, eventQService, kEventQueueService, &rv);
if (NS_FAILED(rv)) return rv;
rv = eventQService->GetThreadEventQueue(PR_CurrentThread(), &eventQ);
if (NS_FAILED(rv)) return rv;
rv = NS_NewAsyncStreamListener(aListener, eventQ,
getter_AddRefs(mStreamListener));
NS_RELEASE(eventQ);
if (NS_FAILED(rv)) return rv;
rv = mStreamListener->OnStartRequest(mChannel, aContext);
if (NS_FAILED(rv)) return rv;
return NextListenerEvent();
}
protected:
nsresult
Fail(void) {
mAborted = PR_TRUE;
return mStreamListener->OnStopRequest(mChannel, mContext, NS_BINDING_FAILED, nsnull);
}
nsresult
NextListenerEvent() {
PRUint32 available;
nsresult rv = mSyncStream->Available(&available);
if (NS_FAILED(rv)) return rv;
available -= mAvailable;
available = PR_MIN(available, mRemaining);
if (available) {
PRUint32 size = PR_MIN(available, MEM_CACHE_SEGMENT_SIZE);
rv = mStreamListener->OnDataAvailable(mChannel, mContext, this,
mDataAvailCursor, size);
mDataAvailCursor += size;
mRemaining -= size;
mAvailable += size;
return rv;
} else {
rv = mStreamListener->OnStopRequest(mChannel, mContext, NS_OK, nsnull);
AsyncReadStreamAdaptor* thisAlias = this;
NS_RELEASE(thisAlias);
return rv;
}
}
private:
nsCOMPtr<nsISupports> mContext; // Opaque context passed to AsyncRead()
nsCOMPtr<nsIStreamListener> mStreamListener; // Stream listener that has been proxied
nsCOMPtr<nsIInputStream> mSyncStream; // Underlying synchronous stream that is
// being converted to an async stream
PRUint32 mDataAvailCursor;
PRUint32 mRemaining; // Size of AsyncRead request less bytes for
// consumer OnDataAvailable's that were fired
PRUint32 mAvailable; // Number of bytes for which OnDataAvailable fired
nsMemCacheChannel* mChannel; // Associated memory cache channel, strong link
// but can not use nsCOMPtr
PRBool mAborted; // Abort() has been called
PRBool mSuspended; // Suspend() has been called
};
NS_IMPL_ISUPPORTS(AsyncReadStreamAdaptor, NS_GET_IID(nsIInputStream))
// The only purpose of this output stream wrapper is to adjust the cache's
// overall occupancy as new data flows into the cache entry.
class MemCacheWriteStreamWrapper : public nsIOutputStream {
public:
MemCacheWriteStreamWrapper(nsMemCacheChannel* aChannel, nsIOutputStream *aBaseStream):
mBaseStream(aBaseStream), mChannel(aChannel)
{
NS_INIT_REFCNT();
NS_ADDREF(mChannel);
}
virtual ~MemCacheWriteStreamWrapper() { NS_RELEASE(mChannel); };
static nsresult
Create(nsMemCacheChannel* aChannel, nsIOutputStream *aBaseStream, nsIOutputStream* *aWrapper) {
MemCacheWriteStreamWrapper *wrapper =
new MemCacheWriteStreamWrapper(aChannel, aBaseStream);
if (!wrapper) return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(wrapper);
*aWrapper = wrapper;
return NS_OK;
}
NS_DECL_ISUPPORTS
NS_IMETHOD
Write(const char *aBuffer, PRUint32 aCount, PRUint32 *aNumWritten) {
*aNumWritten = 0;
nsresult rv = mBaseStream->Write(aBuffer, aCount, aNumWritten);
mChannel->NotifyStorageInUse(*aNumWritten);
return rv;
}
NS_IMETHOD
Flush() { return mBaseStream->Flush(); }
NS_IMETHOD
Close() { return mBaseStream->Close(); }
private:
nsCOMPtr<nsIOutputStream> mBaseStream;
nsMemCacheChannel* mChannel;
};
NS_IMPL_ISUPPORTS(MemCacheWriteStreamWrapper, NS_GET_IID(nsIOutputStream))
nsMemCacheChannel::nsMemCacheChannel(nsMemCacheRecord *aRecord, nsILoadGroup *aLoadGroup)
: mRecord(aRecord)
{
NS_INIT_REFCNT();
mRecord->mNumChannels++;
}
nsMemCacheChannel::~nsMemCacheChannel()
{
mRecord->mNumChannels--;
}
NS_IMETHODIMP
nsMemCacheChannel::IsPending(PRBool* aIsPending)
{
*aIsPending = PR_FALSE;
if (!mAsyncReadStream)
return NS_OK;
return mAsyncReadStream->IsPending(aIsPending);
}
NS_IMETHODIMP
nsMemCacheChannel::Cancel(void)
{
if (!mAsyncReadStream)
return NS_ERROR_FAILURE;
return mAsyncReadStream->Cancel();
}
NS_IMETHODIMP
nsMemCacheChannel::Suspend(void)
{
if (!mAsyncReadStream)
return NS_ERROR_FAILURE;
return mAsyncReadStream->Suspend();
}
NS_IMETHODIMP
nsMemCacheChannel::Resume(void)
{
if (!mAsyncReadStream)
return NS_ERROR_FAILURE;
return mAsyncReadStream->Resume();
}
NS_IMETHODIMP
nsMemCacheChannel::GetOriginalURI(nsIURI * *aURI)
{
// Not required
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsMemCacheChannel::GetURI(nsIURI * *aURI)
{
// Not required to be implemented, since it is implemented by cache manager
NS_ASSERTION(0, "nsMemCacheChannel method unexpectedly called");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsMemCacheChannel::OpenInputStream(PRUint32 aStartPosition, PRInt32 aReadCount,
nsIInputStream* *aResult)
{
nsresult rv;
NS_ENSURE_ARG(aResult);
if (mInputStream)
return NS_ERROR_NOT_AVAILABLE;
rv = mRecord->mStorageStream->NewInputStream(aStartPosition, getter_AddRefs(mInputStream));
*aResult = mInputStream;
NS_ADDREF(*aResult);
return rv;
}
NS_IMETHODIMP
nsMemCacheChannel::OpenOutputStream(PRUint32 startPosition, nsIOutputStream* *aResult)
{
nsresult rv;
NS_ENSURE_ARG(aResult);
nsCOMPtr<nsIOutputStream> outputStream;
PRUint32 oldLength;
mRecord->mStorageStream->GetLength(&oldLength);
rv = mRecord->mStorageStream->GetOutputStream(startPosition, getter_AddRefs(outputStream));
if (NS_FAILED(rv)) return rv;
if (startPosition < oldLength)
NotifyStorageInUse(startPosition - oldLength);
return MemCacheWriteStreamWrapper::Create(this, outputStream, aResult);
}
NS_IMETHODIMP
nsMemCacheChannel::AsyncOpen(nsIStreamObserver *observer, nsISupports *ctxt)
{
// Not required
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsMemCacheChannel::AsyncRead(PRUint32 aStartPosition, PRInt32 aReadCount,
nsISupports *aContext, nsIStreamListener *aListener)
{
nsCOMPtr<nsIInputStream> inputStream;
nsresult rv = OpenInputStream(aStartPosition, aReadCount, getter_AddRefs(inputStream));
if (NS_FAILED(rv)) return rv;
AsyncReadStreamAdaptor *asyncReadStreamAdaptor;
asyncReadStreamAdaptor = new AsyncReadStreamAdaptor(this, inputStream);
if (!asyncReadStreamAdaptor)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(asyncReadStreamAdaptor);
mAsyncReadStream = asyncReadStreamAdaptor;
rv = asyncReadStreamAdaptor->AsyncRead(aStartPosition, aReadCount, aContext, aListener);
if (NS_FAILED(rv))
delete asyncReadStreamAdaptor;
return rv;
}
NS_IMETHODIMP
nsMemCacheChannel::AsyncWrite(nsIInputStream *fromStream, PRUint32 startPosition,
PRInt32 writeCount, nsISupports *ctxt,
nsIStreamObserver *observer)
{
// Not required to be implemented
NS_ASSERTION(0, "nsMemCacheChannel method unexpectedly called");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsMemCacheChannel::GetLoadAttributes(nsLoadFlags *aLoadAttributes)
{
// Not required to be implemented, since it is implemented by cache manager
NS_ASSERTION(0, "nsMemCacheChannel method unexpectedly called");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsMemCacheChannel::SetLoadAttributes(nsLoadFlags aLoadAttributes)
{
// Not required to be implemented, since it is implemented by cache manager
NS_ASSERTION(0, "nsMemCacheChannel method unexpectedly called");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsMemCacheChannel::GetContentType(char* *aContentType)
{
// Not required to be implemented, since it is implemented by cache manager
NS_ASSERTION(0, "nsMemCacheChannel method unexpectedly called");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsMemCacheChannel::GetContentLength(PRInt32 *aContentLength)
{
// Not required to be implemented, since it is implemented by cache manager
NS_ASSERTION(0, "nsMemCacheChannel method unexpectedly called");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsMemCacheChannel::GetOwner(nsISupports* *aOwner)
{
*aOwner = mOwner.get();
NS_IF_ADDREF(*aOwner);
return NS_OK;
}
NS_IMETHODIMP
nsMemCacheChannel::SetOwner(nsISupports* aOwner)
{
// Not required to be implemented, since it is implemented by cache manager
mOwner = aOwner;
return NS_OK;
}
NS_IMETHODIMP
nsMemCacheChannel::GetLoadGroup(nsILoadGroup* *aLoadGroup)
{
// Not required to be implemented, since it is implemented by cache manager
NS_ASSERTION(0, "nsMemCacheChannel method unexpectedly called");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsMemCacheChannel::SetLoadGroup(nsILoadGroup* aLoadGroup)
{
// Not required to be implemented, since it is implemented by cache manager
NS_ASSERTION(0, "nsMemCacheChannel method unexpectedly called");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsMemCacheChannel::GetNotificationCallbacks(nsIInterfaceRequestor* *aNotificationCallbacks)
{
// Not required to be implemented, since it is implemented by cache manager
NS_ASSERTION(0, "nsMemCacheChannel method unexpectedly called");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsMemCacheChannel::SetNotificationCallbacks(nsIInterfaceRequestor* aNotificationCallbacks)
{
// Not required to be implemented, since it is implemented by cache manager
NS_ASSERTION(0, "nsMemCacheChannel method unexpectedly called");
return NS_ERROR_NOT_IMPLEMENTED;
}

View File

@@ -0,0 +1,61 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator client code, released
* March 31, 1998.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
*/
#ifndef _nsMemCacheChannel_h_
#define _nsMemCacheChannel_h_
#include "nsMemCacheRecord.h"
#include "nsIChannel.h"
#include "nsIInputStream.h"
#include "nsCOMPtr.h"
class AsyncReadStreamAdaptor;
class nsMemCacheChannel : public nsIChannel
{
public:
// Constructors and Destructor
nsMemCacheChannel(nsMemCacheRecord *aRecord, nsILoadGroup *aLoadGroup);
virtual ~nsMemCacheChannel();
// Declare nsISupports methods
NS_DECL_ISUPPORTS
// Declare nsIRequest methods
NS_DECL_NSIREQUEST
// Declare nsIChannel methods
NS_DECL_NSICHANNEL
protected:
void NotifyStorageInUse(PRInt32 aBytesUsed);
nsCOMPtr<nsMemCacheRecord> mRecord;
nsCOMPtr<nsIInputStream> mInputStream;
nsCOMPtr<nsISupports> mOwner;
AsyncReadStreamAdaptor* mAsyncReadStream; // non-owning pointer
friend class MemCacheWriteStreamWrapper;
friend class AsyncReadStreamAdaptor;
};
#endif // _nsMemCacheChannel_h_

View File

@@ -0,0 +1,164 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator client code, released
* March 31, 1998.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
*/
#include "nsMemCache.h"
#include "nsMemCacheRecord.h"
#include "nsMemCacheChannel.h"
#include "nsIAllocator.h"
#include "nsStorageStream.h"
static NS_DEFINE_IID(kINetDataCacheRecord, NS_INETDATACACHERECORD_IID);
nsMemCacheRecord::nsMemCacheRecord()
: mKey(0), mKeyLength(0), mMetaData(0), mMetaDataLength(0), mNumChannels(0)
{
NS_INIT_REFCNT();
}
nsMemCacheRecord::~nsMemCacheRecord()
{
if (mMetaData)
delete[] mMetaData;
if (mKey)
delete[] mKey;
}
NS_IMPL_ISUPPORTS(nsMemCacheRecord, NS_GET_IID(nsINetDataCacheRecord))
NS_IMETHODIMP
nsMemCacheRecord::GetKey(PRUint32 *aLength, char **aResult)
{
NS_ENSURE_ARG(aResult);
*aResult = (char *)nsAllocator::Alloc(mKeyLength);
if (!*aResult)
return NS_ERROR_OUT_OF_MEMORY;
memcpy(*aResult, mKey, mKeyLength);
*aLength = mKeyLength;
return NS_OK;
}
nsresult
nsMemCacheRecord::Init(const char *aKey, PRUint32 aKeyLength,
PRUint32 aRecordID, nsMemCache *aCache)
{
nsresult rv;
NS_ASSERTION(!mKey, "Memory cache record key set multiple times");
rv = NS_NewStorageStream(MEM_CACHE_SEGMENT_SIZE, MEM_CACHE_MAX_ENTRY_SIZE,
getter_AddRefs(mStorageStream));
if (NS_FAILED(rv)) return rv;
mKey = new char[aKeyLength];
if (!mKey)
return NS_ERROR_OUT_OF_MEMORY;
memcpy(mKey, aKey, aKeyLength);
mKeyLength = aKeyLength;
mRecordID = aRecordID;
mCache = aCache;
return NS_OK;
}
NS_IMETHODIMP
nsMemCacheRecord::GetRecordID(PRInt32 *aRecordID)
{
NS_ENSURE_ARG(aRecordID);
*aRecordID = mRecordID;
return NS_OK;
}
NS_IMETHODIMP
nsMemCacheRecord::GetMetaData(PRUint32 *aLength, char **aResult)
{
NS_ENSURE_ARG(aResult);
*aResult = 0;
if (mMetaDataLength) {
*aResult = (char*)nsAllocator::Alloc(mMetaDataLength);
if (!*aResult)
return NS_ERROR_OUT_OF_MEMORY;
memcpy(*aResult, mMetaData, mMetaDataLength);
}
*aLength = mMetaDataLength;
return NS_OK;
}
NS_IMETHODIMP
nsMemCacheRecord::SetMetaData(PRUint32 aLength, const char *aData)
{
if (mMetaData)
delete[] mMetaData;
mMetaData = new char[aLength];
if (!mMetaData)
return NS_ERROR_OUT_OF_MEMORY;
memcpy(mMetaData, aData, aLength);
mMetaDataLength = aLength;
return NS_OK;
}
NS_IMETHODIMP
nsMemCacheRecord::GetStoredContentLength(PRUint32 *aStoredContentLength)
{
NS_ENSURE_ARG(aStoredContentLength);
return mStorageStream->GetLength(aStoredContentLength);
}
NS_IMETHODIMP
nsMemCacheRecord::SetStoredContentLength(PRUint32 aStoredContentLength)
{
PRUint32 before, after;
mStorageStream->GetLength(&before);
nsresult rv = mStorageStream->SetLength(aStoredContentLength);
if (NS_FAILED(rv)) return rv;
mStorageStream->GetLength(&after);
mCache->mOccupancy -= (before - after);
return NS_OK;
}
NS_IMETHODIMP
nsMemCacheRecord::Delete(void)
{
if (mNumChannels)
return NS_ERROR_NOT_AVAILABLE;
return mCache->Delete(this);
}
NS_IMETHODIMP
nsMemCacheRecord::GetFilename(nsIFileSpec* *aFilename)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsMemCacheRecord::NewChannel(nsILoadGroup *aLoadGroup, nsIChannel* *aResult)
{
NS_ENSURE_ARG(aResult);
nsMemCacheChannel* channel = new nsMemCacheChannel(this, aLoadGroup);
if (!channel)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(channel);
*aResult = NS_STATIC_CAST(nsIChannel*, channel);
return NS_OK;
}

View File

@@ -0,0 +1,65 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator client code, released
* March 31, 1998.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
*/
#ifndef _nsMemCacheRecord_h_
#define _nsMemCacheRecord_h_
#include "nsINetDataCacheRecord.h"
#include "nsIStorageStream.h"
#include "nsCOMPtr.h"
class nsMemCache;
class nsMemCacheRecord : public nsINetDataCacheRecord
{
public:
// Declare interface methods
NS_DECL_ISUPPORTS
NS_DECL_NSINETDATACACHERECORD
protected:
// Constructors and Destructor
nsMemCacheRecord();
virtual ~nsMemCacheRecord();
nsresult Init(const char *aKey, PRUint32 aKeyLength,
PRUint32 aRecordID, nsMemCache *aCache);
char* mKey; // opaque database key for this record
PRUint32 mKeyLength; // length, in bytes, of mKey
PRInt32 mRecordID; // An alternate key for this record
char* mMetaData; // opaque URI metadata
PRUint32 mMetaDataLength; // length, in bytes, of mMetaData
nsMemCache* mCache; // weak pointer to the cache database
// that this record inhabits
nsCOMPtr<nsIStorageStream> mStorageStream;
PRUint32 mNumChannels; // Count un-Release'ed nsIChannels
friend class nsMemCache;
friend class nsMemCacheChannel;
};
#endif // _nsMemCacheRecord_h_

55
mozilla/netwerk/cache/mgr/Makefile.in vendored Normal file
View File

@@ -0,0 +1,55 @@
#
# The contents of this file are subject to the Netscape Public
# License Version 1.1 (the "License"); you may not use this file
# except in compliance with the License. You may obtain a copy of
# the License at http://www.mozilla.org/NPL/
#
# Software distributed under the License is distributed on an "AS
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
# implied. See the License for the specific language governing
# rights and limitations under the License.
#
# The Original Code is mozilla.org code.
#
# The Initial Developer of the Original Code is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s):
#
DEPTH = ../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
MODULE = nkcache
LIBRARY_NAME = nkcachemgr_s
REQUIRES = nspr
EXPORTS = \
nsCacheManager.h \
$(NULL)
CPPSRCS = \
nsCacheManager.cpp \
nsCachedNetData.cpp \
nsReplacementPolicy.cpp \
nsCacheEntryChannel.cpp \
$(NULL)
LOCAL_INCLUDES = -I$(srcdir)/../public -I$(srcdir)/../include
EXTRA_LIBS = $(NSPR_LIBS)
# we don't want the shared lib, but we want to force the creation of a
# static lib.
override NO_SHARED_LIB=1
override NO_STATIC_LIB=
include $(topsrcdir)/config/rules.mk

45
mozilla/netwerk/cache/mgr/Makefile.win vendored Executable file
View File

@@ -0,0 +1,45 @@
#!gmake
#
# The contents of this file are subject to the Netscape Public
# License Version 1.1 (the "License"); you may not use this file
# except in compliance with the License. You may obtain a copy of
# the License at http://www.mozilla.org/NPL/
#
# Software distributed under the License is distributed on an "AS
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
# implied. See the License for the specific language governing
# rights and limitations under the License.
#
# The Original Code is mozilla.org code.
#
# The Initial Developer of the Original Code is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s):
DEPTH=..\..\..
include <$(DEPTH)/config/config.mak>
MODULE = nkcache
LIBRARY_NAME = nkcachemgr_s
CPP_OBJS = \
.\$(OBJDIR)\nsCacheManager.obj \
.\$(OBJDIR)\nsCachedNetData.obj \
.\$(OBJDIR)\nsReplacementPolicy.obj \
.\$(OBJDIR)\nsCacheEntryChannel.obj \
$(NULL)
include <$(DEPTH)\config\rules.mak>
install:: $(LIBRARY)
$(MAKE_INSTALL) $(LIBRARY) $(DIST)\lib
clobber::
rm -rf $(OBJDIR)
rm -f $(DIST)\lib\$(LIBRARY_NAME).lib

View File

@@ -0,0 +1,261 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator client code, released
* March 31, 1998.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Scott Furman, fur@netscape.com
*/
#include "nsCacheManager.h"
#include "nsCacheEntryChannel.h"
#include "nsIOutputStream.h"
#include "nsIIOService.h"
#include "nsIServiceManager.h"
#include "nsIStreamListener.h"
nsCacheEntryChannel::nsCacheEntryChannel(nsCachedNetData* aCacheEntry, nsIChannel* aChannel,
nsILoadGroup* aLoadGroup):
nsChannelProxy(aChannel), mCacheEntry(aCacheEntry), mLoadGroup(aLoadGroup), mLoadAttributes(0)
{
NS_ASSERTION(aCacheEntry->mChannelCount < 0xFF, "Overflowed channel counter");
mCacheEntry->mChannelCount++;
NS_INIT_REFCNT();
}
nsCacheEntryChannel::~nsCacheEntryChannel()
{
mCacheEntry->mChannelCount--;
}
NS_IMPL_ISUPPORTS3(nsCacheEntryChannel, nsISupports, nsIChannel, nsIRequest)
// A proxy for nsIOutputStream
class CacheOutputStream : public nsIOutputStream {
public:
CacheOutputStream(nsIOutputStream *aOutputStream, nsCachedNetData *aCacheEntry):
mOutputStream(aOutputStream), mCacheEntry(aCacheEntry), mStartTime(PR_Now())
{ NS_INIT_REFCNT(); }
virtual ~CacheOutputStream() {
mCacheEntry->NoteDownloadTime(mStartTime, PR_Now());
mCacheEntry->ClearFlag(nsCachedNetData::UPDATE_IN_PROGRESS);
}
NS_DECL_ISUPPORTS
NS_IMETHOD Close() {
return mOutputStream->Close();
}
NS_IMETHOD Flush() { return mOutputStream->Flush(); }
NS_IMETHOD
Write(const char *aBuf, PRUint32 aCount, PRUint32 *aActualBytes) {
nsresult rv;
*aActualBytes = 0;
rv = mOutputStream->Write(aBuf, aCount, aActualBytes);
mCacheEntry->mLogicalLength += *aActualBytes;
if (NS_FAILED(rv)) return rv;
nsCacheManager::LimitCacheSize();
return rv;
}
protected:
nsCOMPtr<nsIOutputStream> mOutputStream;
nsCOMPtr<nsCachedNetData> mCacheEntry;
// Time at which stream was opened
PRTime mStartTime;
};
NS_IMPL_ISUPPORTS(CacheOutputStream, NS_GET_IID(nsIOutputStream))
NS_IMETHODIMP
nsCacheEntryChannel::OpenOutputStream(PRUint32 aStartPosition, nsIOutputStream* *aOutputStream)
{
nsresult rv;
nsCOMPtr<nsIOutputStream> baseOutputStream;
rv = mChannel->OpenOutputStream(aStartPosition, getter_AddRefs(baseOutputStream));
if (NS_FAILED(rv)) return rv;
mCacheEntry->NoteUpdate();
mCacheEntry->NoteAccess();
mCacheEntry->mLogicalLength = aStartPosition;
*aOutputStream = new CacheOutputStream(baseOutputStream, mCacheEntry);
if (!*aOutputStream)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(*aOutputStream);
return NS_OK;
}
NS_IMETHODIMP
nsCacheEntryChannel::OpenInputStream(PRUint32 aStartPosition, PRInt32 aReadCount,
nsIInputStream* *aInputStream)
{
mCacheEntry->NoteAccess();
return mChannel->OpenInputStream(aStartPosition, aReadCount, aInputStream);
}
class CacheManagerStreamListener: public nsIStreamListener {
public:
CacheManagerStreamListener(nsIStreamListener *aListener,
nsILoadGroup *aLoadGroup, nsIChannel *aChannel):
mListener(aListener), mLoadGroup(aLoadGroup), mChannel(aChannel)
{ NS_INIT_REFCNT(); }
virtual ~CacheManagerStreamListener() {}
private:
NS_DECL_ISUPPORTS
NS_IMETHOD
OnDataAvailable(nsIChannel *channel, nsISupports *aContext,
nsIInputStream *inStr, PRUint32 sourceOffset, PRUint32 count) {
return mListener->OnDataAvailable(mChannel, aContext, inStr, sourceOffset, count);
}
NS_IMETHOD
OnStartRequest(nsIChannel *channel, nsISupports *aContext) {
if (mLoadGroup)
mLoadGroup->AddChannel(mChannel, aContext);
return mListener->OnStartRequest(mChannel, aContext);
}
NS_IMETHOD
OnStopRequest(nsIChannel *channel, nsISupports *aContext,
nsresult status, const PRUnichar *errorMsg) {
nsresult rv;
rv = mListener->OnStopRequest(mChannel, aContext, status, errorMsg);
if (mLoadGroup)
mLoadGroup->RemoveChannel(mChannel, aContext, status, errorMsg);
return rv;
}
private:
nsCOMPtr<nsIStreamListener> mListener;
nsCOMPtr<nsILoadGroup> mLoadGroup;
nsCOMPtr<nsIChannel> mChannel;
};
NS_IMPL_ISUPPORTS2(CacheManagerStreamListener, nsIStreamListener, nsIStreamObserver)
NS_IMETHODIMP
nsCacheEntryChannel::AsyncRead(PRUint32 aStartPosition, PRInt32 aReadCount,
nsISupports *aContext, nsIStreamListener *aListener)
{
nsresult rv;
mCacheEntry->NoteAccess();
nsCOMPtr<nsIStreamListener> headListener;
if (mLoadGroup) {
mLoadGroup->GetDefaultLoadAttributes(&mLoadAttributes);
// Create a load group "proxy" listener...
nsCOMPtr<nsILoadGroupListenerFactory> factory;
rv = mLoadGroup->GetGroupListenerFactory(getter_AddRefs(factory));
if (NS_SUCCEEDED(rv) && factory) {
rv = factory->CreateLoadGroupListener(aListener,
getter_AddRefs(headListener));
if (NS_FAILED(rv)) return rv;
}
} else {
headListener = aListener;
}
CacheManagerStreamListener* cacheManagerStreamListener;
nsIChannel *channelForListener;
channelForListener = mProxyChannel ? mProxyChannel.get() : NS_STATIC_CAST(nsIChannel*, this);
cacheManagerStreamListener =
new CacheManagerStreamListener(headListener, mLoadGroup, channelForListener);
if (!cacheManagerStreamListener) return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(cacheManagerStreamListener);
rv = mChannel->AsyncRead(aStartPosition, aReadCount, aContext,
cacheManagerStreamListener);
NS_RELEASE(cacheManagerStreamListener);
return rv;
}
// No async writes allowed to the cache yet
NS_IMETHODIMP
nsCacheEntryChannel::AsyncWrite(nsIInputStream *aFromStream, PRUint32 aStartPosition,
PRInt32 aWriteCount, nsISupports *aContext,
nsIStreamObserver *aObserver)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsCacheEntryChannel::GetLoadGroup(nsILoadGroup* *aLoadGroup)
{
*aLoadGroup = mLoadGroup;
return NS_OK;
}
NS_IMETHODIMP
nsCacheEntryChannel::GetLoadAttributes(nsLoadFlags *aLoadAttributes)
{
*aLoadAttributes = mLoadAttributes;
return NS_OK;
}
NS_IMETHODIMP
nsCacheEntryChannel::SetLoadAttributes(nsLoadFlags aLoadAttributes)
{
mLoadAttributes = aLoadAttributes;
return NS_OK;
}
static NS_DEFINE_CID(kIOServiceCID, NS_IOSERVICE_CID);
NS_IMETHODIMP
nsCacheEntryChannel::GetURI(nsIURI * *aURI)
{
char* spec;
nsresult rv;
rv = mCacheEntry->GetUriSpec(&spec);
if (NS_FAILED(rv)) return rv;
NS_WITH_SERVICE(nsIIOService, serv, kIOServiceCID, &rv);
if (NS_FAILED(rv)) return rv;
rv = serv->NewURI(spec, 0, aURI);
nsAllocator::Free(spec);
return rv;
}
NS_IMETHODIMP
nsCacheEntryChannel::GetOriginalURI(nsIURI * *aURI)
{
// FIXME - should return original URI passed into NewChannel() ?
return NS_ERROR_NOT_IMPLEMENTED;
}

View File

@@ -0,0 +1,82 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator client code, released
* March 31, 1998.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Scott Furman, fur@netscape.com
*/
#ifndef _nsCacheEntryChannel_h_
#define _nsCacheEntryChannel_h_
#include "nsCOMPtr.h"
#include "nsIChannel.h"
#include "nsCachedNetData.h"
#include "nsILoadGroup.h"
class nsIStreamListener;
// A proxy for an nsIChannel, useful when only a few nsIChannel
// methods must be overridden
class nsChannelProxy : public nsIChannel {
public:
NS_FORWARD_NSICHANNEL(mChannel->)
NS_FORWARD_NSIREQUEST(mChannel->)
protected:
nsChannelProxy(nsIChannel* aChannel):mChannel(aChannel) {};
virtual ~nsChannelProxy() {};
nsCOMPtr<nsIChannel> mChannel;
};
// Override several nsIChannel methods so that they interact with the cache manager
class nsCacheEntryChannel : public nsChannelProxy {
public:
NS_DECL_ISUPPORTS
NS_IMETHOD OpenOutputStream(PRUint32 aStartPosition, nsIOutputStream* *aOutputStream);
NS_IMETHOD OpenInputStream(PRUint32 aStartPosition, PRInt32 aReadCount,
nsIInputStream* *aInputStream);
NS_IMETHOD AsyncRead(PRUint32 aStartPosition, PRInt32 aReadCount,
nsISupports *aContext, nsIStreamListener *aListener);
NS_IMETHOD AsyncWrite(nsIInputStream *aFromStream, PRUint32 aStartPosition,
PRInt32 aWriteCount, nsISupports *aContext,
nsIStreamObserver *aObserver);
NS_IMETHOD GetLoadAttributes(nsLoadFlags *aLoadAttributes);
NS_IMETHOD SetLoadAttributes(nsLoadFlags aLoadAttributes);
NS_IMETHOD GetLoadGroup(nsILoadGroup* *aLoadGroup);
NS_IMETHOD GetURI(nsIURI * *aURI);
NS_IMETHOD GetOriginalURI(nsIURI * *aURI);
protected:
nsCacheEntryChannel(nsCachedNetData* aCacheEntry, nsIChannel* aChannel, nsILoadGroup* aLoadGroup);
virtual ~nsCacheEntryChannel();
friend class nsCachedNetData;
private:
nsCOMPtr<nsCachedNetData> mCacheEntry;
nsCOMPtr<nsILoadGroup> mLoadGroup;
nsCOMPtr<nsIChannel> mProxyChannel;
nsLoadFlags mLoadAttributes;
};
#endif // _nsCacheEntryChannel_h_

View File

@@ -0,0 +1,497 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator client code, released
* March 31, 1998.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Scott Furman, fur@netscape.com
*/
#include "nsINetDataCache.h"
#include "nsCacheManager.h"
#include "nsCachedNetData.h"
#include "nsReplacementPolicy.h"
#include "nsString.h"
#include "nsIURI.h"
#include "nsHashtable.h"
#include "nsIComponentManager.h"
#include "nsINetDataDiskCache.h"
// Limit the number of entries in the cache to conserve memory space
// in the nsReplacementPolicy code
#define MAX_MEM_CACHE_ENTRIES 800
#define MAX_DISK_CACHE_ENTRIES 3200
// Cache capacities in MB, overridable via APIs
#define DEFAULT_MEMORY_CACHE_CAPACITY 1024
#define DEFAULT_DISK_CACHE_CAPACITY 10000
#define CACHE_HIGH_WATER_MARK(capacity) ((PRUint32)(0.98 * (capacity)))
#define CACHE_LOW_WATER_MARK(capacity) ((PRUint32)(0.97 * (capacity)))
nsCacheManager* gCacheManager = 0;
NS_IMPL_ISUPPORTS(nsCacheManager, NS_GET_IID(nsINetDataCacheManager))
nsCacheManager::nsCacheManager()
: mActiveCacheRecords(0),
mDiskCacheCapacity(DEFAULT_DISK_CACHE_CAPACITY),
mMemCacheCapacity(DEFAULT_MEMORY_CACHE_CAPACITY)
{
NS_ASSERTION(!gCacheManager, "Multiple cache managers created");
gCacheManager = this;
NS_INIT_REFCNT();
}
nsCacheManager::~nsCacheManager()
{
gCacheManager = 0;
delete mActiveCacheRecords;
delete mMemSpaceManager;
delete mDiskSpaceManager;
}
nsresult
nsCacheManager::Init()
{
nsresult rv;
mActiveCacheRecords = new nsHashtable(64);
if (!mActiveCacheRecords)
return NS_ERROR_OUT_OF_MEMORY;
// Instantiate the memory cache component
rv = nsComponentManager::CreateInstance(NS_NETWORK_MEMORY_CACHE_PROGID,
nsnull,
NS_GET_IID(nsINetDataCache),
getter_AddRefs(mMemCache));
if (NS_FAILED(rv))
return rv;
rv = nsComponentManager::CreateInstance(NS_NETWORK_FLAT_CACHE_PROGID,
nsnull,
NS_GET_IID(nsINetDataCache),
getter_AddRefs(mFlatCache));
if (NS_FAILED(rv)) {
// For now, we don't require a flat cache module to be present
if (rv != NS_ERROR_FACTORY_NOT_REGISTERED)
return rv;
}
#ifdef FILE_CACHE_IS_READY
// Instantiate the file cache component
rv = nsComponentManager::CreateInstance(NS_NETWORK_FILE_CACHE_PROGID,
nsnull,
NS_GET_IID(nsINetDataCache),
getter_AddRefs(mFileCache));
if (NS_FAILED(rv)) {
NS_WARNING("No disk cache present");
}
#endif
// Set up linked list of caches in search order
mCacheSearchChain = mMemCache;
if (mFlatCache) {
mMemCache->SetNextCache(mFlatCache);
mFlatCache->SetNextCache(mFileCache);
} else {
mMemCache->SetNextCache(mFileCache);
}
// TODO - Load any extension caches here
// Initialize replacement policy for memory cache module
mMemSpaceManager = new nsReplacementPolicy;
if (!mMemSpaceManager)
return NS_ERROR_OUT_OF_MEMORY;
rv = mMemSpaceManager->Init(MAX_MEM_CACHE_ENTRIES);
if (NS_FAILED(rv)) return rv;
rv = mMemSpaceManager->AddCache(mMemCache);
// Initialize replacement policy for disk cache modules (file
// cache and flat cache)
mDiskSpaceManager = new nsReplacementPolicy;
if (!mDiskSpaceManager)
return NS_ERROR_OUT_OF_MEMORY;
rv = mDiskSpaceManager->Init(MAX_DISK_CACHE_ENTRIES);
if (NS_FAILED(rv)) return rv;
if (mFileCache) {
rv = mDiskSpaceManager->AddCache(mFileCache);
if (NS_FAILED(rv)) return rv;
}
if (mFlatCache) {
rv = mDiskSpaceManager->AddCache(mFlatCache);
if (NS_FAILED(rv)) return rv;
}
return NS_OK;
}
NS_IMETHODIMP
nsCacheManager::GetCachedNetData(const char *aUriSpec, const char *aSecondaryKey,
PRUint32 aSecondaryKeyLength,
PRUint32 aFlags, nsICachedNetData* *aResult)
{
nsCachedNetData *cachedData;
nsresult rv;
nsINetDataCache *cache;
nsReplacementPolicy *spaceManager;
if (aFlags & CACHE_AS_FILE) {
cache = mFileCache;
spaceManager = mDiskSpaceManager;
// Ensure that cache is initialized
if (mDiskCacheCapacity == (PRUint32)-1)
return NS_ERROR_NOT_AVAILABLE;
} else if ((aFlags & BYPASS_PERSISTENT_CACHE) ||
(!mFileCache && !mFlatCache) || !mDiskCacheCapacity) {
cache = mMemCache;
spaceManager = mMemSpaceManager;
} else {
cache = mFlatCache ? mFlatCache : mFileCache;
spaceManager = mDiskSpaceManager;
}
// Construct the cache key by appending the secondary key to the URI spec
nsCAutoString cacheKey(aUriSpec);
// Insert NUL at end of URI spec
cacheKey += '\0';
if (aSecondaryKey)
cacheKey.Append(aSecondaryKey, aSecondaryKeyLength);
nsStringKey key(cacheKey);
cachedData = (nsCachedNetData*)mActiveCacheRecords->Get(&key);
// There is no existing instance of nsCachedNetData for this URL.
// Make one from the corresponding record in the cache module.
if (cachedData) {
NS_ASSERTION(cache == cachedData->mCache,
"Cannot yet handle simultaneously active requests for the "
"same URL using different caches");
NS_ADDREF(cachedData);
} else {
rv = spaceManager->GetCachedNetData(cacheKey.GetBuffer(), cacheKey.Length(),
cache, &cachedData);
if (NS_FAILED(rv)) return rv;
mActiveCacheRecords->Put(&key, cachedData);
}
*aResult = cachedData;
return NS_OK;
}
// Remove this cache entry from the list of active ones
nsresult
nsCacheManager::NoteDormant(nsCachedNetData* aEntry)
{
nsresult rv;
PRUint32 keyLength;
char* key;
nsCOMPtr<nsINetDataCacheRecord> record;
nsCachedNetData* deletedEntry;
rv = aEntry->GetRecord(getter_AddRefs(record));
if (NS_FAILED(rv)) return rv;
rv = record->GetKey(&keyLength, &key);
if (NS_FAILED(rv)) return rv;
nsStringKey hashTableKey(nsCString(key, keyLength));
deletedEntry = (nsCachedNetData*)gCacheManager->mActiveCacheRecords->Remove(&hashTableKey);
// NS_ASSERTION(deletedEntry == aEntry, "Hash table inconsistency");
return NS_OK;
}
NS_IMETHODIMP
nsCacheManager::Contains(const char *aUriSpec, const char *aSecondaryKey,
PRUint32 aSecondaryKeyLength,
PRUint32 aFlags, PRBool *aResult)
{
nsINetDataCache *cache;
nsReplacementPolicy *spaceManager;
nsCachedNetData *cachedData;
if (aFlags & CACHE_AS_FILE) {
cache = mFileCache;
spaceManager = mDiskSpaceManager;
} else if ((aFlags & BYPASS_PERSISTENT_CACHE) ||
(!mFileCache && !mFlatCache) || !mDiskCacheCapacity) {
cache = mMemCache;
spaceManager = mMemSpaceManager;
} else {
cache = mFlatCache ? mFlatCache : mFileCache;
spaceManager = mDiskSpaceManager;
}
// Construct the cache key by appending the secondary key to the URI spec
nsCAutoString cacheKey(aUriSpec);
// Insert NUL between URI spec and secondary key
cacheKey += '\0';
cacheKey.Append(aSecondaryKey, aSecondaryKeyLength);
// Locate the record using (URI + secondary key)
nsStringKey key(cacheKey);
cachedData = (nsCachedNetData*)mActiveCacheRecords->Get(&key);
if (cachedData && (cache == cachedData->mCache)) {
*aResult = PR_TRUE;
return NS_OK;
} else {
// No active cache entry, see if there is a dormant one
return cache->Contains(cacheKey.GetBuffer(), cacheKey.Length(), aResult);
}
}
NS_IMETHODIMP
nsCacheManager::GetNumEntries(PRUint32 *aNumEntries)
{
nsresult rv;
nsCOMPtr<nsISimpleEnumerator> iterator;
nsCOMPtr<nsISupports> cacheSupports;
nsCOMPtr<nsINetDataCache> cache;
PRUint32 totalEntries = 0;
rv = NewCacheModuleIterator(getter_AddRefs(iterator));
if (NS_FAILED(rv)) return rv;
while (1) {
PRBool notDone;
rv = iterator->HasMoreElements(&notDone);
if (NS_FAILED(rv)) return rv;
if (!notDone)
break;
iterator->GetNext(getter_AddRefs(cacheSupports));
cache = do_QueryInterface(cacheSupports);
PRUint32 numEntries;
rv = cache->GetNumEntries(&numEntries);
if (NS_FAILED(rv)) return rv;
totalEntries += numEntries;
}
*aNumEntries = totalEntries;
return NS_OK;
}
NS_IMETHODIMP
nsCacheManager::NewCacheEntryIterator(nsISimpleEnumerator* *aResult)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
class CacheEnumerator : public nsISimpleEnumerator
{
public:
CacheEnumerator(nsINetDataCache* aFirstCache):mCache(aFirstCache)
{ NS_INIT_REFCNT(); }
virtual ~CacheEnumerator() {};
NS_DECL_ISUPPORTS
NS_IMETHODIMP
HasMoreElements(PRBool* aMoreElements) {
*aMoreElements = (mCache != 0);
return NS_OK;
}
NS_IMETHODIMP
GetNext(nsISupports* *aSupports) {
*aSupports = mCache;
if (!mCache)
return NS_ERROR_FAILURE;
NS_ADDREF(*aSupports);
nsCOMPtr<nsINetDataCache> nextCache;
nsresult rv = mCache->GetNextCache(getter_AddRefs(nextCache));
mCache = nextCache;
return rv;
}
private:
nsCOMPtr<nsINetDataCache> mCache;
};
NS_IMPL_ISUPPORTS(CacheEnumerator, NS_GET_IID(nsISimpleEnumerator))
NS_IMETHODIMP
nsCacheManager::NewCacheModuleIterator(nsISimpleEnumerator* *aResult)
{
*aResult = new CacheEnumerator(mCacheSearchChain);
if (!*aResult)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(*aResult);
return NS_OK;
}
NS_IMETHODIMP
nsCacheManager::RemoveAll(void)
{
nsresult rv, result;
nsCOMPtr<nsISimpleEnumerator> iterator;
nsCOMPtr<nsINetDataCache> cache;
nsCOMPtr<nsISupports> iSupports;
result = NS_OK;
rv = NewCacheModuleIterator(getter_AddRefs(iterator));
if (NS_FAILED(rv)) return rv;
while (1) {
PRBool notDone;
rv = iterator->HasMoreElements(&notDone);
if (NS_FAILED(rv)) return rv;
if (!notDone)
break;
iterator->GetNext(getter_AddRefs(iSupports));
cache = do_QueryInterface(iSupports);
PRUint32 cacheFlags;
rv = cache->GetFlags(&cacheFlags);
if (NS_FAILED(rv)) return rv;
if ((cacheFlags & nsINetDataCache::READ_ONLY) == 0) {
rv = cache->RemoveAll();
if (NS_FAILED(rv))
result = rv;
}
}
return result;
}
nsresult
nsCacheManager::LimitMemCacheSize()
{
nsresult rv;
nsReplacementPolicy* spaceManager;
NS_ASSERTION(gCacheManager, "No cache manager");
spaceManager = gCacheManager->mMemSpaceManager;
PRUint32 occupancy;
rv = spaceManager->GetStorageInUse(&occupancy);
if (NS_FAILED(rv)) return rv;
PRUint32 memCacheCapacity = gCacheManager->mMemCacheCapacity;
if (occupancy > CACHE_HIGH_WATER_MARK(memCacheCapacity))
return spaceManager->Evict(CACHE_LOW_WATER_MARK(memCacheCapacity));
return NS_OK;
}
nsresult
nsCacheManager::LimitDiskCacheSize()
{
nsresult rv;
nsReplacementPolicy* spaceManager;
NS_ASSERTION(gCacheManager, "No cache manager");
spaceManager = gCacheManager->mDiskSpaceManager;
PRUint32 occupancy;
rv = spaceManager->GetStorageInUse(&occupancy);
if (NS_FAILED(rv)) return rv;
PRUint32 diskCacheCapacity = gCacheManager->mDiskCacheCapacity;
if (occupancy > CACHE_HIGH_WATER_MARK(diskCacheCapacity))
return spaceManager->Evict(CACHE_LOW_WATER_MARK(diskCacheCapacity));
return NS_OK;
}
nsresult
nsCacheManager::LimitCacheSize()
{
nsresult rv;
rv = LimitDiskCacheSize();
if (NS_FAILED(rv)) return rv;
rv = LimitMemCacheSize();
if (NS_FAILED(rv)) return rv;
return NS_OK;
}
NS_IMETHODIMP
nsCacheManager::SetMemCacheCapacity(PRUint32 aCapacity)
{
mMemCacheCapacity = aCapacity;
LimitCacheSize();
return NS_OK;
}
NS_IMETHODIMP
nsCacheManager::GetMemCacheCapacity(PRUint32* aCapacity)
{
NS_ENSURE_ARG_POINTER(aCapacity);
*aCapacity = mMemCacheCapacity;
return NS_OK;
}
NS_IMETHODIMP
nsCacheManager::SetDiskCacheCapacity(PRUint32 aCapacity)
{
mDiskCacheCapacity = aCapacity;
LimitCacheSize();
return NS_OK;
}
NS_IMETHODIMP
nsCacheManager::GetDiskCacheCapacity(PRUint32* aCapacity)
{
NS_ENSURE_ARG_POINTER(aCapacity);
*aCapacity = mDiskCacheCapacity;
return NS_OK;
}
NS_IMETHODIMP
nsCacheManager::SetDiskCacheFolder(nsIFileSpec* aFolder)
{
NS_ENSURE_ARG(aFolder);
if (!mFileCache)
return NS_ERROR_NOT_AVAILABLE;
nsCOMPtr<nsINetDataDiskCache> fileCache;
fileCache = do_QueryInterface(mFileCache);
return fileCache->SetDiskCacheFolder(aFolder);
}
NS_IMETHODIMP
nsCacheManager::GetDiskCacheFolder(nsIFileSpec* *aFolder)
{
NS_ENSURE_ARG(aFolder);
if (!mFileCache)
return NS_ERROR_NOT_AVAILABLE;
nsCOMPtr<nsINetDataDiskCache> fileCache;
fileCache = do_QueryInterface(mFileCache);
return fileCache->GetDiskCacheFolder(aFolder);
}

View File

@@ -0,0 +1,100 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator client code, released
* March 31, 1998.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Scott Furman, fur@netscape.com
*/
#ifndef _nsCacheManager_h_
#define _nsCacheManager_h_
// 2030f0b0-9567-11d3-90d3-0040056a906e
#define NS_CACHE_MANAGER_CID \
{ \
0x2030f0b0, \
0x9567, \
0x11d3, \
{0x90, 0xd3, 0x00, 0x40, 0x05, 0x6a, 0x90, 0x6e} \
}
#include "nsINetDataCacheManager.h"
#include "nsINetDataCache.h"
#include "nsCOMPtr.h"
class nsHashtable;
class nsReplacementPolicy;
class nsCachedNetData;
class nsCacheManager : public nsINetDataCacheManager {
public:
nsCacheManager();
virtual ~nsCacheManager();
NS_METHOD Init();
// nsISupports methods
NS_DECL_ISUPPORTS
// nsINetDataCacheManager methods
NS_DECL_NSINETDATACACHEMANAGER
private:
// Mapping from cache key to nsCachedNetData, but only for those cache
// entries with external references, i.e. those referred to outside the
// cache manager
nsHashtable* mActiveCacheRecords;
// Memory cache
nsCOMPtr<nsINetDataCache> mMemCache;
// Flat-file database cache; All content aggregated into single disk file
nsCOMPtr<nsINetDataCache> mFlatCache;
// stream-as-file cache
nsCOMPtr<nsINetDataCache> mFileCache;
// Unified replacement policy for flat-cache and file-cache
nsReplacementPolicy* mDiskSpaceManager;
// Replacement policy for memory cache
nsReplacementPolicy* mMemSpaceManager;
// List of caches in search order
nsINetDataCache* mCacheSearchChain;
// Combined file/flat cache capacity, in KB
PRUint32 mDiskCacheCapacity;
// Memory cache capacity, in KB
PRUint32 mMemCacheCapacity;
protected:
static nsresult NoteDormant(nsCachedNetData* aEntry);
static nsresult LimitCacheSize();
static nsresult LimitMemCacheSize();
static nsresult LimitDiskCacheSize();
friend class nsCachedNetData;
friend class CacheOutputStream;
};
#endif // _nsCacheManager_h_

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,242 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator client code, released
* March 31, 1998.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Scott Furman, fur@netscape.com
*/
#ifndef _nsCachedNetData_h_
#define _nsCachedNetData_h_
#include "nsICachedNetData.h"
#include "nsCOMPtr.h"
#include "nsINetDataCacheRecord.h"
class nsINetDataCache;
class nsIStreamAsFileObserver;
class nsIStreamAsFile;
class nsIArena;
class StreamAsFileObserverClosure;
class CacheMetaData;
// Number of recent access times recorded
#define MAX_K 3
/**
* FIXME - add comment. There are a lot of these data structures resident in
* memory, so be careful about adding members unnecessarily.
*/
class nsCachedNetData : public nsICachedNetData {
public:
NS_DECL_ISUPPORTS
// nsICachedNetData methods
NS_DECL_NSICACHEDNETDATA
NS_METHOD Init(nsINetDataCacheRecord *aRecord, nsINetDataCache *aCache);
protected:
// Bits for mFlags, below
typedef enum {
DIRTY = 1 << 0, // Cache entry data needs to be flushed to database
// ==== Flags that can be set by the protocol handler ====
ALLOW_PARTIAL = 1 << 1, // Protocol handler supports partial fetching
UPDATE_IN_PROGRESS = 1 << 2, // Protocol handler now modifying cache data
// ==== Cache-entry state flags. At most one of these flags can be set ====
TRUNCATED_CONTENT = 1 << 4, // Entry contains valid content, but it has
// been truncated by cache manager
// A previously-used cache entry, which has been purged of all cached
// content and protocol-private data. This cache entry can be refilled
// with new content or it may be retained in this vestigial state
// because the usage statistics it contains will be used by the
// replacement policy if the same URI is ever cached again.
VESTIGIAL = 1 << 5,
// ==== Memory usage status bits. At most one of these flags can be set ====
RECYCLED = 1 << 8, // Previously associated database record has
// been deleted; This cache entry is available
// for recycling.
DORMANT = 1 << 9, // No references to this cache entry, except by
// the cache manager itself
// ==== Setter bits ====
LAST_MODIFIED_KNOWN = 1 <<12, // Protocol handler called SetLastModifiedTime()
EXPIRATION_KNOWN = 1 <<13, // Protocol handler called SetExpirationTime()
STALE_TIME_KNOWN = 1 <<14, // Protocol handler called SetStaleTime()
// ==== Useful flag combinations ====
// Cache entry not eligible for eviction
UNEVICTABLE = VESTIGIAL | RECYCLED | UPDATE_IN_PROGRESS,
// State flags that are in-memory only, i.e. not persistent
TRANSIENT_FLAGS = DIRTY | RECYCLED | DORMANT
} Flag;
PRBool GetFlag(Flag aFlag) { return (mFlags & aFlag) != 0; }
nsresult GetFlag(PRBool *aResult, Flag aFlag) { *aResult = GetFlag(aFlag); return NS_OK; }
// Set a boolean flag for the cache entry
nsresult SetFlag(PRBool aValue, Flag aFlag);
nsresult SetFlag(Flag aFlag) { return SetFlag(PR_TRUE, aFlag); }
nsresult ClearFlag(Flag aFlag) { return SetFlag(PR_FALSE, aFlag); }
void ComputeProfit(PRUint32 aCurrentTime);
static int Compare(const void *a, const void *b, void *unused);
void NoteAccess();
void NoteUpdate();
// Get underlying raw cache database record.
nsresult GetRecord(nsINetDataCacheRecord* *aRecord);
nsresult GetRecordID(PRInt32 *aRecordID);
nsresult Evict(PRUint32 aTruncatedContentLength);
nsresult GetFileSpec(nsIFileSpec* *aFileSpec);
void NoteDownloadTime(PRTime start, PRTime end);
// placement new for arena-allocation
void *operator new (size_t aSize, nsIArena *aArena);
friend class nsReplacementPolicy;
friend class nsCacheManager;
friend class StreamAsFile;
friend class nsCacheEntryChannel;
friend class CacheOutputStream;
friend class InterceptStreamListener;
private:
nsCachedNetData() {};
virtual ~nsCachedNetData() {};
// Initialize internal fields of this nsCachedNetData instance from the
// underlying raw cache database record.
nsresult Deserialize(PRBool aDeserializeFlags);
// Notify stream-as-file observers about change in cache entry status
nsresult Notify(PRUint32 aMessage, nsresult aError);
// Add/Remove stream-as-file observers
nsresult AddObserver(nsIStreamAsFile *aStreamAsFile, nsIStreamAsFileObserver* aObserver);
nsresult RemoveObserver(nsIStreamAsFileObserver* aObserver);
// Mark cache entry to indicate a write out to the cache database is required
void SetDirty() { mFlags |= DIRTY; }
nsresult Resurrect(nsINetDataCacheRecord *aRecord);
nsresult CommitFlags();
CacheMetaData* FindTaggedMetaData(const char* aTag, PRBool aCreate);
private:
// List of nsIStreamAsFileObserver's that will receive notification events
// when the cache manager or a client desires to delete/truncate a cache
// entry file.
StreamAsFileObserverClosure* mObservers;
// Protocol-specific meta-data, opaque to the cache manager
CacheMetaData *mMetaData;
// Next in chain for a single bucket in the replacement policy hash table
// that maps from record ID to nsCachedNetData
nsCachedNetData* mNext;
// See flag bits, above
// NOTE: 16 bit member is combined with members below for
// struct packing efficiency. Do not change order of members!
PRUint16 mFlags;
protected:
// Number of nsCacheEntryChannels referring to this record
PRUint8 mChannelCount;
// Below members are statistics kept per cache-entry, used to decide how
// profitable it will be to evict a record from the cache relative to other
// existing records. Note: times are measured in *seconds* since the
// 1/1/70 epoch, same as a unix time_t.
// Number of accesses for this cache record
// NOTE: 8 bit member is combined with members above for
// struct packing efficiency. Do not change order of members!
PRUint8 mNumAccesses;
// A reference to the underlying, raw cache database record, either as a
// pointer to an in-memory object or as a database record identifier
union {
nsINetDataCacheRecord* mRecord;
// Database record ID of associated cache record. See
// nsINetDataCache::GetRecordByID().
PRInt32 mRecordID;
};
// Weak link to parent cache
nsINetDataCache* mCache;
// Length of stored content, which may be less than storage consumed if
// compression is used
PRUint32 mLogicalLength;
// Most recent cache entry access times, used to compute access frequency
PRUint32 mAccessTime[MAX_K];
// We use modification time of the original document for replacement policy
// computations, i.e. to compute a document's age, but if we don't know it,
// we use the time that the document was last written to the cache.
union {
// Document modification time, if known.
PRUint32 mLastModifiedTime;
// Time of last cache update for this doc
PRUint32 mLastUpdateTime;
};
union {
// Time until which document is fresh, i.e. does not have to be validated
// with server and, therefore, data in cache is guaranteed usable
PRUint32 mExpirationTime;
// Heuristic time at which cached document is likely to be out-of-date
// with respect to canonical copy on server. Used for cache replacement
// policy, not for validation.
PRUint32 mStaleTime;
};
// Download time per byte, measure roughly in units of KB/s
float mDownloadRate;
// Heuristic estimate of cache entry future benefits, based on above values
float mProfit;
};
#endif // _nsCachedNetData_h_

View File

@@ -0,0 +1,666 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator client code, released
* March 31, 1998.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Scott Furman, fur@netscape.com
*/
#include "nsReplacementPolicy.h"
#include "nsCachedNetData.h"
#include "nsQuickSort.h"
#include "nsIAllocator.h"
#include "nsIEnumerator.h"
#include "prtime.h"
#include "prbit.h"
#include "nsCOMPtr.h"
#include <math.h>
// Constant used to estimate frequency of access to a document based on size
#define CACHE_CONST_B 1.35
// A cache whose space is managed by this replacement policy
class nsReplacementPolicy::CacheInfo {
public:
CacheInfo(nsINetDataCache* aCache):mCache(aCache),mNext(0) {}
nsINetDataCache* mCache;
CacheInfo* mNext;
};
nsReplacementPolicy::nsReplacementPolicy()
: mRankedEntries(0), mCaches(0), mRecordsRemovedSinceLastRanking(0),
mNumEntries(0), mCapacityRankedEntriesArray(0), mLastRankTime(0) {}
nsReplacementPolicy::~nsReplacementPolicy()
{
if (mRankedEntries)
nsAllocator::Free(mRankedEntries);
if (mMapRecordIdToEntry)
nsAllocator::Free(mMapRecordIdToEntry);
}
nsresult
nsReplacementPolicy::Init(PRUint32 aMaxCacheEntries)
{
nsresult rv;
rv = NS_NewHeapArena(getter_AddRefs(mArena), sizeof(nsCachedNetData) * 32);
if (NS_FAILED(rv)) return rv;
mMaxEntries = aMaxCacheEntries;
mHashArrayLength = PR_CeilingLog2(aMaxCacheEntries) >> 3;
size_t numBytes = mHashArrayLength * sizeof(*mMapRecordIdToEntry);
mMapRecordIdToEntry = (nsCachedNetData**)nsAllocator::Alloc(numBytes);
if (!mMapRecordIdToEntry)
return NS_ERROR_OUT_OF_MEMORY;
nsCRT::zero(mMapRecordIdToEntry, numBytes);
return NS_OK;
}
nsresult
nsReplacementPolicy::AddCache(nsINetDataCache *aCache)
{
CacheInfo *cacheInfo = new CacheInfo(aCache);
if (!cacheInfo)
return NS_ERROR_OUT_OF_MEMORY;
cacheInfo->mNext = mCaches;
mCaches = cacheInfo;
return NS_OK;
}
PRUint32
nsReplacementPolicy::HashRecordID(PRInt32 aRecordID)
{
return ((aRecordID >> 16) ^ aRecordID) & (mHashArrayLength - 1);
}
nsCachedNetData*
nsReplacementPolicy::FindCacheEntryByRecordID(PRInt32 aRecordID, nsINetDataCache *aCache)
{
nsresult rv;
nsCachedNetData* cacheEntry;
PRUint32 bucket = HashRecordID(aRecordID);
cacheEntry = mMapRecordIdToEntry[bucket];
for (;cacheEntry; cacheEntry = cacheEntry->mNext) {
PRInt32 recordID;
rv = cacheEntry->GetRecordID(&recordID);
if (NS_FAILED(rv))
continue;
if ((recordID == aRecordID) && (cacheEntry->mCache == aCache))
return cacheEntry;
}
return 0;
}
// Add a cache entry to the hash table that maps record ID to entries
void
nsReplacementPolicy::AddCacheEntry(nsCachedNetData* aCacheEntry, PRInt32 aRecordID)
{
nsCachedNetData** cacheEntryp;
PRUint32 bucket = HashRecordID(aRecordID);
cacheEntryp = &mMapRecordIdToEntry[bucket];
while (*cacheEntryp)
cacheEntryp = &(*cacheEntryp)->mNext;
*cacheEntryp = aCacheEntry;
aCacheEntry->mNext = 0;
}
// Delete a cache entry from the hash table that maps record ID to entries
nsresult
nsReplacementPolicy::DeleteCacheEntry(nsCachedNetData* aCacheEntry)
{
nsresult rv;
PRInt32 recordID;
rv = aCacheEntry->GetRecordID(&recordID);
if (NS_FAILED(rv)) return rv;
PRUint32 bucket = HashRecordID(recordID);
nsCachedNetData** cacheEntryp;
cacheEntryp = &mMapRecordIdToEntry[bucket];
while (*cacheEntryp) {
if (*cacheEntryp == aCacheEntry) {
*cacheEntryp = aCacheEntry->mNext;
return NS_OK;
}
cacheEntryp = &(*cacheEntryp)->mNext;
}
NS_ASSERTION(0, "hash table inconsistency");
return NS_ERROR_FAILURE;
}
nsresult
nsReplacementPolicy::AddAllRecordsInCache(nsINetDataCache *aCache)
{
nsresult rv;
nsCOMPtr<nsISimpleEnumerator> iterator;
nsCOMPtr<nsISupports> iSupports;
nsCOMPtr<nsINetDataCacheRecord> record;
rv = aCache->NewCacheEntryIterator(getter_AddRefs(iterator));
if (!NS_SUCCEEDED(rv)) return rv;
while (1) {
PRBool notDone;
rv = iterator->HasMoreElements(&notDone);
if (NS_FAILED(rv)) return rv;
if (!notDone)
break;
rv = iterator->GetNext(getter_AddRefs(iSupports));
if (!NS_SUCCEEDED(rv)) return rv;
record = do_QueryInterface(iSupports);
rv = AssociateCacheEntryWithRecord(record, aCache, 0);
if (!NS_SUCCEEDED(rv)) return rv;
}
return NS_OK;
}
// Get current time and convert to seconds since the epoch
static PRUint32
now32()
{
double nowFP;
PRInt64 now64 = PR_Now();
LL_L2D(nowFP, now64);
PRUint32 now = (PRUint32)(nowFP * 1e-6);
return now;
}
void
nsCachedNetData::NoteDownloadTime(PRTime start, PRTime end)
{
double startFP, endFP, rate, duration;
LL_L2D(startFP, start);
LL_L2D(endFP, end);
duration = endFP - startFP;
// If the data arrives so fast that it can not be timed due to the clock
// granularity, assume a data arrival duration of 10 ms
if (!duration)
duration = 10000;
// Compute download rate in kB/s
rate = mLogicalLength / (duration * (1e-6 * 1024.0));
if (mDownloadRate) {
// Exponentially smooth download rate
const double alpha = 0.5;
mDownloadRate = (float)(mDownloadRate * alpha + rate * (1.0 - alpha));
} else {
mDownloadRate = (float)rate;
}
}
// 1 hour
#define MIN_HALFLIFE (60 * 60)
// 1 week
#define TYPICAL_HALFLIFE (7 * 24 * 60 * 60)
/**
* Estimate the profit that would be lost if the given cache entry was evicted
* from the cache. Profit is defined as the future expected download delay per
* byte of cached content. The profit computation is made based on projected
* frequency of access, prior download performance and a heuristic staleness
* criteria. The technique used is a variation of that described in the
* following paper:
*
* "A Case for Delay-Conscious Caching of Web Documents"
* http://www.bell-labs.com/user/rvingral/www97.html
*
* Briefly, expected profit is:
*
* (projected frequency of access) * (download time per byte) * (probability freshness)
*/
void
nsCachedNetData::ComputeProfit(PRUint32 aNow)
{
PRUint32 K, now;
if (aNow)
now = aNow;
else
now = now32();
K = PR_MIN(MAX_K, mNumAccesses);
if (!K) {
mProfit = 0;
return;
}
// Compute time, in seconds, since k'th most recent access
double timeSinceKthAccess = now - mAccessTime[K - 1];
if (timeSinceKthAccess <= 0.0) // Sanity check
timeSinceKthAccess = 1.0;
// Estimate frequency of future document access based on past
// access frequency
double frequencyAccess = K / timeSinceKthAccess;
// If we don't have much historical data on access frequency
// use a heuristic based on document size as an estimate
if (mLogicalLength) {
if (K == 1) {
frequencyAccess /= pow(mLogicalLength, CACHE_CONST_B);
} else if (K == 2) {
frequencyAccess /= pow(mLogicalLength, CACHE_CONST_B / 2);
}
}
// Estimate likelihood that data in cache is fresh, i.e.
// that it corresponds to the document on the server
double probabilityFreshness;
PRInt32 halfLife, age, docTime;
PRBool potentiallyStale;
docTime = GetFlag(LAST_MODIFIED_KNOWN) ? mLastModifiedTime : mLastUpdateTime;
age = now - docTime;
probabilityFreshness = 1.0; // Optimistic
if (GetFlag(EXPIRATION_KNOWN)) {
potentiallyStale = now > mExpirationTime;
halfLife = mExpirationTime - mLastModifiedTime;
} else if (GetFlag(STALE_TIME_KNOWN)) {
potentiallyStale = PR_TRUE;
halfLife = mStaleTime - docTime;
} else {
potentiallyStale = PR_TRUE;
halfLife = TYPICAL_HALFLIFE;
}
if (potentiallyStale) {
if (halfLife < MIN_HALFLIFE)
halfLife = MIN_HALFLIFE;
probabilityFreshness = pow(0.5, (double)age / (double)halfLife);
}
mProfit = (float)(frequencyAccess * probabilityFreshness);
if (mDownloadRate)
mProfit /= mDownloadRate;
}
// Number of entries to grow mRankedEntries array when it's full
#define STATS_GROWTH_INCREMENT 256
// Sorting predicate for NS_Quicksort
int
nsCachedNetData::Compare(const void *a, const void *b, void *unused)
{
nsCachedNetData* entryA = *(nsCachedNetData**)a;
nsCachedNetData* entryB = *(nsCachedNetData**)b;
// Percolate deleted or empty entries to the end of the mRankedEntries
// array, so that they can be recycled.
if (!entryA || entryA->GetFlag(RECYCLED)) {
if (!entryB || entryB->GetFlag(RECYCLED))
return 0;
else
return +1;
}
if (!entryB || entryB->GetFlag(RECYCLED))
return -1;
// Evicted entries (those with no content data) and active entries (those
// currently being updated) are collected towards the end of the sorted
// array just prior to the deleted cache entries, since evicted entries
// can't be re-evicted.
if (entryA->GetFlag(UPDATE_IN_PROGRESS)) {
if (entryB->GetFlag(UPDATE_IN_PROGRESS))
return 0;
else
return +1;
}
if (entryB->GetFlag(UPDATE_IN_PROGRESS))
return -1;
PRUint16 Ka = PR_MIN(MAX_K, entryA->mNumAccesses);
PRUint16 Kb = PR_MIN(MAX_K, entryB->mNumAccesses);
// Order cache entries by the number of times they've been accessed
if (Ka < Kb)
return -1;
if (Ka > Kb)
return +1;
/*
* Among records that have been accessed an equal number of times, order
* them by profit.
*/
if (entryA->mProfit > entryB->mProfit)
return +1;
if (entryA->mProfit < entryB->mProfit)
return -1;
return 0;
}
/**
* Rank cache entries in terms of their elegibility for eviction.
*/
nsresult
nsReplacementPolicy::RankRecords()
{
PRUint32 i, now;
// Add all cache records if this is the first ranking
if (!mLastRankTime) {
nsresult rv;
CacheInfo *cacheInfo;
cacheInfo = mCaches;
while (cacheInfo) {
rv = AddAllRecordsInCache(cacheInfo->mCache);
if (NS_FAILED(rv)) return rv;
cacheInfo = cacheInfo->mNext;
}
}
// Get current time and convert to seconds since the epoch
now = now32();
// Recompute profit for every known cache record, except deleted ones
for (i = 0; i < mNumEntries; i++) {
nsCachedNetData* entry = mRankedEntries[i];
if (entry && !entry->GetFlag(nsCachedNetData::RECYCLED))
entry->ComputeProfit(now);
}
NS_QuickSort(mRankedEntries, mNumEntries, sizeof *mRankedEntries,
nsCachedNetData::Compare, 0);
mNumEntries -= mRecordsRemovedSinceLastRanking;
mRecordsRemovedSinceLastRanking = 0;
mLastRankTime = now;
return NS_OK;
}
// A heuristic policy to avoid the cost of re-ranking cache records by
// profitability every single time space must be made available in the cache.
void
nsReplacementPolicy::MaybeRerankRecords()
{
// Rank at most once per minute
PRUint32 now = now32();
if ((now - mLastRankTime) >= 60)
RankRecords();
}
void
nsReplacementPolicy::CompactRankedEntriesArray()
{
if (mRecordsRemovedSinceLastRanking || !mLastRankTime)
RankRecords();
}
nsresult
nsReplacementPolicy::CheckForTooManyCacheEntries()
{
if (mCapacityRankedEntriesArray == mMaxEntries) {
return DeleteOneEntry(0);
} else {
nsresult rv;
CacheInfo *cacheInfo;
cacheInfo = mCaches;
while (cacheInfo) {
PRUint32 numEntries, maxEntries;
rv = cacheInfo->mCache->GetNumEntries(&numEntries);
if (NS_FAILED(rv)) return rv;
rv = cacheInfo->mCache->GetMaxEntries(&maxEntries);
if (NS_FAILED(rv)) return rv;
if (numEntries == maxEntries)
return DeleteOneEntry(cacheInfo->mCache);
cacheInfo = cacheInfo->mNext;
}
}
return NS_OK;
}
/**
* Create a new association between a low-level cache database record and a
* cache entry. Add the entry to the set of entries eligible for eviction from
* the cache. This would typically be done when the cache entry is created.
*/
nsresult
nsReplacementPolicy::AssociateCacheEntryWithRecord(nsINetDataCacheRecord *aRecord,
nsINetDataCache* aCache,
nsCachedNetData** aResult)
{
nsCachedNetData* cacheEntry;
nsresult rv;
// First, see if the record is already known to the replacement policy
PRInt32 recordID;
rv = aRecord->GetRecordID(&recordID);
if (NS_FAILED(rv)) return rv;
cacheEntry = FindCacheEntryByRecordID(recordID, aCache);
if (cacheEntry) {
if (aResult) {
if (cacheEntry->GetFlag(nsCachedNetData::DORMANT))
cacheEntry->Resurrect(aRecord);
NS_ADDREF(cacheEntry);
*aResult = cacheEntry;
}
return NS_OK;
}
// Compact the array of cache entry statistics, so that free entries appear
// at the end, for possible reuse.
if (mNumEntries && (mNumEntries == mCapacityRankedEntriesArray))
CompactRankedEntriesArray();
// If compaction doesn't yield available entries in the
// mRankedEntries array, then extend the array.
if (mNumEntries == mCapacityRankedEntriesArray) {
PRUint32 newCapacity;
rv = CheckForTooManyCacheEntries();
if (NS_FAILED(rv)) return rv;
newCapacity = mCapacityRankedEntriesArray + STATS_GROWTH_INCREMENT;
if (newCapacity > mMaxEntries)
newCapacity = mMaxEntries;
nsCachedNetData** newRankedEntriesArray;
PRUint32 numBytes = sizeof(nsCachedNetData*) * newCapacity;
newRankedEntriesArray =
(nsCachedNetData**)nsAllocator::Realloc(mRankedEntries, numBytes);
if (!newRankedEntriesArray)
return NS_ERROR_OUT_OF_MEMORY;
mRankedEntries = newRankedEntriesArray;
mCapacityRankedEntriesArray = newCapacity;
PRUint32 i;
for (i = mNumEntries; i < newCapacity; i++)
mRankedEntries[i] = 0;
}
// Recycle the record after the last in-use record in the array
nsCachedNetData *entry = mRankedEntries[mNumEntries];
NS_ASSERTION(!entry || !entry->GetFlag(nsCachedNetData::RECYCLED),
"Only deleted cache entries should appear at end of array");
if (!entry) {
entry = new(mArena) nsCachedNetData;
if (!entry)
return NS_ERROR_OUT_OF_MEMORY;
mRankedEntries[mNumEntries] = entry;
} else {
// Clear out recycled data structure
nsCRT::zero(entry, sizeof(*entry));
}
entry->Init(aRecord, aCache);
AddCacheEntry(entry, recordID);
// Add one reference to the cache entry from the cache manager
NS_ADDREF(entry);
if (aResult) {
// And one reference from our caller
NS_ADDREF(entry);
*aResult = entry;
}
mNumEntries++;
return NS_OK;
}
nsresult
nsReplacementPolicy::GetCachedNetData(const char* cacheKey, PRUint32 cacheKeyLength,
nsINetDataCache* aCache,
nsCachedNetData** aResult)
{
nsresult rv;
nsCOMPtr<nsINetDataCacheRecord> record;
rv = aCache->GetCachedNetData(cacheKey, cacheKeyLength,
getter_AddRefs(record));
if (NS_FAILED(rv)) return rv;
return AssociateCacheEntryWithRecord(record, aCache, aResult);
}
/**
* Delete the least desirable record from the cache database. This is used
* when the addition of another record would exceed either the cache manager or
* the cache's maximum permitted number of records.
*/
nsresult
nsReplacementPolicy::DeleteOneEntry(nsINetDataCache *aCache)
{
PRUint32 i;
nsresult rv;
nsCachedNetData *entry;
i = 0;
while (1) {
MaybeRerankRecords();
for (; i < mNumEntries; i++) {
entry = mRankedEntries[i];
if (!entry || entry->GetFlag(nsCachedNetData::RECYCLED))
continue;
if (!aCache || (entry->mCache == aCache))
break;
}
// Report error if no record found to delete
if (i == mNumEntries)
return NS_ERROR_FAILURE;
rv = entry->Delete();
if (NS_SUCCEEDED(rv)) {
rv = DeleteCacheEntry(entry);
return rv;
}
}
}
nsresult
nsReplacementPolicy::GetStorageInUse(PRUint32* aStorageInUse)
{
nsresult rv;
CacheInfo *cacheInfo;
*aStorageInUse = 0;
cacheInfo = mCaches;
while (cacheInfo) {
PRUint32 cacheStorage;
rv = cacheInfo->mCache->GetStorageInUse(&cacheStorage);
if (NS_FAILED(rv)) return rv;
*aStorageInUse += cacheStorage;
cacheInfo = cacheInfo->mNext;
}
return NS_OK;
}
/**
* Delete the least desirable records from the cache until the occupancy of the
* cache has been reduced by the given number of KB. This is used when the
* addition of more cache data would exceed the cache's capacity.
*/
nsresult
nsReplacementPolicy::Evict(PRUint32 aTargetOccupancy)
{
PRUint32 i;
nsCachedNetData *entry;
nsresult rv;
PRUint32 occupancy;
PRInt32 truncatedLength;
nsCOMPtr<nsINetDataCacheRecord> record;
MaybeRerankRecords();
for (i = 0; i < mNumEntries; i++) {
rv = GetStorageInUse(&occupancy);
if (!NS_SUCCEEDED(rv)) return rv;
if (occupancy <= aTargetOccupancy)
return NS_OK;
entry = mRankedEntries[i];
// Skip deleted/empty cache entries and ones that have already been evicted
if (!entry || entry->GetFlag(nsCachedNetData::UNEVICTABLE))
continue;
if (entry->GetFlag(nsCachedNetData::ALLOW_PARTIAL)) {
rv = entry->GetRecord(getter_AddRefs(record));
if (NS_FAILED(rv))
continue;
PRUint32 contentLength;
rv = record->GetStoredContentLength(&contentLength);
if (NS_FAILED(rv))
continue;
// Additional cache storage required, in KB
PRUint32 storageToReclaim = (occupancy - aTargetOccupancy) << 10;
truncatedLength = (PRInt32)(contentLength - storageToReclaim);
if (truncatedLength < 0)
truncatedLength = 0;
} else {
truncatedLength = 0;
}
rv = entry->Evict(truncatedLength);
}
return NS_ERROR_FAILURE;
}

View File

@@ -0,0 +1,136 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator client code, released
* March 31, 1998.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Scott Furman, fur@netscape.com
*/
/**
* This class manages one or more caches that share a storage resource, e.g. a
* file cache and a flat-database cache might each occupy space on the disk and
* they would share a single instance of nsReplacementPolicy. The replacement
* policy heuristically chooses which cache entries to evict when storage is
* required to accommodate incoming cache data.
*/
#ifndef _nsReplacementPolicy_h_
#define _nsReplacementPolicy_h_
#include "nscore.h"
#include "nsISupportsUtils.h"
#include "nsINetDataCache.h"
#include "nsICachedNetData.h"
#include "nsIArena.h"
#include "nsCOMPtr.h"
#include "nsHashtable.h"
class nsCachedNetData;
struct PL_HashTable;
/**
* This private class is responsible for implementing the network data cache's
* replacement policy, i.e. it decides which cache data should be evicted to
* make room for new incoming data.
*/
class nsReplacementPolicy {
public:
nsReplacementPolicy();
~nsReplacementPolicy();
protected:
nsresult Init(PRUint32 aMaxCacheEntries);
nsresult AddCache(nsINetDataCache *aCache);
nsresult GetCachedNetData(const char* cacheKey, PRUint32 cacheKeyLength,
nsINetDataCache* aCache,
nsCachedNetData** aResult);
nsresult GetStorageInUse(PRUint32* aNumKBytes);
friend class nsCacheManager;
private:
nsresult RankRecords();
void MaybeRerankRecords();
void CompactRankedEntriesArray();
nsresult DeleteOneEntry(nsINetDataCache* aCache);
nsresult Evict(PRUint32 aTargetOccupancy);
nsCachedNetData* FindCacheEntryByRecordID(PRInt32 aRecordID, nsINetDataCache *aCache);
void AddCacheEntry(nsCachedNetData* aCacheEntry, PRInt32 aRecordID);
nsresult DeleteCacheEntry(nsCachedNetData* aCacheEntry);
PRUint32 HashRecordID(PRInt32 aRecordID);
nsresult AssociateCacheEntryWithRecord(nsINetDataCacheRecord *aRecord,
nsINetDataCache* aCache,
nsCachedNetData** aResult);
nsresult AddAllRecordsInCache(nsINetDataCache *aCache);
nsresult CheckForTooManyCacheEntries();
class CacheInfo;
private:
// Growable array of pointers to individual cache entries; It is sorted by
// profitability, such that low-numbered array indices refer to cache
// entries that are the least profitable to retain. New cache entries are
// added to the end of the array. Deleted cache entries are specially
// marked and percolate to the end of the array for recycling whenever
// mRankedEntries is sorted. Evicted cache entries (those with no
// associated content data) are retained for the purpose of improving the
// replacement policy efficacy, and are percolated towards the end of the
// array, just prior to the deleted cache entries.
//
// The array is not in sorted order 100% of the time; For efficiency
// reasons, sorting is only done when heuristically deemed necessary.
nsCachedNetData** mRankedEntries;
// Hash table buckets to map Record ID to cache entry. We use this instead
// of a PL_HashTable to reduce storage requirements
nsCachedNetData** mMapRecordIdToEntry;
// Length of mMapRecordIdToEntry array
PRUint32 mHashArrayLength;
// Linked list of caches that share this replacement policy
CacheInfo* mCaches;
// Allocation area for cache entry (nsCachedNetData) instances
nsCOMPtr<nsIArena> mArena;
// Bookkeeping
PRUint32 mRecordsRemovedSinceLastRanking;
// Maximum permitted length of mRankedEntries array
PRUint32 mMaxEntries;
// Number of occupied slots in mRankedEntries array
PRUint32 mNumEntries;
// Capacity of mRankedEntries array
PRUint32 mCapacityRankedEntriesArray;
// Time at which cache entries were last ranked by profitability
PRUint32 mLastRankTime;
};
#endif // _nsReplacementPolicy_h_

View File

@@ -0,0 +1,43 @@
#
# The contents of this file are subject to the Netscape Public
# License Version 1.1 (the "License"); you may not use this file
# except in compliance with the License. You may obtain a copy of
# the License at http://www.mozilla.org/NPL/
#
# Software distributed under the License is distributed on an "AS
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
# implied. See the License for the specific language governing
# rights and limitations under the License.
#
# The Original Code is mozilla.org code.
#
# The Initial Developer of the Original Code is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s):
#
DEPTH = ../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
MODULE = nkcache
include $(DEPTH)/config/autoconf.mk
XPIDLSRCS = \
nsICachedNetData.idl \
nsINetDataCacheManager.idl \
nsINetDataCache.idl \
nsINetDataCacheRecord.idl \
nsINetDataDiskCache.idl \
nsIStreamAsFile.idl \
$(NULL)
EXPORTS := $(addprefix $(srcdir)/, $(EXPORTS))
include $(topsrcdir)/config/rules.mk

41
mozilla/netwerk/cache/public/Makefile.win vendored Executable file
View File

@@ -0,0 +1,41 @@
#!gmake
#
# The contents of this file are subject to the Netscape Public
# License Version 1.1 (the "License"); you may not use this file
# except in compliance with the License. You may obtain a copy of
# the License at http://www.mozilla.org/NPL/
#
# Software distributed under the License is distributed on an "AS
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
# implied. See the License for the specific language governing
# rights and limitations under the License.
#
# The Original Code is mozilla.org code.
#
# The Initial Developer of the Original Code is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s):
MODULE = nkcache
DEPTH = ..\..\..
include <$(DEPTH)/config/config.mak>
EXPORTS = \
$(NULL)
XPIDLSRCS = \
.\nsICachedNetData.idl \
.\nsINetDataCacheManager.idl \
.\nsINetDataCache.idl \
.\nsINetDataCacheRecord.idl \
.\nsINetDataDiskCache.idl \
.\nsIStreamAsFile.idl \
$(NULL)
include <$(DEPTH)/config/rules.mak>

View File

@@ -0,0 +1,229 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
#include "nsrootidl.idl"
#include "nsISupports.idl"
interface nsIFileSpec;
interface nsIURI;
interface nsIObserver;
interface nsIChannel;
interface nsINetDataCache;
interface nsINetDataCacheRecord;
interface nsILoadGroup;
interface nsIStreamListener;
/**
* The nsICachedNetData interface represents a single entry in a database that
* caches data retrieved from the network. This interface is implemented by the
* cache manager on top of the low-level nsINetDataCacheRecord and
* nsINetDataCache interfaces that are implemented by the database.
*
* Each cache record may contain both content and metadata. The content may
* be, for example, GIF image data or HTML, and it is accessed through
* nsIChannel's streaming API. The opaque metadata, which may contain HTTP
* headers among other things, is stored as a byte array. Each entry in the
* cache is indexed by two different keys: a record id number and a key created
* by combining the URI with a "secondary key", e.g. HTTP post data.
*
* @See nsINetDataCacheRecord
* @See nsINetDataCache
* @See nsINetDataDiskCache
* @See nsINetDataCacheManager
*/
[scriptable, uuid(6aeb2a40-6d43-11d3-90c8-000064657374)]
interface nsICachedNetData : nsISupports
{
/**
* String form of the URI provided as an argument to the call to
* nsINetDataCacheManager::GetCachedNetData() that created this record.
*/
readonly attribute string uriSpec;
/**
* Getter for the opaque secondary database key provided as an argument to
* the call to nsINetDataCacheManager::GetCachedNetData() that created this
* record.
*/
void getSecondaryKey(out unsigned long length,
[retval, size_is(length)] out string secondaryKey);
/**
* This flag may be set by a protocol handler to indicate that it supports
* partial fetching of data. In that case, the cache manager is permitted
* to truncate the entry's content to accommodate incoming data for other
* cache entries rather than deleting it wholesale.
*/
attribute boolean allowPartial;
/**
* This flag indicates that the write stream supplying content data for the
* cache did not complete normally and, therefore, the content may be
* truncated.
*/
readonly attribute boolean partialFlag;
/**
* This flag can be set and cleared by a protocol handler as a form of
* self-notification, so as to avoid race conditions in which a protocol
* handler issues two identical network requests to fill the same cache
* entry. The cache manager itself largely ignores this flag.
*/
attribute boolean updateInProgress;
/**
* inUse is set if any existing channels are associated with this cache
* entry or if the updateInProgess flag is set. This can be used to
* prevent writing to a cache entry by a protocol handler if it's being
* read or written elsewhere.
*/
readonly attribute boolean inUse;
/**
* Date/time that the document was last stored on the origin server, as
* supplied by the protocol handler. This value is used as input to the
* cache replacement policy, i.e. it is not used for validation. If the
* protocol can't supply a last-modified time, this attribute should remain
* unset. When unset, the value of this attribute is zero.
*
* FIXME: Should use nsIDateTime interface, once it's created
* instead of PRTime, for improved scriptability ?
*/
attribute PRTime lastModifiedTime;
/**
* Supplied by the protocol handler, the expirationTime attribute specifies
* the time until which the document is guaranteed fresh, i.e. the document
* does not have to be validated with the server and, therefore, any data
* in cache is definitely usable. The value of this attribute serves as a
* hint to the cache replacement policy. Only one of either staleTime or
* expirationTime may be set for a single cache record. When unset, the
* value of this attribute is zero.
*/
attribute PRTime expirationTime;
/**
* Date/time supplied by the protocol handler, at which point the content
* is *likely* to be stale, i.e. the data in the cache may be out-of-date
* with respect to the data on the server. This heuristic date does not
* necessarily correspond to the HTTP Expires header, as it does not
* determine when cached network data must be validated with the origin
* server, but only serves as a hint to the cache replacement policy. Only
* one of either staleTime or expirationTime may be set for a single cache
* record. When unset, the value of this attribute is zero.
*/
attribute PRTime staleTime;
/**
* Date/time of last access of the data in this cache record, as determined
* by the cache manager.
*/
readonly attribute PRTime lastAccessTime;
/**
* Number of times this record has been accessed since it was first stored.
*/
readonly attribute PRUint16 numberAccesses;
/**
* Accessor methods for opaque meta-data which can be read and updated
* independently of the content data.
*
* The aTag argument can be used to accommodate multiple clients of the
* cache API, each of which wants to store its own private meta-data into
* the cache. For example, there could be a "headers" tag that the HTTP
* protocol handler uses to store http response headers and a "image size"
* tag used to store the image dimensions of a GIF file. The aData
* argument refers to an opaque blob of arbitrary bytes.
*
* IMPORTANT: If aData does not contain byte-oriented data, i.e. it's not a
* string, the contents of aData must be byte-swapped by the,
* caller, so as to make the cache files endian-independent.
*/
void getAnnotation(in string aTag,
out PRUint32 aLength, [size_is(aLength), retval] out string aData);
void setAnnotation(in string aTag,
in PRUint32 aLength, [size_is(aLength)] in string aData);
/**
* As a getter, return the number of content bytes stored in the cache,
* i.e. via the nsIChannel streaming APIs. This may be less than the
* complete content length if a partial cache fill occurred. The cached
* content can be truncated by setting the value of this attribute. The
* value of the attribute represents a logical, not a physical, length. If
* compression has been used, the content may consume less storage than
* indicated by this attribute.
*
* When this attribute is set to zero the associated cache disk file, if
* any, should be deleted.
*/
attribute PRUint32 storedContentLength;
/**
* Notify any observers associated with this cache entry of the deletion
* request. If all observers drop their reference to the cache entry,
* proceed to delete the underlying cache database record and associated
* content storage.
*/
void delete();
/**
* Flush any changes in this entry's data to the cache database. This
* method will automatically be called when the last reference to the cache
* is dropped, but it can also be called explicitly for a synchronous
* effect.
*/
void commit();
/**
* Parent container cache for this entry.
*/
readonly attribute nsINetDataCache cache;
/**
* Create a channel for reading or writing a stream of content into the
* entry. It is expected that many of the nsIChannel methods return
* NS_NOT_IMPLEMENTED, including:
*
* + GetURI()
* + GetContentType()
* + GetContentLength()
*
* Though nsIChannel provides for both async and synchronous I/O APIs, both
* may not be implemented. Only AsyncRead() and OpenOutputStream() is
* required. The aProxyChannel argument allows another channel to be
* specified as the proffered argument to nsIStreamListener methods rather
* than the cache's own channel.
*/
nsIChannel newChannel(in nsILoadGroup aLoadGroup,
in nsIChannel aProxyChannel);
/**
* This method can be used by a caching protocol handler to store data in
* the cache by forking an asynchronous read stream so that it is
* simultaneously sent to a requester and written into the cache. This
* method implicitly sets the updateInProgress flag, if it has not already
* been set.
*/
nsIStreamListener interceptAsyncRead(in nsIStreamListener aOriginalListener,
in PRUint32 aStartOffset);
};

View File

@@ -0,0 +1,143 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
#include "nsISupports.idl"
interface nsIURI;
interface nsINetDataCacheRecord;
interface nsISimpleEnumerator;
interface nsIFileSpec;
/**
* The nsINetDataCache defines the low-level API for a network-data
* cache, used to cache the responses to network retrieval commands.
* This interface, along with nsINetDataCacheRecord, is implemented by
* the memory cache, the file cache and, optionally, by some extension
* caches. This interface is essentially a pseudo-private API for the
* cache manager. Other clients should never use this interface.
*
* Each cache entry may contain both content, e.g. GIF image data, and
* associated metadata, e.g. HTTP headers. Each entry is indexed by two
* different keys: a record id number and a key created by combining the URI
* with a "secondary key", e.g. HTTP post data.
*
* The nsINetDataCache interface is agnostic as to where the data is
* stored and whether the storage is volatile or persistent. The
* memory cache, any disk caches and any extension caches must all
* implement this interface.
*
*/
[scriptable, uuid(ccfc58c0-6dde-11d3-90c8-000064657374)]
interface nsINetDataCache : nsISupports
{
/**
* Human-readable description of the cache module, e.g. "Disk Cache"
*/
readonly attribute wstring description;
/**
* Returns true if cached data is available for the given opaque key,
* even if only partial data is stored.
*/
boolean contains([size_is(length)] in string key, in PRUint32 length);
/**
* Fetch the cache entry record for the given opaque key. If one does not
* exist, create a new, empty record.
*/
nsINetDataCacheRecord getCachedNetData([size_is(length)] in string key,
in PRUint32 length);
/**
* Fetch the cache entry record for the given URI using the record ID as a key.
*/
nsINetDataCacheRecord getCachedNetDataByID(in PRInt32 RecordID);
/**
* False indicates that this cache is entirely bypassed.
*/
attribute boolean enabled;
/**
* Constants for flags attribute, below
*/
// Used for extension caches, e.g. a CD-ROM cache
const long READ_ONLY = 1 << 0;
// One of these bits must be set
const long MEMORY_CACHE = 1 << 1;
const long FLAT_FILE_CACHE = 1 << 2;
const long FILE_PER_URL_CACHE = 1 << 3;
/**
* See constants defined above.
*/
readonly attribute PRUint32 flags;
/**
* Total number of URI entries stored in the cache.
*/
readonly attribute PRUint32 numEntries;
/**
* Maximum number of URI entries that may be stored in the cache.
*/
readonly attribute PRUint32 maxEntries;
/**
* Enumerate the URI entries stored in the cache.
*/
nsISimpleEnumerator newCacheEntryIterator();
/**
* Contains a reference to the next cache in search order. For the memory
* cache, this attribute always references the disk cache. For the disk
* cache, it contains a reference to the first extension cache.
*/
attribute nsINetDataCache nextCache;
/**
* An estimate of the amount of storage occupied by the cache, in kB.
* Actual use may be slightly higher than reported due to cache overhead
* and heap fragmentation (in the memory cache) or block quantization (in
* the disk cache).
*/
readonly attribute PRUint32 storageInUse;
/**
* Remove all entries from a writable cache. This could be used, for
* example, after a guest ends a browser session. This is equivalent to
* setting the cache's Capacity to zero, except that all cache entries,
* even those in active use, will be deleted. Also, any global cache
* database files will be deleted.
*/
void removeAll();
};
%{ C++
// ProgID prefix for Components that implement this interface
#define NS_NETWORK_CACHE_PROGID "component://netscape/network/cache"
#define NS_NETWORK_MEMORY_CACHE_PROGID NS_NETWORK_CACHE_PROGID "?name=memory-cache"
#define NS_NETWORK_FLAT_CACHE_PROGID NS_NETWORK_CACHE_PROGID "?name=flat-cache"
#define NS_NETWORK_FILE_CACHE_PROGID NS_NETWORK_CACHE_PROGID "?name=file-cache"
%}

View File

@@ -0,0 +1,163 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
#include "nsISupports.idl"
interface nsISimpleEnumerator;
interface nsICachedNetData;
interface nsINetDataCache;
interface nsINetDataDiskCache;
interface nsIURI;
interface nsIFileSpec;
/**
* The network-response cache manager is partly responsible for the caching of
* content and associated metadata that has been retrieved via the network.
* (The remaining responsibility for caching lies with individual network
* protocol handlers.)
*
* The cache manager supervises the actions of individual cache components,
* such as the memory cache, the disk cache and any extension caches, e.g. a
* read-only CD-ROM cache.
*
* @See nsINetDataCache
* @See nsICachedNetData
*/
[scriptable, uuid(71c8ab00-6d5c-11d3-90c8-000064657374)]
interface nsINetDataCacheManager : nsISupports
{
/**
* Flag for the GetCachedNetData() method: If set, the memory cache is
* neither searched nor will any data be stored into it. This might be
* appropriate, for example, with images, because they have their own
* cache for storing *decoded* images.
*/
const unsigned long BYPASS_MEMORY_CACHE = 1 << 0;
/**
* Flag for the GetCachedNetData() method: If set, the disk cache
* is neither searched nor will any be data stored into it.
* However, read-only extension caches may be searched. This
* might be used to avoid leaving persistent records of secure
* data.
*/
const unsigned long BYPASS_PERSISTENT_CACHE = 1 << 1;
/**
* Flag for the GetCachedNetData() method: If set, any stream
* content is stored in the cache as a single disk file. Content
* will not be cached in the memory cache nor is it cached in a
* flat-file cache database. This is used to implement the jar
* protocol handler and to provide the stream-as-file semantics
* required by the classic bowser plugin API.
*/
const unsigned long CACHE_AS_FILE = 1 << 2;
/**
* Fetch the cache entry record for the given URI. If one does not exist,
* create a new, empty record. The normal search order for caches is:
* + Memory cache
* + Disk cache
* + File cache (stream-as-file cache)
* + All extension caches
*
* When writing, data is typically stored in both the memory cache and the
* disk cache. Both the search order and this write policy can be modified by
* setting one or more of the flag argument bits, as defined above.
*
* The optionally-NULL secondaryKey argument can be used, e.g. for form
* post data or for HTTP headers in the case of HTTP.
*/
nsICachedNetData getCachedNetData(in string uri,
[size_is(secondaryKeyLength)] in string secondaryKey,
in PRUint32 secondaryKeyLength,
in PRUint32 flags);
/**
* Returns true if cached content is available for the given URI, even if
* only partial data is stored. The flags argument behaves the same as for
* the GetCachedNetData() method, above.
*/
boolean contains(in string uri,
[size_is(secondaryKeyLength)] in string secondaryKey,
in PRUint32 secondaryKeyLength,
in PRUint32 flags);
/**
* Total number of unexpired URI entries stored in all caches. This number
* does not take into account duplicate URIs, e.g. because the memory cache
* and the disk cache might each contain an entry for the same URI.
*/
readonly attribute PRUint32 numEntries;
/**
* Enumerate the unexpired URI entries stored in all caches. Some URIs may
* be enumerated more than once, e.g. because the the memory cache and the
* disk cache might each contain an entry for the same URI.
*/
nsISimpleEnumerator newCacheEntryIterator();
/*
* Enumerate all the loaded nsINetDataCache-implementing cache modules.
* The first module enumerated will be the memory cache, the second will be
* the disk cache, then the file cache, followed by all the extension
* caches, in search order.
*/
nsISimpleEnumerator newCacheModuleIterator();
/**
* Remove all entries from all writable caches. This could be used, for
* example, after a guest ends a browser session. This is equivalent to
* setting the DiskCacheCapacity to zero, except that all cache entries,
* even those in active use, will be deleted. Also, any global cache
* database files will be deleted.
*/
void RemoveAll();
/**
* The disk cache is made up of the file cache (for stream-as-file
* requests) and a (possibly independent) persistent cache that handles all
* other cache requests. This attribute sets/gets the combined capacity of
* these caches, measured in KBytes. Setting the capacity lower than the
* current amount of space currently in use may cause cache entries to be
* evicted from the cache to accomodate the requested capacity.
*/
attribute PRUint32 diskCacheCapacity;
/**
* This attribute sets/gets the capacity of the memory cache, measured in
* KBytes. Setting the capacity lower than the current amount of space
* currently in use may cause cache entries to be evicted from the cache to
* accomodate the requested capacity.
*/
attribute PRUint32 memCacheCapacity;
/**
* This attribute must be set before attempting to store into the disk cache.
*/
attribute nsIFileSpec diskCacheFolder;
};
%{ C++
// ProgID prefix for Components that implement this interface
#define NS_NETWORK_CACHE_MANAGER_PROGID NS_NETWORK_CACHE_PROGID "?name=manager"
%}

View File

@@ -0,0 +1,125 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
#include "nsISupports.idl"
#include "nsrootidl.idl"
interface nsIFileSpec;
interface nsIChannel;
interface nsINetDataCache;
/**
* The nsINetDataCacheRecord represents a single entry in a database that
* caches data retrieved from the network. On top of this low-level interface
* to the raw record data, the cache manager implements a higher-level record
* interface, nsICachedNetData. Each instance of nsINetDataCacheRecord is
* (internally) associated with a parent database, an instance of the
* nsINetDataCache interface. This interface is essentially a pseudo-private
* API for the cache manager. Other clients should never use this interface.
*
* Each cache record may contain both content and metadata. The content may
* be, for example, GIF image data or HTML, and it is accessed through
* nsIChannel's streaming API. The opaque metadata, which may contain HTTP
* headers among other things, is accessed as a contiguous byte array. Each
* entry in the cache is indexed by two different keys: a unique record id
* number, generated by the cache, and an opaque string. The latter contains
* the URI and other secondary key information, e.g. HTTP form post key/value
* pairs.
*
* The nsINetDataCacheRecord interface is agnostic as to where the data is
* stored and whether the storage is volatile or persistent. The memory cache,
* the disk cache, a flat-file cache and any read-only extension caches must
* all implement this interface.
*
* @See nsICachedNetData
* @See nsINetDataCache
* @See nsINetDataDiskCache
* @See nsINetDataCacheManager
*/
interface nsILoadGroup;
[scriptable, uuid(fdcdd6a0-7461-11d3-90ca-0040056a906e)]
interface nsINetDataCacheRecord : nsISupports
{
/**
* As far as the nsINetDataCacheRecord implementation is concerned, the
* cache entry database key is an opaque blob, but it's intended to contain
* both the URI and any secondary keys, such as HTTP post data.
*/
void getKey(out unsigned long length, [size_is(length), retval] out string key);
/**
* A persistent record number assigned by the cache which must be unique
* among all entries stored within the same cache. The record ID serves as
* an alternate key to the cache record. Providing that they satisfy the
* afforementioned uniqueness requirement, record IDs can be assigned any
* value by the database except that they may never be zero.
*/
readonly attribute PRInt32 recordID;
/**
* Opaque data which can be updated for each cache entry independently of
* the content data. This data is a combination of protocol-independent
* data provided by the cache manager and protocol-specific meta-data,
* e.g. HTTP headers.
*/
void getMetaData(out PRUint32 length, [size_is(length), retval] out string metaData);
void setMetaData(in PRUint32 length, [size_is(length)] in string data);
/**
* Number of content bytes stored in the cache, i.e. via the nsIChannel
* streaming APIs. This may be less than the complete content length if a
* partial cache fill occurred. Additionally, the cached content can be
* truncated by reducing the value of this attribute. When this attribute
* is set to zero the associated cache disk file, if any, should be
* deleted.
*/
attribute PRUint32 storedContentLength;
/**
* Delete this cache entry and its associated content.
*/
void delete();
/**
* Create a channel for reading or writing a stream of content into the
* entry. However, many of the nsIChannel methods may return
* NS_NOT_IMPLEMENTED, including:
*
* + GetURI()
* + GetContentType()
* + GetContentLength()
*/
nsIChannel newChannel(in nsILoadGroup loadGroup);
/**
* If a cache is implemented such that it stores each URI's content in an
* individual disk file, this method will identify the file corresponding
* to this record. This may be used to implement the "stream-as-file"
* semantics required by some plugins and by the 'jar:' protocol handler.
* However, not all cache implementations are *required* to store the data
* from each URI in an individual file, so it is acceptable for an
* implementation of this method to signal NS_NOT_IMPLEMENTED.
*/
readonly attribute nsIFileSpec filename;
};

View File

@@ -0,0 +1,42 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
#include "nsINetDataCache.idl"
interface nsIFileSpec;
/**
/**
* A network-data disk cache is used to persistently cache the responses to
* network retrieval commands. Each cache entry may contain both content,
* e.g. GIF image data, and associated metadata, e.g. HTTP headers.
*/
[scriptable, uuid(6408e390-6f13-11d3-90c8-000064657374)]
interface nsINetDataDiskCache : nsINetDataCache
{
/**
* This attribute must be set before calling any other methods of this
* interface.
*/
attribute nsIFileSpec diskCacheFolder;
};

View File

@@ -0,0 +1,106 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator client code, released
* March 31, 1998.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Scott Furman, fur@netscape.com
*/
#include "nsrootidl.idl"
#include "nsISupports.idl"
interface nsIFileSpec;
interface nsIStreamAsFileObserver;
/**
* In addition to enhancing effective network response time via caching, the
* cache manager serves a second purpose by providing the stream-as-file
* service required by traditional browser plugins and the jar: protocol
* handler. The interface below provides a means for a client to determine the
* filename associated with a stream and to detect modification/deletion of
* that file.
*/
[scriptable, uuid(0eedbbf0-92d9-11d3-90d3-0040056a906e)]
interface nsIStreamAsFile : nsISupports
{
/**
* Filename containing stream-as-file
*/
readonly attribute nsIFileSpec fileSpec;
/**
* Add an observer for this cache record. When the cache wants to delete
* or truncate a record, so as to make space for another cache entry's
* content data, it will call <code>aObserver</code>'s Observe() method,
* passing the nsIStreamAsFile instance as the <code>aSubject</code>
* argument and an appropriate message. If the observer does not wish to
* inhibit deletion/truncation, it should Release() any references it has to the
* cache record.
*
* @See nsIStreamAsFileObserver
*/
void addObserver(in nsIStreamAsFileObserver aObserver);
/**
* Delete an observer that was added by the AddObserver() method.
*/
void removeObserver(in nsIStreamAsFileObserver aObserver);
};
/**
* This interface can be implemented by a client to receive notifications of
* either modification or deletion of a file created by the cache manager using
* the stream-as-file semantics.
*/
[scriptable, uuid(a26e27c0-92da-11d3-90d3-0040056a906e)]
interface nsIStreamAsFileObserver : nsISupports
{
/**
* Flag bits for argument to Observe() method.
*/
const long NOTIFY_AVAILABLE = 1 << 0; // Stream-as-file now available for reading
const long NOTIFY_ERROR = 1 << 1; // Error while loading stream / creating file
const long REQUEST_DELETION = 1 << 2; // Cache manager wishes to delete/truncate file
const long INVALIDATE = 1 << 3; // File is out-of-date
// Convenience value
const long MAKE_UNAVAILABLE = REQUEST_DELETION | INVALIDATE;
/**
* Receive either a notification or a request concerning a file that has
* been opened using stream-as-file. The aMessage and aError arguments
* have varying values depending on the nature of the notification.
* aMessage is set to NOTIFY_AVAILABLE when a complete stream has been read
* and stored on disk in a file. At that point, and no sooner, may the
* filename attribute of the associated nsIStreamAsFile be accessed via the
* associated nsIStreamAsFile interface. If the aMessage argument is
* NOTIFY_ERROR, the aError argument contains the relevant error code. If
* the aMessage argument is either REQUEST_DELETION or REQUEST_TRUNCATION,
* the callee should immediately Release() all references to the
* nsIStreamAsFile (and any references to its associated nsICachedNetData
* instances), unless it wishes to inhibit the requested file modification.
* If the aMessage argument is INVALIDATE, the cache manager is replacing
* the file with a more recent version. If a client wants to continue
* using the (now out-of-date) file, it must delete it when it has finished,
* as the cache manager will effectively relinquished ownership of the
* file.
*/
void ObserveStreamAsFile(in nsIStreamAsFile aStreamAsFile,
in PRUint32 aMessage,
in nsresult aError);
};

View File

@@ -0,0 +1,39 @@
#!gmake
#
# The contents of this file are subject to the Netscape Public
# License Version 1.1 (the "License"); you may not use this file
# except in compliance with the License. You may obtain a copy of
# the License at http://www.mozilla.org/NPL/
#
# Software distributed under the License is distributed on an "AS
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
# implied. See the License for the specific language governing
# rights and limitations under the License.
#
# The Original Code is mozilla.org code.
#
# The Initial Developer of the Original Code is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s):
DEPTH = ..
MODULE = necko
DIRS= \
base \
dns \
build \
protocol \
socket \
util \
mime \
streamconv \
cache \
test \
$(NULL)
include <$(DEPTH)\config\rules.mak>

View File

@@ -0,0 +1,32 @@
/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
#include "nsISupports.idl"
interface nsIAtom;
[scriptable, uuid(a3ec67f0-465a-11d3-9a89-0080c7cb1080)]
interface nsIHTTPHeader : nsISupports
{
nsIAtom GetField();
string GetValue();
};

View File

@@ -0,0 +1,603 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "nsIStreamListener.h"
#include "nsIStreamObserver.h"
#include "nsIServiceManager.h"
#include "nsIInputStream.h"
#include "nsIOutputStream.h"
#include "nsIEventQueue.h"
#include "nsIEventQueueService.h"
#include "nsIChannel.h"
#include "nsCOMPtr.h"
#include "nsINetDataCache.h"
#include "nsINetDataCacheManager.h"
#include "nsICachedNetData.h"
// Number of test entries to be placed in the cache
// FIXME - temporary
#define NUM_CACHE_ENTRIES 25
// Cache content stream length will have random length between zero and
// MAX_CONTENT_LENGTH bytes
#define MAX_CONTENT_LENGTH 20000
// Limits, converted to KB
#define DISK_CACHE_CAPACITY ((MAX_CONTENT_LENGTH * 4) >> 10)
#define MEM_CACHE_CAPACITY ((MAX_CONTENT_LENGTH * 3) >> 10)
// Length of random-data cache entry URI key
#define CACHE_KEY_LENGTH 13
// Length of random-data cache entry secondary key
#define CACHE_SECONDARY_KEY_LENGTH 10
// Length of random-data cache entry meta-data
#define CACHE_PROTOCOL_PRIVATE_LENGTH 10
// Mapping from test case number to RecordID
static PRInt32 recordID[NUM_CACHE_ENTRIES];
static PRInt32
mapRecordIdToTestNum(PRInt32 aRecordID)
{
int i;
for (i = 0; i < NUM_CACHE_ENTRIES; i++) {
if (recordID[i] == aRecordID)
return i;
}
return -1;
}
// A supply of stream data to either store or compare with
class nsITestDataStream {
public:
virtual ~nsITestDataStream() {};
virtual PRUint32 Next() = 0;
virtual void Read(char* aBuf, PRUint32 aCount) = 0;
virtual void ReadString(char* aBuf, PRUint32 aCount) = 0;
virtual PRBool Match(char* aBuf, PRUint32 aCount) = 0;
virtual PRBool MatchString(char* aBuf, PRUint32 aCount) = 0;
virtual void Skip(PRUint32 aCount) = 0;
virtual void SkipString(PRUint32 aCount) = 0;
};
// A reproducible stream of random data.
class RandomStream : public nsITestDataStream {
public:
RandomStream(PRUint32 aSeed) {
mStartSeed = mState = aSeed;
}
PRUint32 GetStartSeed() {
return mStartSeed;
}
PRUint32 Next() {
mState = 1103515245 * mState + 12345 ^ (mState >> 16);
return mState;
}
PRUint8 NextChar() {
PRUint8 c;
do {
c = Next();
} while (!isalnum(c));
return c;
}
void Read(char* aBuf, PRUint32 aCount) {
PRUint32 i;
for (i = 0; i < aCount; i++) {
*aBuf++ = Next();
}
}
// Same as Read(), but using only printable chars and
// with a terminating NUL
void ReadString(char* aBuf, PRUint32 aCount) {
PRUint32 i;
for (i = 0; i < aCount; i++) {
*aBuf++ = NextChar();
}
*aBuf = 0;
}
PRBool
Match(char* aBuf, PRUint32 aCount) {
PRUint32 i;
for (i = 0; i < aCount; i++) {
if (*aBuf++ != (char)(Next() & 0xff))
return PR_FALSE;
}
return PR_TRUE;
}
PRBool
MatchString(char* aBuf, PRUint32 aCount) {
PRUint32 i;
for (i = 0; i < aCount; i++) {
if (*aBuf++ != (char)(NextChar() & 0xff))
return PR_FALSE;
}
// Check for terminating NUL character
if (*aBuf)
return PR_FALSE;
return PR_TRUE;
}
void
Skip(PRUint32 aCount) {
while (aCount--)
Next();
}
void
SkipString(PRUint32 aCount) {
while (aCount--)
NextChar();
}
protected:
PRUint32 mState;
PRUint32 mStartSeed;
};
static int gNumReaders = 0;
static PRUint32 gTotalBytesRead = 0;
static PRUint32 gTotalBytesWritten = 0;
static PRUint32 gTotalDuration = 0;
class nsReader : public nsIStreamListener {
public:
NS_DECL_ISUPPORTS
nsReader()
: mStartTime(0), mBytesRead(0)
{
NS_INIT_REFCNT();
gNumReaders++;
}
virtual ~nsReader() {
delete mTestDataStream;
gNumReaders--;
}
nsresult
Init(nsITestDataStream* aRandomStream, PRUint32 aExpectedStreamLength) {
mTestDataStream = aRandomStream;
mExpectedStreamLength = aExpectedStreamLength;
mRefCnt = 1;
return NS_OK;
}
NS_IMETHOD OnStartRequest(nsIChannel* channel,
nsISupports* context) {
mStartTime = PR_IntervalNow();
return NS_OK;
}
NS_IMETHOD OnDataAvailable(nsIChannel* channel,
nsISupports* context,
nsIInputStream *aIStream,
PRUint32 aSourceOffset,
PRUint32 aLength) {
char buf[1025];
while (aLength > 0) {
PRUint32 amt;
PRBool match;
aIStream->Read(buf, sizeof buf, &amt);
if (amt == 0) break;
aLength -= amt;
mBytesRead += amt;
match = mTestDataStream->Match(buf, amt);
NS_ASSERTION(match, "Stored data was corrupted on read");
}
return NS_OK;
}
NS_IMETHOD OnStopRequest(nsIChannel* channel,
nsISupports* context,
nsresult aStatus,
const PRUnichar* aMsg) {
PRIntervalTime endTime;
PRIntervalTime duration;
endTime = PR_IntervalNow();
duration = (endTime - mStartTime);
if (NS_FAILED(aStatus)) printf("channel failed.\n");
// printf("read %d bytes\n", mBytesRead);
//FIXME NS_ASSERTION(mBytesRead == mExpectedStreamLength,
// "Stream in cache is wrong length");
gTotalBytesRead += mBytesRead;
gTotalDuration += duration;
return NS_OK;
}
protected:
PRIntervalTime mStartTime;
PRUint32 mBytesRead;
nsITestDataStream* mTestDataStream;
PRUint32 mExpectedStreamLength;
};
NS_IMPL_ISUPPORTS2(nsReader, nsIStreamListener, nsIStreamObserver)
static nsIEventQueue* eventQueue;
static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
nsresult
InitQueue() {
nsresult rv;
NS_WITH_SERVICE(nsIEventQueueService, eventQService, kEventQueueServiceCID, &rv);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get event queue service");
rv = eventQService->CreateThreadEventQueue();
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't create event queue");
rv = eventQService->GetThreadEventQueue(PR_CurrentThread(), &eventQueue);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get event queue for main thread");
return NS_OK;
}
// Process events until all streams are OnStopRequest'ed
nsresult
WaitForEvents() {
while (gNumReaders) {
eventQueue->ProcessPendingEvents();
}
return NS_OK;
}
// Read data for a single cache record and compare against testDataStream
nsresult
TestReadStream(nsICachedNetData *cacheEntry, nsITestDataStream *testDataStream,
PRUint32 expectedStreamLength)
{
nsCOMPtr<nsIChannel> channel;
nsresult rv;
PRUint32 actualContentLength;
rv = cacheEntry->NewChannel(0, 0, getter_AddRefs(channel));
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
rv = cacheEntry->GetStoredContentLength(&actualContentLength);
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
// FIXME NS_ASSERTION(actualContentLength == expectedStreamLength,
// "nsICachedNetData::GetContentLength() busted ?");
nsReader *reader = new nsReader;
reader->AddRef();
rv = reader->Init(testDataStream, expectedStreamLength);
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
rv = channel->AsyncRead(0, -1, 0, reader);
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
reader->Release();
return NS_OK;
}
// Convert PRTime to unix-style time_t, i.e. seconds since the epoch
static PRUint32
convertPRTimeToSeconds(PRTime aTime64)
{
double fpTime;
LL_L2D(fpTime, aTime64);
return (PRUint32)(fpTime * 1e-6 + 0.5);
}
// Convert unix-style time_t, i.e. seconds since the epoch, to PRTime
static PRTime
convertSecondsToPRTime(PRUint32 aSeconds)
{
PRInt64 t64;
LL_L2I(t64, aSeconds);
LL_MUL(t64, t64, 1000000);
return t64;
}
// Read the test data that was written in FillCache(), checking for
// corruption, truncation.
nsresult
TestRead(nsINetDataCacheManager *aCache, PRUint32 aFlags)
{
nsresult rv;
PRBool inCache;
nsCOMPtr<nsICachedNetData> cacheEntry;
RandomStream *randomStream;
char uriCacheKey[CACHE_KEY_LENGTH];
char secondaryCacheKey[CACHE_SECONDARY_KEY_LENGTH];
char *storedUriKey;
PRUint32 testNum;
gTotalBytesRead = 0;
gTotalDuration = 0;
for (testNum = 0; testNum < NUM_CACHE_ENTRIES; testNum++) {
randomStream = new RandomStream(testNum);
randomStream->ReadString(uriCacheKey, sizeof uriCacheKey - 1);
randomStream->Read(secondaryCacheKey, sizeof secondaryCacheKey);
// Ensure that entry is in the cache
rv = aCache->Contains(uriCacheKey,
secondaryCacheKey, sizeof secondaryCacheKey,
aFlags, &inCache);
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
NS_ASSERTION(inCache, "nsINetDataCacheManager::Contains error");
rv = aCache->GetCachedNetData(uriCacheKey,
secondaryCacheKey, sizeof secondaryCacheKey,
aFlags,
getter_AddRefs(cacheEntry));
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
// Test GetUriSpec() method
rv = cacheEntry->GetUriSpec(&storedUriKey);
NS_ASSERTION(NS_SUCCEEDED(rv) &&
!memcmp(storedUriKey, &uriCacheKey[0], sizeof uriCacheKey),
"nsICachedNetData::GetKey failed");
nsAllocator::Free(storedUriKey);
// Test GetSecondaryKey() method
PRUint32 storedSecondaryKeyLength;
char* storedSecondaryKey;
rv = cacheEntry->GetSecondaryKey(&storedSecondaryKeyLength, &storedSecondaryKey);
NS_ASSERTION(NS_SUCCEEDED(rv) &&
!memcmp(storedSecondaryKey, &secondaryCacheKey[0],
sizeof secondaryCacheKey),
"nsICachedNetData::GetSecondaryKey failed");
// Compare against stored protocol data
char *storedProtocolData;
PRUint32 storedProtocolDataLength;
rv = cacheEntry->GetAnnotation("test data", &storedProtocolDataLength, &storedProtocolData);
NS_ASSERTION(NS_SUCCEEDED(rv) &&
storedProtocolDataLength == CACHE_PROTOCOL_PRIVATE_LENGTH,
"nsICachedNetData::GetAnnotation() failed");
randomStream->Match(storedProtocolData, storedProtocolDataLength);
// Test GetAllowPartial()
PRBool allowPartial;
rv = cacheEntry->GetAllowPartial(&allowPartial);
NS_ASSERTION(NS_SUCCEEDED(rv) &&
(allowPartial == (PRBool)(randomStream->Next() & 1)),
"nsICachedNetData::GetAllowPartial() failed");
// Test GetExpirationTime()
PRTime expirationTime;
PRTime expectedExpirationTime = convertSecondsToPRTime(randomStream->Next() & 0xffffff);
rv = cacheEntry->GetExpirationTime(&expirationTime);
NS_ASSERTION(NS_SUCCEEDED(rv) && LL_EQ(expirationTime, expectedExpirationTime),
"nsICachedNetData::GetExpirationTime() failed");
PRUint32 expectedStreamLength = randomStream->Next() % MAX_CONTENT_LENGTH;
TestReadStream(cacheEntry, randomStream, expectedStreamLength);
}
WaitForEvents();
// Compute rate in MB/s
double rate = gTotalBytesRead / PR_IntervalToMilliseconds(gTotalDuration);
rate *= NUM_CACHE_ENTRIES;
rate *= 1000;
rate /= (1024 * 1024);
printf("Read %7d bytes at a rate of %5.1f MB per second \n",
gTotalBytesRead, rate);
return NS_OK;
}
// Create entries in the network data cache, using random data for the
// key, the meta-data and the stored content data.
nsresult
FillCache(nsINetDataCacheManager *aCache, PRUint32 aFlags, PRUint32 aCacheCapacity)
{
nsresult rv;
PRBool inCache;
nsCOMPtr<nsICachedNetData> cacheEntry;
nsCOMPtr<nsIChannel> channel;
nsCOMPtr<nsIOutputStream> outStream;
nsCOMPtr<nsINetDataCache> containingCache;
char buf[1000];
PRUint32 protocolDataLength;
char cacheKey[CACHE_KEY_LENGTH];
char secondaryCacheKey[CACHE_SECONDARY_KEY_LENGTH];
char protocolData[CACHE_PROTOCOL_PRIVATE_LENGTH];
PRUint32 testNum;
RandomStream *randomStream;
gTotalBytesWritten = 0;
PRIntervalTime startTime = PR_IntervalNow();
for (testNum = 0; testNum < NUM_CACHE_ENTRIES; testNum++) {
randomStream = new RandomStream(testNum);
randomStream->ReadString(cacheKey, sizeof cacheKey - 1);
randomStream->Read(secondaryCacheKey, sizeof secondaryCacheKey);
// No entry should be in cache until we add it
rv = aCache->Contains(cacheKey,
secondaryCacheKey, sizeof secondaryCacheKey,
aFlags, &inCache);
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
NS_ASSERTION(!inCache, "nsINetDataCacheManager::Contains error");
rv = aCache->GetCachedNetData(cacheKey,
secondaryCacheKey, sizeof secondaryCacheKey,
aFlags,
getter_AddRefs(cacheEntry));
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't access cacheEntry via cache key");
// Test nsINetDataCacheManager::GetNumEntries()
PRUint32 numEntries = (PRUint32)-1;
rv = aCache->GetNumEntries(&numEntries);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get number of cache entries");
NS_ASSERTION(numEntries == testNum + 1, "GetNumEntries failure");
// Record meta-data should be initially empty
char *protocolDatap;
rv = cacheEntry->GetAnnotation("test data", &protocolDataLength, &protocolDatap);
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
if ((protocolDataLength != 0) || (protocolDatap != 0))
return NS_ERROR_FAILURE;
// Store random data as meta-data
randomStream->Read(protocolData, sizeof protocolData);
cacheEntry->SetAnnotation("test data", sizeof protocolData, protocolData);
// Store random data as allow-partial flag
PRBool allowPartial = randomStream->Next() & 1;
rv = cacheEntry->SetAllowPartial(allowPartial);
NS_ASSERTION(NS_SUCCEEDED(rv),
"nsICachedNetData::SetAllowPartial() failed");
// Store random data as expiration time
PRTime expirationTime = convertSecondsToPRTime(randomStream->Next() & 0xffffff);
rv = cacheEntry->SetExpirationTime(expirationTime);
NS_ASSERTION(NS_SUCCEEDED(rv),
"nsICachedNetData::SetExpirationTime() failed");
// Cache manager complains if expiration set without setting last-modified time
rv = cacheEntry->SetLastModifiedTime(expirationTime);
rv = cacheEntry->NewChannel(0, 0, getter_AddRefs(channel));
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
rv = cacheEntry->GetCache(getter_AddRefs(containingCache));
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
rv = channel->OpenOutputStream(0, getter_AddRefs(outStream));
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
int streamLength = randomStream->Next() % MAX_CONTENT_LENGTH;
int remaining = streamLength;
while (remaining) {
PRUint32 numWritten;
int amount = PR_MIN(sizeof buf, remaining);
randomStream->Read(buf, amount);
rv = outStream->Write(buf, amount, &numWritten);
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
NS_ASSERTION(numWritten == (PRUint32)amount, "Write() bug?");
remaining -= amount;
PRUint32 storageInUse;
rv = containingCache->GetStorageInUse(&storageInUse);
NS_ASSERTION(NS_SUCCEEDED(rv) && (storageInUse <= aCacheCapacity),
"Cache manager failed to limit cache growth");
}
outStream->Close();
gTotalBytesWritten += streamLength;
// *Now* there should be an entry in the cache
rv = aCache->Contains(cacheKey,
secondaryCacheKey, sizeof secondaryCacheKey,
aFlags, &inCache);
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
NS_ASSERTION(inCache, "nsINetDataCacheManager::Contains error");
delete randomStream;
}
PRIntervalTime endTime = PR_IntervalNow();
// Compute rate in MB/s
double rate = gTotalBytesWritten / PR_IntervalToMilliseconds(endTime - startTime);
rate *= 1000;
rate /= (1024 * 1024);
printf("Wrote %7d bytes at a rate of %5.1f MB per second \n",
gTotalBytesWritten, rate);
return NS_OK;
}
nsresult NS_AutoregisterComponents()
{
nsresult rv = nsComponentManager::AutoRegister(nsIComponentManager::NS_Startup,
NULL /* default */);
return rv;
}
nsresult
Test(nsINetDataCacheManager *aCache, PRUint32 aFlags, PRUint32 aCacheCapacity)
{
nsresult rv;
rv = aCache->RemoveAll();
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't clear cache");
PRUint32 numEntries = (PRUint32)-1;
rv = aCache->GetNumEntries(&numEntries);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get number of cache entries");
NS_ASSERTION(numEntries == 0, "Couldn't clear cache");
rv = FillCache(aCache, aFlags, aCacheCapacity);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't fill cache with random test data");
rv = TestRead(aCache, aFlags);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't read random test data from cache");
rv = aCache->RemoveAll();
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't clear cache");
rv = aCache->GetNumEntries(&numEntries);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get number of cache entries");
NS_ASSERTION(numEntries == 0, "Couldn't clear cache");
return 0;
}
int
main(int argc, char* argv[])
{
nsresult rv;
nsCOMPtr<nsINetDataCacheManager> cache;
rv = NS_AutoregisterComponents();
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't register XPCOM components");
rv = nsComponentManager::CreateInstance(NS_NETWORK_CACHE_MANAGER_PROGID,
nsnull,
NS_GET_IID(nsINetDataCacheManager),
getter_AddRefs(cache));
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't create cache manager factory") ;
cache->SetDiskCacheCapacity(DISK_CACHE_CAPACITY);
cache->SetMemCacheCapacity(MEM_CACHE_CAPACITY);
InitQueue();
Test(cache, nsINetDataCacheManager::BYPASS_PERSISTENT_CACHE, MEM_CACHE_CAPACITY);
Test(cache, nsINetDataCacheManager::BYPASS_MEMORY_CACHE, DISK_CACHE_CAPACITY);
return 0;
}

View File

@@ -0,0 +1,820 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "nsIStreamListener.h"
#include "nsIStreamObserver.h"
#include "nsIServiceManager.h"
#include "nsIInputStream.h"
#include "nsIOutputStream.h"
#include "nsIEventQueue.h"
#include "nsIEventQueueService.h"
#include "nsIChannel.h"
#include "nsCOMPtr.h"
#include "nsString.h"
#include <stdio.h>
#include "nsINetDataCache.h"
#include "nsINetDataDiskCache.h"
#include "nsINetDataCacheRecord.h"
#include "nsMemCacheCID.h"
// file cache include
#include "nsNetDiskCacheCID.h"
#include "nsIPref.h"
#include "prenv.h"
#include "nsIFileStream.h"
// Number of test entries to be placed in the cache
#define NUM_CACHE_ENTRIES 250
// Cache content stream length will have random length between zero and
// MAX_CONTENT_LENGTH bytes
#define MAX_CONTENT_LENGTH 20000
// Length of random-data cache entry key
#define CACHE_KEY_LENGTH 15
// Length of random-data cache entry meta-data
#define CACHE_METADATA_LENGTH 100
static NS_DEFINE_CID(kMemCacheCID, NS_MEM_CACHE_FACTORY_CID);
static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
// file cache cid
static NS_DEFINE_CID(kDiskCacheCID, NS_NETDISKCACHE_CID) ;
static NS_DEFINE_CID(kPrefCID, NS_PREF_CID);
static NS_DEFINE_IID(kIPrefIID, NS_IPREF_IID);
// Mapping from test case number to RecordID
static PRInt32 recordID[NUM_CACHE_ENTRIES];
static PRInt32
mapRecordIdToTestNum(PRInt32 aRecordID)
{
int i;
for (i = 0; i < NUM_CACHE_ENTRIES; i++) {
if (recordID[i] == aRecordID)
return i;
}
return -1;
}
// A supply of stream data to either store or compare with
class nsITestDataStream {
public:
virtual ~nsITestDataStream() {};
virtual PRUint32 Next() = 0;
virtual void Read(char* aBuf, PRUint32 aCount) = 0;
virtual PRBool Match(char* aBuf, PRUint32 aCount) = 0;
virtual void Skip(PRUint32 aCount) = 0;
};
// A reproducible stream of random data.
class RandomStream : public nsITestDataStream {
public:
RandomStream(PRUint32 aSeed) {
mStartSeed = mState = aSeed;
}
PRUint32 GetStartSeed() {
return mStartSeed;
}
PRUint32 Next() {
mState = 1103515245 * mState + 12345;
return mState;
}
void Read(char* aBuf, PRUint32 aCount) {
PRUint32 i;
for (i = 0; i < aCount; i++) {
*aBuf++ = Next();
}
}
PRBool
Match(char* aBuf, PRUint32 aCount) {
PRUint32 i;
for (i = 0; i < aCount; i++) {
if (*aBuf++ != (char)(Next() & 0xff))
return PR_FALSE;
}
return PR_TRUE;
}
void
Skip(PRUint32 aCount) {
while (aCount--)
Next();
}
protected:
PRUint32 mState;
PRUint32 mStartSeed;
};
// A stream of data that increments on each byte that is read, modulo 256
class CounterStream : public nsITestDataStream {
public:
CounterStream(PRUint32 aSeed) {
mStartSeed = mState = aSeed;
}
PRUint32 GetStartSeed() {
return mStartSeed;
}
PRUint32 Next() {
mState += 1;
mState &= 0xff;
return mState;
}
void Read(char* aBuf, PRUint32 aCount) {
PRUint32 i;
for (i = 0; i < aCount; i++) {
*aBuf++ = Next();
}
}
PRBool
Match(char* aBuf, PRUint32 aCount) {
PRUint32 i;
for (i = 0; i < aCount; i++) {
if (*aBuf++ != (char)Next())
return PR_FALSE;
}
return PR_TRUE;
}
void
Skip(PRUint32 aCount) {
mState += aCount;
mState &= 0xff;
}
protected:
PRUint32 mState;
PRUint32 mStartSeed;
};
static int gNumReaders = 0;
static PRUint32 gTotalBytesRead = 0;
static PRUint32 gTotalDuration = 0;
class nsReader : public nsIStreamListener {
public:
NS_DECL_ISUPPORTS
nsReader()
: mStartTime(0), mBytesRead(0)
{
NS_INIT_REFCNT();
gNumReaders++;
}
virtual ~nsReader() {
delete mTestDataStream;
gNumReaders--;
}
nsresult
Init(nsITestDataStream* aRandomStream, PRUint32 aExpectedStreamLength) {
mTestDataStream = aRandomStream;
mExpectedStreamLength = aExpectedStreamLength;
mRefCnt = 1;
return NS_OK;
}
NS_IMETHOD OnStartRequest(nsIChannel* channel,
nsISupports* context) {
mStartTime = PR_IntervalNow();
return NS_OK;
}
NS_IMETHOD OnDataAvailable(nsIChannel* channel,
nsISupports* context,
nsIInputStream *aIStream,
PRUint32 aSourceOffset,
PRUint32 aLength) {
char buf[1025];
while (aLength > 0) {
PRUint32 amt;
PRBool match;
aIStream->Read(buf, sizeof buf, &amt);
if (amt == 0) break;
aLength -= amt;
mBytesRead += amt;
match = mTestDataStream->Match(buf, amt);
NS_ASSERTION(match, "Stored data was corrupted on read");
}
return NS_OK;
}
NS_IMETHOD OnStopRequest(nsIChannel* channel,
nsISupports* context,
nsresult aStatus,
const PRUnichar* aMsg) {
PRIntervalTime endTime;
PRIntervalTime duration;
endTime = PR_IntervalNow();
duration = (endTime - mStartTime);
if (NS_FAILED(aStatus)) printf("channel failed.\n");
// printf("read %d bytes\n", mBytesRead);
NS_ASSERTION(mBytesRead == mExpectedStreamLength,
"Stream in cache is wrong length");
gTotalBytesRead += mBytesRead;
gTotalDuration += duration;
return NS_OK;
}
protected:
PRIntervalTime mStartTime;
PRUint32 mBytesRead;
nsITestDataStream* mTestDataStream;
PRUint32 mExpectedStreamLength;
};
NS_IMPL_ISUPPORTS2(nsReader, nsIStreamListener, nsIStreamObserver)
static nsIEventQueue* eventQueue;
nsresult
InitQueue() {
nsresult rv;
NS_WITH_SERVICE(nsIEventQueueService, eventQService, kEventQueueServiceCID, &rv);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get event queue service");
rv = eventQService->CreateThreadEventQueue();
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't create event queue");
rv = eventQService->GetThreadEventQueue(PR_CurrentThread(), &eventQueue);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get event queue for main thread");
return NS_OK;
}
// Process events until all streams are OnStopRequest'ed
nsresult
WaitForEvents() {
while (gNumReaders) {
eventQueue->ProcessPendingEvents();
}
return NS_OK;
}
// Read data for a single cache record and compare against testDataStream
nsresult
TestReadStream(nsINetDataCacheRecord *record, nsITestDataStream *testDataStream,
PRUint32 expectedStreamLength)
{
nsCOMPtr<nsIChannel> channel;
nsresult rv;
PRUint32 actualContentLength;
rv = record->NewChannel(0, getter_AddRefs(channel));
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
rv = record->GetStoredContentLength(&actualContentLength);
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
NS_ASSERTION(actualContentLength == expectedStreamLength,
"nsINetDataCacheRecord::GetContentLength() busted ?");
nsReader *reader = new nsReader;
rv = reader->Init(testDataStream, expectedStreamLength);
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
rv = channel->AsyncRead(0, -1, 0, reader);
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
reader->Release();
return NS_OK;
}
// Check that records can be retrieved using their record-ID, in addition
// to using the opaque key.
nsresult
TestRecordID(nsINetDataCache *cache)
{
nsresult rv;
nsCOMPtr<nsINetDataCacheRecord> record;
RandomStream *randomStream;
PRUint32 metaDataLength;
char cacheKey[CACHE_KEY_LENGTH];
char *metaData;
PRUint32 testNum;
PRBool match;
for (testNum = 0; testNum < NUM_CACHE_ENTRIES; testNum++) {
randomStream = new RandomStream(testNum);
randomStream->Read(cacheKey, sizeof cacheKey);
rv = cache->GetCachedNetDataByID(recordID[testNum], getter_AddRefs(record));
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't obtain record using record ID");
// Match against previously stored meta-data
rv = record->GetMetaData(&metaDataLength, &metaData);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get record meta-data");
match = randomStream->Match(metaData, metaDataLength);
NS_ASSERTION(match, "Meta-data corrupted or incorrect");
nsAllocator::Free(metaData);
delete randomStream;
}
return NS_OK;
}
// Check that all cache entries in the database are enumerated and that
// no duplicates appear.
nsresult
TestEnumeration(nsINetDataCache *cache)
{
nsresult rv;
nsCOMPtr<nsINetDataCacheRecord> record;
nsCOMPtr<nsISupports> tempISupports;
nsCOMPtr<nsISimpleEnumerator> iterator;
RandomStream *randomStream;
PRUint32 metaDataLength;
char cacheKey[CACHE_KEY_LENGTH];
char *metaData;
PRUint32 testNum;
PRBool match;
PRInt32 recID;
int numRecords = 0;
// Iterate over all records in the cache
rv = cache->NewCacheEntryIterator(getter_AddRefs(iterator));
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't create new cache entry iterator");
PRBool notDone;
while (1) {
// Done iterating ?
rv = iterator->HasMoreElements(&notDone);
if (NS_FAILED(rv)) return rv;
if (!notDone)
break;
// Get next record in iteration
rv = iterator->GetNext(getter_AddRefs(tempISupports));
NS_ASSERTION(NS_SUCCEEDED(rv), "iterator bustage");
record = do_QueryInterface(tempISupports);
numRecords++;
// Get record ID
rv = record->GetRecordID(&recID);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get Record ID");
testNum = mapRecordIdToTestNum(recID);
NS_ASSERTION(testNum != -1, "Corrupted Record ID ?");
// Erase mapping from table, so that duplicate enumerations are detected
recordID[testNum] = -1;
// Make sure stream matches test data
randomStream = new RandomStream(testNum);
randomStream->Read(cacheKey, sizeof cacheKey);
// Match against previously stored meta-data
rv = record->GetMetaData(&metaDataLength, &metaData);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get record meta-data");
match = randomStream->Match(metaData, metaDataLength);
NS_ASSERTION(match, "Meta-data corrupted or incorrect");
nsAllocator::Free(metaData);
delete randomStream;
}
NS_ASSERTION(numRecords == NUM_CACHE_ENTRIES, "Iteration bug");
return NS_OK;
}
// Read the test data that was written in FillCache(), checking for
// corruption, truncation.
nsresult
TestRead(nsINetDataCache *cache)
{
nsresult rv;
PRBool inCache;
nsCOMPtr<nsINetDataCacheRecord> record;
RandomStream *randomStream;
PRUint32 metaDataLength;
char cacheKey[CACHE_KEY_LENGTH];
char *metaData, *storedCacheKey;
PRUint32 testNum, storedCacheKeyLength;
PRBool match;
for (testNum = 0; testNum < NUM_CACHE_ENTRIES; testNum++) {
randomStream = new RandomStream(testNum);
randomStream->Read(cacheKey, sizeof cacheKey);
// Ensure that entry is in the cache
rv = cache->Contains(cacheKey, sizeof cacheKey, &inCache);
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
NS_ASSERTION(inCache, "nsINetDataCache::Contains error");
rv = cache->GetCachedNetData(cacheKey, sizeof cacheKey, getter_AddRefs(record));
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
// Match against previously stored meta-data
match = record->GetMetaData(&metaDataLength, &metaData);
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
match = randomStream->Match(metaData, metaDataLength);
NS_ASSERTION(match, "Meta-data corrupted or incorrect");
nsAllocator::Free(metaData);
// Test GetKey() method
rv = record->GetKey(&storedCacheKeyLength, &storedCacheKey);
NS_ASSERTION(NS_SUCCEEDED(rv) &&
(storedCacheKeyLength == sizeof cacheKey) &&
!memcmp(storedCacheKey, &cacheKey[0], sizeof cacheKey),
"nsINetDataCacheRecord::GetKey failed");
nsAllocator::Free(storedCacheKey);
PRUint32 expectedStreamLength = randomStream->Next() % MAX_CONTENT_LENGTH;
TestReadStream(record, randomStream, expectedStreamLength);
}
WaitForEvents();
// Compute rate in MB/s
double rate = gTotalBytesRead / PR_IntervalToMilliseconds(gTotalDuration);
rate *= NUM_CACHE_ENTRIES;
rate *= 1000;
rate /= (1024 * 1024);
printf("Read %d bytes at a rate of %5.1f MB per second \n",
gTotalBytesRead, rate);
return NS_OK;
}
// Repeatedly call SetStoredContentLength() on a cache entry and make
// read the stream's data to ensure that it's not corrupted by the effect
nsresult
TestTruncation(nsINetDataCache *cache)
{
nsresult rv;
nsCOMPtr<nsINetDataCacheRecord> record;
RandomStream *randomStream;
char cacheKey[CACHE_KEY_LENGTH];
randomStream = new RandomStream(0);
randomStream->Read(cacheKey, sizeof cacheKey);
rv = cache->GetCachedNetData(cacheKey, sizeof cacheKey, getter_AddRefs(record));
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
randomStream->Skip(CACHE_METADATA_LENGTH);
PRUint32 initialStreamLength = randomStream->Next() % MAX_CONTENT_LENGTH;
delete randomStream;
PRUint32 i;
PRUint32 delta = initialStreamLength / 64;
for (i = initialStreamLength; i >= delta; i -= delta) {
PRUint32 expectedStreamLength = i;
// Do the truncation
record->SetStoredContentLength(expectedStreamLength);
randomStream = new RandomStream(0);
randomStream->Skip(CACHE_KEY_LENGTH + CACHE_METADATA_LENGTH + 1);
PRUint32 afterContentLength;
rv = record->GetStoredContentLength(&afterContentLength);
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
NS_ASSERTION(afterContentLength == expectedStreamLength,
"nsINetDataCacheRecord::SetContentLength() failed to truncate record");
TestReadStream(record, randomStream, expectedStreamLength);
WaitForEvents();
}
return NS_OK;
}
// Write known data to random offsets in a single cache entry and test
// resulting stream for correctness.
nsresult
TestOffsetWrites(nsINetDataCache *cache)
{
nsresult rv;
nsCOMPtr<nsINetDataCacheRecord> record;
nsCOMPtr<nsIChannel> channel;
nsCOMPtr<nsIOutputStream> outStream;
char buf[512];
char cacheKey[CACHE_KEY_LENGTH];
RandomStream *randomStream;
randomStream = new RandomStream(0);
randomStream->Read(cacheKey, sizeof cacheKey);
rv = cache->GetCachedNetData(cacheKey, sizeof cacheKey, getter_AddRefs(record));
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't access record via opaque cache key");
// Write buffer-fulls of data at random offsets into the cache entry.
// Data written is (offset % 0xff)
PRUint32 startingOffset;
PRUint32 streamLength = 0;
CounterStream *counterStream;
int i;
for (i = 0; i < 100; i++) {
rv = record->NewChannel(0, getter_AddRefs(channel));
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
startingOffset = streamLength ? streamLength - (randomStream->Next() % sizeof buf): 0;
rv = channel->OpenOutputStream(startingOffset, getter_AddRefs(outStream));
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
counterStream = new CounterStream(startingOffset);
counterStream->Read(buf, sizeof buf);
PRUint32 numWritten;
rv = outStream->Write(buf, sizeof buf, &numWritten);
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
NS_ASSERTION(numWritten == sizeof buf, "Write() bug?");
streamLength = startingOffset + sizeof buf;
rv = outStream->Close();
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't close channel");
delete counterStream;
}
delete randomStream;
counterStream = new CounterStream(0);
TestReadStream(record, counterStream, streamLength);
WaitForEvents();
return NS_OK;
}
// Create entries in the network data cache, using random data for the
// key, the meta-data and the stored content data.
nsresult
FillCache(nsINetDataCache *cache)
{
nsresult rv;
PRBool inCache;
nsCOMPtr<nsINetDataCacheRecord> record;
nsCOMPtr<nsIChannel> channel;
nsCOMPtr<nsIOutputStream> outStream;
char buf[1000];
PRUint32 metaDataLength;
char cacheKey[CACHE_KEY_LENGTH];
char metaData[CACHE_METADATA_LENGTH];
PRUint32 testNum;
char *data;
RandomStream *randomStream;
PRUint32 totalBytesWritten = 0;
PRIntervalTime startTime = PR_IntervalNow();
for (testNum = 0; testNum < NUM_CACHE_ENTRIES; testNum++) {
randomStream = new RandomStream(testNum);
randomStream->Read(cacheKey, sizeof cacheKey);
// No entry should be in cache until we add it
rv = cache->Contains(cacheKey, sizeof cacheKey, &inCache);
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
NS_ASSERTION(!inCache, "nsINetDataCache::Contains error");
rv = cache->GetCachedNetData(cacheKey, sizeof cacheKey, getter_AddRefs(record));
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't access record via opaque cache key");
// Test nsINetDataCacheRecord::GetRecordID()
rv = record->GetRecordID(&recordID[testNum]);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get Record ID");
// Test nsINetDataCache::GetNumEntries()
PRUint32 numEntries = (PRUint32)-1;
rv = cache->GetNumEntries(&numEntries);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get number of cache entries");
NS_ASSERTION(numEntries == testNum + 1, "GetNumEntries failure");
// Record meta-data should be initially empty
rv = record->GetMetaData(&metaDataLength, &data);
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
if ((metaDataLength != 0) || (data != 0))
return NS_ERROR_FAILURE;
// Store random data as meta-data
randomStream->Read(metaData, sizeof metaData);
record->SetMetaData(sizeof metaData, metaData);
rv = record->NewChannel(0, getter_AddRefs(channel));
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
rv = channel->OpenOutputStream(0, getter_AddRefs(outStream));
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
PRUint32 beforeOccupancy;
rv = cache->GetStorageInUse(&beforeOccupancy);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get cache occupancy");
int streamLength = randomStream->Next() % MAX_CONTENT_LENGTH;
int remaining = streamLength;
while (remaining) {
PRUint32 numWritten;
int amount = PR_MIN(sizeof buf, remaining);
randomStream->Read(buf, amount);
rv = outStream->Write(buf, amount, &numWritten);
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
NS_ASSERTION(numWritten == (PRUint32)amount, "Write() bug?");
remaining -= amount;
}
outStream->Close();
totalBytesWritten += streamLength;
PRUint32 afterOccupancy;
rv = cache->GetStorageInUse(&afterOccupancy);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get cache occupancy");
PRUint32 streamLengthInKB = streamLength >> 10;
NS_ASSERTION((afterOccupancy - beforeOccupancy) >= streamLengthInKB,
"nsINetDataCache::GetStorageInUse() is busted");
// *Now* there should be an entry in the cache
rv = cache->Contains(cacheKey, sizeof cacheKey, &inCache);
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
NS_ASSERTION(inCache, "nsINetDataCache::Contains error");
delete randomStream;
}
PRIntervalTime endTime = PR_IntervalNow();
// Compute rate in MB/s
double rate = totalBytesWritten / PR_IntervalToMilliseconds(endTime - startTime);
rate *= 1000;
rate /= (1024 * 1024);
printf("Wrote %7d bytes at a rate of %5.1f MB per second \n",
totalBytesWritten, rate);
return NS_OK;
}
nsresult NS_AutoregisterComponents()
{
nsresult rv = nsComponentManager::AutoRegister(nsIComponentManager::NS_Startup,
NULL /* default */);
return rv;
}
PRBool initPref ()
{
nsresult rv;
NS_WITH_SERVICE(nsIPref, prefPtr, kPrefCID, &rv);
if (NS_FAILED(rv))
return false;
nsCOMPtr<nsIFileSpec> fileSpec;
rv = NS_NewFileSpec (getter_AddRefs(fileSpec));
if (NS_FAILED(rv))
return false;
nsCString defaultPrefFile = PR_GetEnv ("MOZILLA_FIVE_HOME");
if (defaultPrefFile.Length())
defaultPrefFile += "/";
else
defaultPrefFile = "./";
defaultPrefFile += "default_prefs.js";
fileSpec->SetUnixStyleFilePath (defaultPrefFile.GetBuffer());
PRBool exists = false;
fileSpec->Exists(&exists);
if (exists)
prefPtr->ReadUserPrefsFrom(fileSpec);
else
return false;
return true;
}
int
main(int argc, char* argv[])
{
nsresult rv;
if(argc <2) {
printf(" %s -f to test filecache\n", argv[0]) ;
printf(" %s -m to test memcache\n", argv[0]) ;
return -1 ;
}
rv = NS_AutoregisterComponents();
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't register XPCOM components");
nsCOMPtr<nsINetDataCache> cache;
if (PL_strcasecmp(argv[1], "-m") == 0) {
rv = nsComponentManager::CreateInstance(kMemCacheCID, nsnull,
NS_GET_IID(nsINetDataCache),
getter_AddRefs(cache));
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't create memory cache factory");
} else if (PL_strcasecmp(argv[1], "-f") == 0) {
nsCOMPtr<nsINetDataDiskCache> diskcache ;
rv = nsComponentManager::CreateInstance(kDiskCacheCID, nsnull,
NS_GET_IID(nsINetDataDiskCache),
getter_AddRefs(diskcache));
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't create disk cache factory") ;
nsCOMPtr<nsIFileSpec> folder ;
NS_NewFileSpec(getter_AddRefs(folder)) ;
folder->SetUnixStyleFilePath("/tmp") ;
diskcache->SetDiskCacheFolder(folder) ;
cache = diskcache ;
} else {
printf(" %s -f to test filecache\n", argv[0]) ;
printf(" %s -m to test memcache\n", argv[0]) ;
return -1 ;
}
InitQueue();
PRUnichar* description;
rv = cache->GetDescription(&description);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get cache description");
nsCAutoString descStr(description);
printf("Testing: %s\n", descStr.GetBuffer());
rv = cache->RemoveAll();
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't clear cache");
PRUint32 startOccupancy;
rv = cache->GetStorageInUse(&startOccupancy);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get cache occupancy");
PRUint32 numEntries = (PRUint32)-1;
rv = cache->GetNumEntries(&numEntries);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get number of cache entries");
NS_ASSERTION(numEntries == 0, "Couldn't clear cache");
rv = FillCache(cache);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't fill cache with random test data");
rv = TestRead(cache);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't read random test data from cache");
rv = TestRecordID(cache);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't index records using record ID");
rv = TestEnumeration(cache);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't successfully enumerate records");
rv = TestTruncation(cache);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't successfully truncate records");
rv = TestOffsetWrites(cache);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't successfully write to records using non-zero offsets");
rv = cache->RemoveAll();
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't clear cache");
rv = cache->GetNumEntries(&numEntries);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get number of cache entries");
NS_ASSERTION(numEntries == 0, "Couldn't clear cache");
PRUint32 endOccupancy;
rv = cache->GetStorageInUse(&endOccupancy);
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get cache occupancy");
NS_ASSERTION(startOccupancy == endOccupancy, "Cache occupancy not correctly computed ?");
return 0;
}

View File

@@ -0,0 +1,82 @@
#!nmake
#
# The contents of this file are subject to the Netscape Public
# License Version 1.1 (the "License"); you may not use this file
# except in compliance with the License. You may obtain a copy of
# the License at http://www.mozilla.org/NPL/
#
# Software distributed under the License is distributed on an "AS
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
# implied. See the License for the specific language governing
# rights and limitations under the License.
#
# The Original Code is mozilla.org code.
#
# The Initial Developer of the Original Code is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s):
DEPTH=..\..
MAKE_OBJ_TYPE = EXE
PROG1 = .\$(OBJDIR)\TestFileInput.exe
PROG2 = .\$(OBJDIR)\TestSocketInput.exe
PROG3 = .\$(OBJDIR)\TestSocketIO.exe
PROG4 = .\$(OBJDIR)\TestProtocols.exe
PROG5 = .\$(OBJDIR)\TestSocketTransport.exe
PROG6 = .\$(OBJDIR)\urltest.exe
PROG7 = .\$(OBJDIR)\TestFileInput2.exe
PROG8 = .\$(OBJDIR)\TestFileTransport.exe
PROG9 = .\$(OBJDIR)\TestRes.exe
PROGA = .\$(OBJDIR)\TestRawCache.exe
PROGB = .\$(OBJDIR)\TestCacheMgr.exe
PROGRAMS = \
#$(PROG1) $(PROG2) $(PROG3) $(PROG4) $(PROG5) $(PROG6) $(PROG7) $(PROG8) $(PROG9)\
$(PROGA) $(PROGB)
LCFLAGS=-DUSE_NSREG -GX
REQUIRES=libreg
INCS = $(INCS) \
-I$(DEPTH)\dist\include \
$(NULL)
LLIBS= \
$(DIST)\lib\xpcom.lib \
$(LIBNSPR) \
$(NULL)
include <$(DEPTH)\config\rules.mak>
install:: $(PROGRAMS)
-for %p in ($(PROGRAMS)) do $(MAKE_INSTALL) %p $(DIST)\bin
clobber::
-for %p in ($(PROGRAMS)) do $(RM) %p $(DIST)\bin\%p
$(PROG1): $(OBJDIR) TestFileInput.cpp
$(PROG2): $(OBJDIR) TestSocketInput.cpp
$(PROG3): $(OBJDIR) TestSocketIO.cpp
$(PROG4): $(OBJDIR) TestProtocols.cpp
$(PROG5): $(OBJDIR) TestSocketTransport.cpp
$(PROG6): $(OBJDIR) urltest.cpp
$(PROG7): $(OBJDIR) TestFileInput2.cpp
$(PROG8): $(OBJDIR) TestFileTransport.cpp
$(PROG9): $(OBJDIR) TestRes.cpp
$(PROGA): $(OBJDIR) TestRawCache.cpp
$(PROGB): $(OBJDIR) TestCacheMgr.cpp

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,226 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
#ifndef nsError_h
#define nsError_h
#ifndef prtypes_h___
#include "prtypes.h"
#endif
/**
* Generic result data type
*/
typedef PRUint32 nsresult;
/*
* To add error code to your module, you need to do the following:
*
* 1) Add a module offset code. Add yours to the bottom of the list
* right below this comment, adding 1.
*
* 2) In your module, define a header file which uses one of the
* NE_ERROR_GENERATExxxxxx macros. Some examples below:
*
* #define NS_ERROR_MYMODULE_MYERROR1 NS_ERROR_GENERATE(NS_ERROR_SEVERITY_ERROR,NS_ERROR_MODULE_MYMODULE,1)
* #define NS_ERROR_MYMODULE_MYERROR2 NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_MYMODULE,2)
* #define NS_ERROR_MYMODULE_MYERROR3 NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_MYMODULE,3)
*
*/
/**
* @name Standard Module Offset Code. Each Module should identify a unique number
* and then all errors associated with that module become offsets from the
* base associated with that module id. There are 16 bits of code bits for
* each module.
*/
#define NS_ERROR_MODULE_XPCOM 1
#define NS_ERROR_MODULE_BASE 2
#define NS_ERROR_MODULE_GFX 3
#define NS_ERROR_MODULE_WIDGET 4
#define NS_ERROR_MODULE_CALENDAR 5
#define NS_ERROR_MODULE_NETWORK 6
#define NS_ERROR_MODULE_PLUGINS 7
#define NS_ERROR_MODULE_LAYOUT 8
#define NS_ERROR_MODULE_HTMLPARSER 9
#define NS_ERROR_MODULE_RDF 10
#define NS_ERROR_MODULE_UCONV 11
#define NS_ERROR_MODULE_REG 12
#define NS_ERROR_MODULE_FILES 13
#define NS_ERROR_MODULE_DOM 14
#define NS_ERROR_MODULE_IMGLIB 15
#define NS_ERROR_MODULE_MAILNEWS 16
#define NS_ERROR_MODULE_EDITOR 17
#define NS_ERROR_MODULE_XPCONNECT 18
/**
* @name Standard Error Handling Macros
*/
#define NS_FAILED(_nsresult) ((_nsresult) & 0x80000000)
#define NS_SUCCEEDED(_nsresult) (!((_nsresult) & 0x80000000))
/**
* @name Severity Code. This flag identifies the level of warning
*/
#define NS_ERROR_SEVERITY_SUCCESS 0
#define NS_ERROR_SEVERITY_ERROR 1
/**
* @name Mozilla Code. This flag separates consumers of mozilla code
* from the native platform
*/
#define NS_ERROR_MODULE_BASE_OFFSET 0x45
/**
* @name Standard Error Generating Macros
*/
#define NS_ERROR_GENERATE(sev,module,code) \
((nsresult) (((PRUint32)(sev)<<31) | ((PRUint32)(module+NS_ERROR_MODULE_BASE_OFFSET)<<16) | ((PRUint32)(code))) )
#define NS_ERROR_GENERATE_SUCCESS(module,code) \
((nsresult) (((PRUint32)(NS_ERROR_SEVERITY_SUCCESS)<<31) | ((PRUint32)(module+NS_ERROR_MODULE_BASE_OFFSET)<<16) | ((PRUint32)(code))) )
#define NS_ERROR_GENERATE_FAILURE(module,code) \
((nsresult) (((PRUint32)(NS_ERROR_SEVERITY_ERROR)<<31) | ((PRUint32)(module+NS_ERROR_MODULE_BASE_OFFSET)<<16) | ((PRUint32)(code))) )
/**
* @name Standard Macros for retrieving error bits
*/
#define NS_ERROR_GET_CODE(err) ((err) & 0xffff)
#define NS_ERROR_GET_MODULE(err) (((((err) >> 16) - NS_ERROR_MODULE_BASE_OFFSET) & 0x1fff))
#define NS_ERROR_GET_SEVERITY(err) (((err) >> 31) & 0x1)
/**
* @name Standard return values
*/
/*@{*/
/* Standard "it worked" return value */
#define NS_OK 0
/* The backwards COM false */
#define NS_COMFALSE 1
#define NS_ERROR_BASE ((nsresult) 0xC1F30000)
/* Returned when an instance is not initialized */
#define NS_ERROR_NOT_INITIALIZED (NS_ERROR_BASE + 1)
/* Returned when an instance is already initialized */
#define NS_ERROR_ALREADY_INITIALIZED (NS_ERROR_BASE + 2)
/* Returned by a not implemented function */
#define NS_ERROR_NOT_IMPLEMENTED ((nsresult) 0x80004001L)
/* Returned when a given interface is not supported. */
#define NS_NOINTERFACE ((nsresult) 0x80004002L)
#define NS_ERROR_NO_INTERFACE NS_NOINTERFACE
#define NS_ERROR_INVALID_POINTER ((nsresult) 0x80004003L)
#define NS_ERROR_NULL_POINTER NS_ERROR_INVALID_POINTER
/* Returned when a function aborts */
#define NS_ERROR_ABORT ((nsresult) 0x80004004L)
/* Returned when a function fails */
#define NS_ERROR_FAILURE ((nsresult) 0x80004005L)
/* Returned when an unexpected error occurs */
#define NS_ERROR_UNEXPECTED ((nsresult) 0x8000ffffL)
/* Returned when a memory allocation failes */
#define NS_ERROR_OUT_OF_MEMORY ((nsresult) 0x8007000eL)
/* Returned when an illegal value is passed */
#define NS_ERROR_ILLEGAL_VALUE ((nsresult) 0x80070057L)
#define NS_ERROR_INVALID_ARG NS_ERROR_ILLEGAL_VALUE
/* Returned when a class doesn't allow aggregation */
#define NS_ERROR_NO_AGGREGATION ((nsresult) 0x80040110L)
/* Returned when an operation can't complete due to an unavailable resource */
#define NS_ERROR_NOT_AVAILABLE ((nsresult) 0x80040111L)
/* Returned when a class is not registered */
#define NS_ERROR_FACTORY_NOT_REGISTERED ((nsresult) 0x80040154L)
/* Returned when a class cannot be registered, but may be tried again later */
#define NS_ERROR_FACTORY_REGISTER_AGAIN ((nsresult) 0x80040155L)
/* Returned when a dynamically loaded factory couldn't be found */
#define NS_ERROR_FACTORY_NOT_LOADED ((nsresult) 0x800401f8L)
/* Returned when a factory doesn't support signatures */
#define NS_ERROR_FACTORY_NO_SIGNATURE_SUPPORT \
(NS_ERROR_BASE + 0x101)
/* Returned when a factory already is registered */
#define NS_ERROR_FACTORY_EXISTS (NS_ERROR_BASE + 0x100)
/* For COM compatibility reasons, we want to use exact error code numbers
for NS_ERROR_PROXY_INVALID_IN_PARAMETER and NS_ERROR_PROXY_INVALID_OUT_PARAMETER.
The first matches:
#define RPC_E_INVALID_PARAMETER _HRESULT_TYPEDEF_(0x80010010L)
Errors returning this mean that the xpcom proxy code could not create a proxy for
one of the in paramaters.
Because of this, we are ignoring the convention if using a base and offset for
error numbers.
*/
/* Returned when a proxy could not be create a proxy for one of the IN parameters
This is returned only when the "real" meathod has NOT been invoked.
*/
#define NS_ERROR_PROXY_INVALID_IN_PARAMETER ((nsresult) 0x80010010L)
/* Returned when a proxy could not be create a proxy for one of the OUT parameters
This is returned only when the "real" meathod has ALREADY been invoked.
*/
#define NS_ERROR_PROXY_INVALID_OUT_PARAMETER ((nsresult) 0x80010011L)
/*@}*/
////////////////////////////////////////////////////////////////////////////////
#ifdef XP_PC
#pragma warning(disable: 4251) // 'nsCOMPtr<class nsIInputStream>' needs to have dll-interface to be used by clients of class 'nsInputStream'
#pragma warning(disable: 4275) // non dll-interface class 'nsISupports' used as base for dll-interface class 'nsIRDFNode'
#endif
#endif

View File

@@ -0,0 +1,126 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
// Force references to all of the symbols that we want exported from
// the dll that are located in the .lib files we link with
#include "nsVoidArray.h"
#include "nsIAtom.h"
#include "nsFileSpec.h"
//#include "nsIBuffer.h"
//#include "nsIByteBufferInputStream.h"
#include "nsFileStream.h"
#include "nsFileSpecStreaming.h"
#include "nsSpecialSystemDirectory.h"
#include "nsIThread.h"
#include "nsDeque.h"
#include "nsObserver.h"
#include "nsTraceRefcnt.h"
#include "nsXPIDLString.h"
#include "nsIEnumerator.h"
#include "nsEnumeratorUtils.h"
#include "nsQuickSort.h"
#include "nsString2.h"
#include "nsProxyEventPrivate.h"
#include "xpt_xdr.h"
#include "nsInterfaceInfo.h"
#include "xptcall.h"
#include "nsIFileSpec.h"
#include "nsIGenericFactory.h"
#include "nsAVLTree.h"
#include "nsHashtableEnumerator.h"
#include "nsPipe2.h"
#include "nsCWeakReference.h"
#include "nsWeakReference.h"
#include "nsISizeOfHandler.h"
#include "nsTextFormater.h"
#include "nsStorageStream.h"
#include "nsIBinaryInputStream.h"
#ifdef DEBUG
#include "pure.h"
#endif
class dummyComparitor: public nsAVLNodeComparitor {
public:
virtual PRInt32 operator()(void* anItem1,void* anItem2)
{
return 0;
}
};
#ifdef DEBUG
extern NS_COM void
TestSegmentedBuffer();
#endif
void XXXNeverCalled()
{
nsTextFormater::snprintf(nsnull,0,nsnull);
dummyComparitor dummy;
nsVoidArray();
nsAVLTree(dummy, nsnull);
NS_GetNumberOfAtoms();
nsFileURL(NULL);
// NS_NewPipe(NULL, NULL, 0, 0, 0, NULL);
NS_NewPipe(NULL, NULL, NULL, 0, 0);
nsFileSpec s;
NS_NewIOFileStream(NULL, s, 0, 0);
nsInputFileStream(s, 0, 0);
nsPersistentFileDescriptor d;
ReadDescriptor(NULL, d);
new nsSpecialSystemDirectory(nsSpecialSystemDirectory::OS_DriveDirectory);
nsIThread::GetCurrent(NULL);
nsDeque(NULL);
NS_NewObserver(NULL, NULL);
nsTraceRefcnt::DumpStatistics();
nsXPIDLCString::Copy(NULL);
NS_NewEmptyEnumerator(NULL);
nsArrayEnumerator(NULL);
NS_NewIntersectionEnumerator(NULL, NULL, NULL);
NS_QuickSort(NULL, 0, 0, NULL, NULL);
nsString2();
nsProxyObject(NULL, 0, NULL);
XPT_DoString(NULL, NULL);
XPT_DoHeader(NULL, NULL);
nsInterfaceInfo* info = NULL;
info->GetName(NULL);
#ifdef DEBUG
info->print(NULL);
PurePrintf(0);
#endif
XPTC_InvokeByIndex(NULL, 0, 0, NULL);
NS_NewFileSpec(NULL);
xptc_dummy();
xptc_dummy2();
XPTI_GetInterfaceInfoManager();
NS_NewGenericFactory(NULL, NULL, NULL);
NS_NewHashtableEnumerator(NULL, NULL, NULL, NULL);
nsCWeakProxy(0, 0);
nsCWeakReferent(0);
NS_GetWeakReference(NULL);
#ifdef DEBUG
TestSegmentedBuffer();
#endif
NS_NewSizeOfHandler(0);
nsStorageStream();
NS_NewBinaryInputStream(0, 0);
}

View File

@@ -0,0 +1,170 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
#ifndef nsIGenericFactory_h___
#define nsIGenericFactory_h___
#include "nsIFactory.h"
// {3bc97f01-ccdf-11d2-bab8-b548654461fc}
#define NS_GENERICFACTORY_CID \
{ 0x3bc97f01, 0xccdf, 0x11d2, { 0xba, 0xb8, 0xb5, 0x48, 0x65, 0x44, 0x61, 0xfc } }
// {3bc97f00-ccdf-11d2-bab8-b548654461fc}
#define NS_IGENERICFACTORY_IID \
{ 0x3bc97f00, 0xccdf, 0x11d2, { 0xba, 0xb8, 0xb5, 0x48, 0x65, 0x44, 0x61, 0xfc } }
#define NS_GENERICFACTORY_PROGID "component:/netscape/generic-factory"
#define NS_GENERICFACTORY_CLASSNAME "Generic Factory"
/**
* Provides a Generic nsIFactory implementation that can be used by
* DLLs with very simple factory needs.
*/
class nsIGenericFactory : public nsIFactory {
public:
static const nsIID& GetIID() { static nsIID iid = NS_IGENERICFACTORY_IID; return iid; }
typedef NS_CALLBACK(ConstructorProcPtr) (nsISupports *aOuter, REFNSIID aIID, void **aResult);
typedef NS_CALLBACK(DestructorProcPtr) (void);
/**
* Establishes the generic factory's constructor function, which will be called
* by CreateInstance.
*/
NS_IMETHOD SetConstructor(ConstructorProcPtr constructor) = 0;
/**
* Establishes the generic factory's destructor function, which will be called
* whe the generic factory is deleted. This is used to notify the DLL that
* an instance of one of its generic factories is going away.
*/
NS_IMETHOD SetDestructor(DestructorProcPtr destructor) = 0;
};
extern NS_COM nsresult
NS_NewGenericFactory(nsIGenericFactory* *result,
nsIGenericFactory::ConstructorProcPtr constructor,
nsIGenericFactory::DestructorProcPtr destructor = NULL);
////////////////////////////////////////////////////////////////////////////////
// Generic Modules
//
// (See xpcom/sample/nsSampleModule.cpp to see how to use this.)
#include "nsIModule.h"
/**
* Use this type to define a list of module component info to pass to
* NS_NewGenericModule. E.g.:
* static nsModuleComponentInfo components[] = { ... };
* See xpcom/sample/nsSampleModule.cpp for more info.
*/
struct nsModuleComponentInfo {
const char* mDescription;
nsCID mCID;
const char* mProgID;
nsIGenericFactory::ConstructorProcPtr mConstructor;
};
extern NS_COM nsresult
NS_NewGenericModule(const char* moduleName,
PRUint32 componentCount,
nsModuleComponentInfo* components,
nsIModule* *result);
#define NS_IMPL_NSGETMODULE(_name, _components) \
extern "C" NS_EXPORT nsresult NSGetModule(nsIComponentManager *servMgr, \
nsIFileSpec* location, \
nsIModule** result) \
{ \
return NS_NewGenericModule((_name), \
sizeof(_components) / sizeof(_components[0]), \
(_components), result); \
}
////////////////////////////////////////////////////////////////////////////////
#define NS_GENERIC_FACTORY_CONSTRUCTOR(_InstanceClass) \
static NS_IMETHODIMP \
_InstanceClass##Constructor(nsISupports *aOuter, REFNSIID aIID, void **aResult) \
{ \
nsresult rv; \
\
_InstanceClass * inst; \
\
if (NULL == aResult) { \
rv = NS_ERROR_NULL_POINTER; \
return rv; \
} \
*aResult = NULL; \
if (NULL != aOuter) { \
rv = NS_ERROR_NO_AGGREGATION; \
return rv; \
} \
\
NS_NEWXPCOM(inst, _InstanceClass); \
if (NULL == inst) { \
rv = NS_ERROR_OUT_OF_MEMORY; \
return rv; \
} \
NS_ADDREF(inst); \
rv = inst->QueryInterface(aIID, aResult); \
NS_RELEASE(inst); \
\
return rv; \
} \
#define NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(_InstanceClass, _InitMethod) \
static NS_IMETHODIMP \
_InstanceClass##Constructor(nsISupports *aOuter, REFNSIID aIID, void **aResult) \
{ \
nsresult rv; \
\
_InstanceClass * inst; \
\
if (NULL == aResult) { \
rv = NS_ERROR_NULL_POINTER; \
return rv; \
} \
*aResult = NULL; \
if (NULL != aOuter) { \
rv = NS_ERROR_NO_AGGREGATION; \
return rv; \
} \
\
NS_NEWXPCOM(inst, _InstanceClass); \
if (NULL == inst) { \
rv = NS_ERROR_OUT_OF_MEMORY; \
return rv; \
} \
NS_ADDREF(inst); \
rv = inst->_InitMethod(); \
if(NS_SUCCEEDED(rv)) { \
rv = inst->QueryInterface(aIID, aResult); \
} \
NS_RELEASE(inst); \
\
return rv; \
} \
#endif /* nsIGenericFactory_h___ */

View File

@@ -0,0 +1,521 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
#include "prmem.h"
#include "prlog.h"
#include "nsHashtable.h"
//
// Key operations
//
static PR_CALLBACK PLHashNumber _hashValue(const void *key)
{
return ((const nsHashKey *) key)->HashValue();
}
static PR_CALLBACK PRIntn _hashKeyCompare(const void *key1, const void *key2) {
return ((const nsHashKey *) key1)->Equals((const nsHashKey *) key2);
}
static PR_CALLBACK PRIntn _hashValueCompare(const void *value1,
const void *value2) {
// We're not going to make any assumptions about value equality
return 0;
}
//
// Memory callbacks
//
static PR_CALLBACK void *_hashAllocTable(void *pool, PRSize size) {
return PR_MALLOC(size);
}
static PR_CALLBACK void _hashFreeTable(void *pool, void *item) {
PR_DELETE(item);
}
static PR_CALLBACK PLHashEntry *_hashAllocEntry(void *pool, const void *key) {
return PR_NEW(PLHashEntry);
}
static PR_CALLBACK void _hashFreeEntry(void *pool, PLHashEntry *entry,
PRUintn flag) {
if (flag == HT_FREE_ENTRY) {
delete (nsHashKey *) (entry->key);
PR_DELETE(entry);
}
}
static PLHashAllocOps _hashAllocOps = {
_hashAllocTable, _hashFreeTable,
_hashAllocEntry, _hashFreeEntry
};
//
// Enumerator callback
//
struct _HashEnumerateArgs {
nsHashtableEnumFunc fn;
void* arg;
};
static PR_CALLBACK PRIntn _hashEnumerate(PLHashEntry *he, PRIntn i, void *arg)
{
_HashEnumerateArgs* thunk = (_HashEnumerateArgs*)arg;
return thunk->fn((nsHashKey *) he->key, he->value, thunk->arg)
? HT_ENUMERATE_NEXT
: HT_ENUMERATE_STOP;
}
//
// HashKey
//
nsHashKey::nsHashKey(void)
{
}
nsHashKey::~nsHashKey(void)
{
}
nsHashtable::nsHashtable(PRUint32 aInitSize, PRBool threadSafe)
: mLock(NULL)
{
hashtable = PL_NewHashTable(aInitSize,
_hashValue,
_hashKeyCompare,
_hashValueCompare,
&_hashAllocOps,
NULL);
if (threadSafe == PR_TRUE)
{
mLock = PR_NewLock();
if (mLock == NULL)
{
// Cannot create a lock. If running on a multiprocessing system
// we are sure to die.
PR_ASSERT(mLock != NULL);
}
}
}
nsHashtable::~nsHashtable() {
PL_HashTableDestroy(hashtable);
if (mLock) PR_DestroyLock(mLock);
}
PRBool nsHashtable::Exists(nsHashKey *aKey)
{
PLHashNumber hash = aKey->HashValue();
if (mLock) PR_Lock(mLock);
PLHashEntry **hep = PL_HashTableRawLookup(hashtable, hash, (void *) aKey);
if (mLock) PR_Unlock(mLock);
return *hep != NULL;
}
void *nsHashtable::Put(nsHashKey *aKey, void *aData) {
void *res = NULL;
PLHashNumber hash = aKey->HashValue();
PLHashEntry *he;
if (mLock) PR_Lock(mLock);
PLHashEntry **hep = PL_HashTableRawLookup(hashtable, hash, (void *) aKey);
if ((he = *hep) != NULL) {
res = he->value;
he->value = aData;
} else {
PL_HashTableRawAdd(hashtable, hep, hash,
(void *) aKey->Clone(), aData);
}
if (mLock) PR_Unlock(mLock);
return res;
}
void *nsHashtable::Get(nsHashKey *aKey) {
if (mLock) PR_Lock(mLock);
void *ret = PL_HashTableLookup(hashtable, (void *) aKey);
if (mLock) PR_Unlock(mLock);
return ret;
}
void *nsHashtable::Remove(nsHashKey *aKey) {
PLHashNumber hash = aKey->HashValue();
PLHashEntry *he;
if (mLock) PR_Lock(mLock);
PLHashEntry **hep = PL_HashTableRawLookup(hashtable, hash, (void *) aKey);
void *res = NULL;
if ((he = *hep) != NULL) {
res = he->value;
PL_HashTableRawRemove(hashtable, hep, he);
}
if (mLock) PR_Unlock(mLock);
return res;
}
// XXX This method was called _hashEnumerateCopy, but it didn't copy the element!
// I don't know how this was supposed to work since the elements are neither copied
// nor refcounted.
static PR_CALLBACK PRIntn _hashEnumerateShare(PLHashEntry *he, PRIntn i, void *arg)
{
nsHashtable *newHashtable = (nsHashtable *)arg;
newHashtable->Put((nsHashKey *) he->key, he->value);
return HT_ENUMERATE_NEXT;
}
nsHashtable * nsHashtable::Clone() {
PRBool threadSafe = PR_FALSE;
if (mLock)
threadSafe = PR_TRUE;
nsHashtable *newHashTable = new nsHashtable(hashtable->nentries, threadSafe);
PL_HashTableEnumerateEntries(hashtable, _hashEnumerateShare, newHashTable);
return newHashTable;
}
void nsHashtable::Enumerate(nsHashtableEnumFunc aEnumFunc, void* closure) {
_HashEnumerateArgs thunk;
thunk.fn = aEnumFunc;
thunk.arg = closure;
PL_HashTableEnumerateEntries(hashtable, _hashEnumerate, &thunk);
}
static PR_CALLBACK PRIntn _hashEnumerateRemove(PLHashEntry *he, PRIntn i, void *arg)
{
_HashEnumerateArgs* thunk = (_HashEnumerateArgs*)arg;
if (thunk)
return thunk->fn((nsHashKey *) he->key, he->value, thunk->arg)
? HT_ENUMERATE_REMOVE
: HT_ENUMERATE_STOP;
else
return HT_ENUMERATE_REMOVE;
}
void nsHashtable::Reset() {
Reset(NULL);
}
void nsHashtable::Reset(nsHashtableEnumFunc destroyFunc, void* closure)
{
if (destroyFunc != NULL)
{
_HashEnumerateArgs thunk;
thunk.fn = destroyFunc;
thunk.arg = closure;
PL_HashTableEnumerateEntries(hashtable, _hashEnumerateRemove, &thunk);
}
else
PL_HashTableEnumerateEntries(hashtable, _hashEnumerateRemove, NULL);
}
////////////////////////////////////////////////////////////////////////////////
nsStringKey::nsStringKey(const char* str)
{
mStr.Assign(str);
}
nsStringKey::nsStringKey(const PRUnichar* str)
{
mStr.Assign(str);
}
nsStringKey::nsStringKey(const nsStr& str)
{
mStr.Assign(str);
}
nsStringKey::~nsStringKey(void)
{
}
PRUint32 nsStringKey::HashValue(void) const
{
if(mStr.IsUnicode())
{
PRUint32 h;
PRUint32 n;
PRUint32 m;
const PRUnichar* c;
h = 0;
n = mStr.Length();
c = mStr.GetUnicode();
if(n < 16)
{ /* Hash every char in a short string. */
for(; n; c++, n--)
h = (h >> 28) ^ (h << 4) ^ *c;
}
else
{ /* Sample a la jave.lang.String.hash(). */
for(m = n / 8; n >= m; c += m, n -= m)
h = (h >> 28) ^ (h << 4) ^ *c;
}
return h;
}
return (PRUint32)PL_HashString((const void*) mStr.GetBuffer());
}
PRBool nsStringKey::Equals(const nsHashKey* aKey) const
{
return ((nsStringKey*)aKey)->mStr == mStr;
}
nsHashKey* nsStringKey::Clone() const
{
return new nsStringKey(mStr);
}
const nsString& nsStringKey::GetString() const
{
return mStr;
}
////////////////////////////////////////////////////////////////////////////////
// nsObjectHashtable: an nsHashtable where the elements are C++ objects to be
// deleted
nsObjectHashtable::nsObjectHashtable(nsHashtableCloneElementFunc cloneElementFun,
void* cloneElementClosure,
nsHashtableEnumFunc destroyElementFun,
void* destroyElementClosure,
PRUint32 aSize, PRBool threadSafe)
: nsHashtable(aSize, threadSafe),
mCloneElementFun(cloneElementFun),
mCloneElementClosure(cloneElementClosure),
mDestroyElementFun(destroyElementFun),
mDestroyElementClosure(destroyElementClosure)
{
}
nsObjectHashtable::~nsObjectHashtable()
{
Reset();
}
PR_CALLBACK PRIntn
nsObjectHashtable::CopyElement(PLHashEntry *he, PRIntn i, void *arg)
{
nsObjectHashtable *newHashtable = (nsObjectHashtable *)arg;
void* newElement =
newHashtable->mCloneElementFun((nsHashKey*)he->key, he->value,
newHashtable->mCloneElementClosure);
if (newElement == nsnull)
return HT_ENUMERATE_STOP;
newHashtable->Put((nsHashKey*)he->key, newElement);
return HT_ENUMERATE_NEXT;
}
nsHashtable*
nsObjectHashtable::Clone()
{
PRBool threadSafe = PR_FALSE;
if (mLock)
threadSafe = PR_TRUE;
nsObjectHashtable* newHashTable =
new nsObjectHashtable(mCloneElementFun, mCloneElementClosure,
mDestroyElementFun, mDestroyElementClosure,
hashtable->nentries, threadSafe);
PL_HashTableEnumerateEntries(hashtable, CopyElement, newHashTable);
return newHashTable;
}
void
nsObjectHashtable::Reset()
{
nsHashtable::Reset(mDestroyElementFun, mDestroyElementClosure);
}
PRBool
nsObjectHashtable::RemoveAndDelete(nsHashKey *aKey)
{
void *value = Remove(aKey);
if (value && mDestroyElementFun)
{
return (*mDestroyElementFun)(aKey, value, mDestroyElementClosure);
}
else
return PR_FALSE;
}
////////////////////////////////////////////////////////////////////////////////
// nsSupportsHashtable: an nsHashtable where the elements are nsISupports*
static PR_CALLBACK PRBool
_ReleaseElement(nsHashKey *aKey, void *aData, void* closure)
{
nsISupports* element = NS_STATIC_CAST(nsISupports*, aData);
NS_IF_RELEASE(element);
return PR_TRUE;
}
nsSupportsHashtable::~nsSupportsHashtable()
{
Enumerate(_ReleaseElement, nsnull);
}
void*
nsSupportsHashtable::Put(nsHashKey *aKey, void *aData)
{
nsISupports* element = NS_STATIC_CAST(nsISupports*, aData);
NS_IF_ADDREF(element);
return nsHashtable::Put(aKey, aData);
}
void*
nsSupportsHashtable::Get(nsHashKey *aKey)
{
void* data = nsHashtable::Get(aKey);
if (!data)
return nsnull;
nsISupports* element = NS_STATIC_CAST(nsISupports*, data);
NS_IF_ADDREF(element);
return data;
}
void*
nsSupportsHashtable::Remove(nsHashKey *aKey)
{
void* data = nsHashtable::Remove(aKey);
if (!data)
return nsnull;
nsISupports* element = NS_STATIC_CAST(nsISupports*, data);
NS_IF_RELEASE(element);
return data;
}
static PR_CALLBACK PRIntn
_hashEnumerateCopy(PLHashEntry *he, PRIntn i, void *arg)
{
nsHashtable *newHashtable = (nsHashtable *)arg;
nsISupports* element = NS_STATIC_CAST(nsISupports*, he->value);
NS_IF_ADDREF(element);
newHashtable->Put((nsHashKey*)he->key, he->value);
return HT_ENUMERATE_NEXT;
}
nsHashtable*
nsSupportsHashtable::Clone()
{
PRBool threadSafe = PR_FALSE;
if (mLock)
threadSafe = PR_TRUE;
nsSupportsHashtable* newHashTable =
new nsSupportsHashtable(hashtable->nentries, threadSafe);
PL_HashTableEnumerateEntries(hashtable, _hashEnumerateCopy, newHashTable);
return newHashTable;
}
void
nsSupportsHashtable::Reset()
{
Enumerate(_ReleaseElement, nsnull);
nsHashtable::Reset();
}
////////////////////////////////////////////////////////////////////////////////
// nsOpaqueKey: Where keys are opaque byte array blobs
//
// Note opaque keys are not copied by this constructor. If you want a private
// copy in each hash key, you must create one and pass it in to this function.
nsOpaqueKey::nsOpaqueKey(const char *aOpaqueKey, PRUint32 aKeyLength)
{
mOpaqueKey = aOpaqueKey;
mKeyLength = aKeyLength;
}
nsOpaqueKey::~nsOpaqueKey(void)
{
}
PRUint32
nsOpaqueKey::HashValue(void) const
{
PRUint32 h, i, k;
h = 0;
// Same hashing technique as for java.lang.String.hashCode()
if (mKeyLength <= 15) {
// A short key; Use a dense sampling to compute the hash code
for (i = 0; i < mKeyLength; i++)
h += 37 * mOpaqueKey[i];
} else {
// A long key; Use a sparse sampling to compute the hash code
k = mKeyLength >> 3;
for (i = 0; i < mKeyLength; i += k)
h += 39 * mOpaqueKey[i];
}
return h;
}
PRBool
nsOpaqueKey::Equals(const nsHashKey* aKey) const
{
nsOpaqueKey *otherKey = (nsOpaqueKey*)aKey;
if (mKeyLength != otherKey->mKeyLength)
return PR_FALSE;
return !(PRBool)memcmp(otherKey->mOpaqueKey, mOpaqueKey, mKeyLength);
}
nsHashKey*
nsOpaqueKey::Clone() const
{
return new nsOpaqueKey(mOpaqueKey, mKeyLength);
}
PRUint32
nsOpaqueKey::GetKeyLength() const
{
return mKeyLength;
}
const char*
nsOpaqueKey::GetKey() const
{
return mOpaqueKey;
}
////////////////////////////////////////////////////////////////////////////////

View File

@@ -0,0 +1,248 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
#ifndef nsHashtable_h__
#define nsHashtable_h__
#include "plhash.h"
#include "prlock.h"
#include "nsCom.h"
class NS_COM nsHashKey {
protected:
nsHashKey(void);
public:
virtual ~nsHashKey(void);
virtual PRUint32 HashValue(void) const = 0;
virtual PRBool Equals(const nsHashKey *aKey) const = 0;
virtual nsHashKey *Clone(void) const = 0;
};
// Enumerator callback function. Use
typedef PRBool (*nsHashtableEnumFunc)(nsHashKey *aKey, void *aData, void* closure);
class NS_COM nsHashtable {
protected:
// members
PLHashTable *hashtable;
PRLock *mLock;
public:
nsHashtable(PRUint32 aSize = 256, PRBool threadSafe = PR_FALSE);
~nsHashtable();
PRInt32 Count(void) { return hashtable->nentries; }
PRBool Exists(nsHashKey *aKey);
void *Put(nsHashKey *aKey, void *aData);
void *Get(nsHashKey *aKey);
void *Remove(nsHashKey *aKey);
nsHashtable *Clone();
void Enumerate(nsHashtableEnumFunc aEnumFunc, void* closure = NULL);
void Reset();
void Reset(nsHashtableEnumFunc destroyFunc, void* closure = NULL);
};
////////////////////////////////////////////////////////////////////////////////
// nsObjectHashtable: an nsHashtable where the elements are C++ objects to be
// deleted
typedef void* (*nsHashtableCloneElementFunc)(nsHashKey *aKey, void *aData, void* closure);
class NS_COM nsObjectHashtable : public nsHashtable {
public:
nsObjectHashtable(nsHashtableCloneElementFunc cloneElementFun,
void* cloneElementClosure,
nsHashtableEnumFunc destroyElementFun,
void* destroyElementClosure,
PRUint32 aSize = 256, PRBool threadSafe = PR_FALSE);
~nsObjectHashtable();
nsHashtable *Clone();
void Reset();
PRBool RemoveAndDelete(nsHashKey *aKey);
protected:
static PR_CALLBACK PRIntn CopyElement(PLHashEntry *he, PRIntn i, void *arg);
nsHashtableCloneElementFunc mCloneElementFun;
void* mCloneElementClosure;
nsHashtableEnumFunc mDestroyElementFun;
void* mDestroyElementClosure;
};
////////////////////////////////////////////////////////////////////////////////
// nsSupportsHashtable: an nsHashtable where the elements are nsISupports*
class NS_COM nsSupportsHashtable : public nsHashtable {
public:
nsSupportsHashtable(PRUint32 aSize = 256, PRBool threadSafe = PR_FALSE)
: nsHashtable(aSize, threadSafe) {}
~nsSupportsHashtable();
void *Put(nsHashKey *aKey, void *aData);
void *Get(nsHashKey *aKey);
void *Remove(nsHashKey *aKey);
nsHashtable *Clone();
void Reset();
};
////////////////////////////////////////////////////////////////////////////////
// nsISupportsKey: Where keys are nsISupports objects that get refcounted.
#include "nsISupports.h"
class nsISupportsKey : public nsHashKey {
protected:
nsISupports* mKey;
public:
nsISupportsKey(nsISupports* key) {
mKey = key;
NS_IF_ADDREF(mKey);
}
~nsISupportsKey(void) {
NS_IF_RELEASE(mKey);
}
PRUint32 HashValue(void) const {
return (PRUint32)mKey;
}
PRBool Equals(const nsHashKey *aKey) const {
return (mKey == ((nsISupportsKey *) aKey)->mKey);
}
nsHashKey *Clone(void) const {
return new nsISupportsKey(mKey);
}
};
////////////////////////////////////////////////////////////////////////////////
// nsVoidKey: Where keys are void* objects that don't get refcounted.
class nsVoidKey : public nsHashKey {
protected:
const void* mKey;
public:
nsVoidKey(const void* key) {
mKey = key;
}
PRUint32 HashValue(void) const {
return (PRUint32)mKey;
}
PRBool Equals(const nsHashKey *aKey) const {
return (mKey == ((const nsVoidKey *) aKey)->mKey);
}
nsHashKey *Clone(void) const {
return new nsVoidKey(mKey);
}
};
////////////////////////////////////////////////////////////////////////////////
// nsIDKey: Where keys are nsIDs (e.g. nsIID, nsCID).
#include "nsID.h"
class nsIDKey : public nsHashKey {
protected:
nsID mID;
public:
nsIDKey(const nsID &aID) {
mID = aID;
}
PRUint32 HashValue(void) const {
return mID.m0;
}
PRBool Equals(const nsHashKey *aKey) const {
return (mID.Equals(((const nsIDKey *) aKey)->mID));
}
nsHashKey *Clone(void) const {
return new nsIDKey(mID);
}
};
////////////////////////////////////////////////////////////////////////////////
// nsStringKey: Where keys are PRUnichar* or char*
// Some uses: hashing ProgIDs, filenames, URIs
#include "nsString.h"
class NS_COM nsStringKey : public nsHashKey {
protected:
nsAutoString mStr;
public:
nsStringKey(const char* str);
nsStringKey(const PRUnichar* str);
nsStringKey(const nsStr& str);
~nsStringKey(void);
PRUint32 HashValue(void) const;
PRBool Equals(const nsHashKey* aKey) const;
nsHashKey* Clone() const;
// For when the owner of the hashtable wants to peek at the actual
// string in the key. No copy is made, so be careful.
const nsString& GetString() const;
};
////////////////////////////////////////////////////////////////////////////////
// nsOpaqueKey: Where keys are opaque byte-array blobs
#include "nsString.h"
class NS_COM nsOpaqueKey : public nsHashKey {
protected:
const char* mOpaqueKey; // Byte array of opaque data
PRUint32 mKeyLength; // Length, in bytes, of mOpaqueKey
public:
// Note opaque keys are not copied by this constructor. If you want a private
// copy in each hash key, you must create one and pass it in to this function.
nsOpaqueKey(const char* aOpaqueKey, PRUint32 aKeyLength);
~nsOpaqueKey(void);
PRUint32 HashValue(void) const;
PRBool Equals(const nsHashKey* aKey) const;
nsHashKey* Clone() const;
// For when the owner of the hashtable wants to peek at the actual
// opaque array in the key. No copy is made, so be careful.
const char* GetKey() const;
PRUint32 GetKeyLength() const;
};
#endif

View File

@@ -0,0 +1,247 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
/*
* Implementation of nsHashEnumerator.
* Use it to expose nsIEnumerator interfaces around nsHashtable objects.
* Contributed by Rob Ginda, rginda@ix.netcom.com
*/
#include "nscore.h"
#include "nsHashtableEnumerator.h"
class nsHashtableEnumerator : public nsIBidirectionalEnumerator
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIENUMERATOR
NS_DECL_NSIBIDIRECTIONALENUMERATOR
public:
virtual ~nsHashtableEnumerator ();
nsHashtableEnumerator (nsHashtable *aHash,
NS_HASH_ENUMERATOR_CONVERTER aConverter,
void *aData);
nsHashtableEnumerator (); /* no implementation */
private:
NS_IMETHOD Reset(nsHashtable *aHash,
NS_HASH_ENUMERATOR_CONVERTER aConverter,
void *aData);
NS_IMETHOD ReleaseElements();
nsISupports **mElements;
PRInt16 mCount, mCurrent;
PRBool mDoneFlag;
};
struct nsHashEnumClosure
{
NS_HASH_ENUMERATOR_CONVERTER Converter;
nsISupports **Elements;
PRInt16 Current;
void *Data;
};
extern "C" NS_COM nsresult
NS_NewHashtableEnumerator (nsHashtable *aHash,
NS_HASH_ENUMERATOR_CONVERTER aConverter,
void *aData, nsIEnumerator **retval)
{
NS_PRECONDITION (retval, "null ptr");
*retval = nsnull;
nsHashtableEnumerator *hte = new nsHashtableEnumerator (aHash, aConverter,
aData);
if (!hte)
return NS_ERROR_OUT_OF_MEMORY;
return hte->QueryInterface (nsCOMTypeInfo<nsIEnumerator>::GetIID(),
(void **)retval);
}
nsHashtableEnumerator::nsHashtableEnumerator (nsHashtable *aHash,
NS_HASH_ENUMERATOR_CONVERTER aConverter,
void *aData)
: mElements(nsnull), mCount(0), mDoneFlag(PR_TRUE)
{
NS_INIT_REFCNT();
Reset (aHash, aConverter, aData);
}
PRBool
hash_enumerator (nsHashKey *aKey, void *aObject, void *closure)
{
nsresult rv;
nsHashEnumClosure *c = (nsHashEnumClosure *)closure;
rv = c->Converter (aKey, (void *)aObject, (void *)c->Data,
&c->Elements[c->Current]);
if (!NS_FAILED(rv))
c->Current++;
return PR_TRUE;
}
NS_IMETHODIMP
nsHashtableEnumerator::Reset (nsHashtable *aHash,
NS_HASH_ENUMERATOR_CONVERTER aConverter,
void *aData)
{
nsHashEnumClosure c;
ReleaseElements();
mCurrent = c.Current = 0;
mCount = aHash->Count();
if (mCount == 0)
return NS_ERROR_FAILURE;
mElements = c.Elements = new nsISupports*[mCount];
c.Data = aData;
c.Converter = aConverter;
aHash->Enumerate (&hash_enumerator, &c);
mCount = c.Current; /* some items may not have converted correctly */
mDoneFlag = PR_FALSE;
return NS_OK;
}
NS_IMETHODIMP
nsHashtableEnumerator::ReleaseElements()
{
for (; mCount > 0; mCount--)
if (mElements[mCount - 1])
NS_RELEASE(mElements[mCount - 1]);
delete[] mElements;
mElements = nsnull;
return NS_OK;
}
NS_IMPL_ISUPPORTS2(nsHashtableEnumerator, nsIBidirectionalEnumerator, nsIEnumerator)
nsHashtableEnumerator::~nsHashtableEnumerator()
{
ReleaseElements();
}
NS_IMETHODIMP
nsHashtableEnumerator::First ()
{
if (!mElements || (mCount == 0))
return NS_ERROR_FAILURE;
mCurrent = 0;
mDoneFlag = PR_FALSE;
return NS_OK;
}
NS_IMETHODIMP
nsHashtableEnumerator::Last ()
{
if (!mElements || (mCount == 0))
return NS_ERROR_FAILURE;
mCurrent = mCount - 1;
mDoneFlag = PR_FALSE;
return NS_OK;
}
NS_IMETHODIMP
nsHashtableEnumerator::Prev ()
{
if (!mElements || (mCount == 0) || (mCurrent == 0)) {
mDoneFlag = PR_TRUE;
return NS_ERROR_FAILURE;
}
mCurrent--;
mDoneFlag = PR_FALSE;
return NS_OK;
}
NS_IMETHODIMP
nsHashtableEnumerator::Next ()
{
if (!mElements || (mCount == 0) || (mCurrent == mCount - 1)) {
mDoneFlag = PR_TRUE;
return NS_ERROR_FAILURE;
}
mCurrent++;
mDoneFlag = PR_FALSE;
return NS_OK;
}
NS_IMETHODIMP
nsHashtableEnumerator::CurrentItem (nsISupports **retval)
{
NS_PRECONDITION (retval, "null ptr");
NS_PRECONDITION (mElements, "invalid state");
NS_ASSERTION (mCurrent >= 0, "mCurrent less than zero");
if (mCount == 0)
{
*retval = nsnull;
return NS_ERROR_FAILURE;
}
NS_ASSERTION (mCurrent <= mCount - 1, "mCurrent too high");
*retval = mElements[mCurrent];
/* who says the item can't be null? */
if (*retval)
NS_ADDREF(*retval);
return NS_OK;
}
NS_IMETHODIMP
nsHashtableEnumerator::IsDone ()
{
if ((!mElements) || (mCount == 0) || (mDoneFlag))
return NS_OK;
return NS_COMFALSE;
}

View File

@@ -0,0 +1,47 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
/*
* This class can be used to expose nsI(BiDirectional)Enumerator interfaces
* around nsHashtable objects.
* Contributed by Rob Ginda, rginda@ix.netcom.com
*/
#ifndef nsHashtableEnumerator_h___
#define nsHashtableEnumerator_h___
#include "nscore.h"
#include "nsIEnumerator.h"
#include "nsHashtable.h"
typedef NS_CALLBACK(NS_HASH_ENUMERATOR_CONVERTER) (nsHashKey *key, void *data,
void *convert_data,
nsISupports **retval);
extern "C" NS_COM nsresult
NS_NewHashtableEnumerator (nsHashtable *aHash,
NS_HASH_ENUMERATOR_CONVERTER aConverter,
void *aData, nsIEnumerator **retval);
#endif /* nsHashtableEnumerator_h___ */

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More