Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1843 lines
37 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. article.h
  5. Abstract:
  6. This module contains class declarations/definitions for
  7. CArticle
  8. CField
  9. CDateField
  10. CFromField
  11. CMessageIDField
  12. CSubjectField
  13. CNewsgroupsField
  14. CPathField
  15. CXrefField
  16. CFollowupToField
  17. CReplyToField
  18. CApprovedField
  19. CSenderField
  20. CExpiresField
  21. COrganizationField
  22. CSummaryField
  23. CReferencesField
  24. CControlField
  25. CLinesField
  26. CDistributionField
  27. CKeywordsField
  28. CNNTPPostingHostField
  29. CXAuthLoginNameField
  30. CNAMEREFLIST
  31. **** Overview ****
  32. An CArticle object provides an software interface for viewing
  33. and editing a netnews article.
  34. An object is initialized by
  35. giving it a handle or filename for a file containing a Netnews
  36. article. During initialization the article is "preparsed".
  37. Preparsing consists of memory mapping the file and then
  38. finding the location of
  39. 1. The gap that may preceed the article in the file.
  40. 2. The article in the file.
  41. 3. The article's header
  42. 4. The article's body.
  43. Also for every header line in the header, the preparsing creates an
  44. entry in an array that records the location of:
  45. 1. The header line
  46. 2. The keyword
  47. 4. The value
  48. All these locations are represented with Pointer/Counter Strings (See
  49. CPCString in pcstring.h.) This representation has just to parts
  50. 1. A char pointer to the start of the item in the memory mapped file..
  51. 2. A dword containing the length of the item.
  52. **** Fields ****
  53. Each CArticle object can also have several CField subobjects. These
  54. subobjects specialize in parsing and editing specific types of fields.
  55. For example, the CNewsgroupsField object knows how to validate, get,
  56. and set the "Newsgroups: " field.
  57. **** Derivied Objects ****
  58. Every type of feed (e.g. FromClient, FromPeer, etc) defines its own CArticle
  59. object with the CField subobjects that it needs. For example, for FromClient
  60. feeds there is a CFromClientArticle (defined in fromclnt.h) with a
  61. CFromClientFromField (also defined in fromclnt.h) that does very strict
  62. parsing of the article's "From: " field.
  63. **** Editing an Article ****
  64. The header of an article can be edited by deleting old headers and adding
  65. new ones. Headers are deleted just may marking an field in the array of
  66. header values. Headers are added by adding a new entry to the array. This
  67. entry can't just point to the memory-mapped file, so it instead points
  68. to dynamically allocated memory.
  69. When an article is "saved" (or "flushed"), the actual image on disk is
  70. changed to reflected the changes made.
  71. Author:
  72. Carl Kadie (CarlK) 10-Oct-1995
  73. Revision History:
  74. --*/
  75. #ifndef _ARTCORE_H_
  76. #define _ARTCORE_H_
  77. #include "tigtypes.h"
  78. #include "grouplst.h"
  79. #include "artglbs.h"
  80. #include "pcstring.h"
  81. #include "nntpret.h"
  82. #include "mapfile.h"
  83. #include "artutil.h"
  84. #include "nntpmacr.h"
  85. #include "pcparse.h"
  86. #include "nntpcons.h"
  87. #include "timeconv.h"
  88. // forward declaration
  89. class CInFeed ;
  90. //
  91. // CPool Signature
  92. //
  93. #define ARTCORE_SIGNATURE (DWORD)'artc'
  94. //
  95. // Utility functions
  96. //
  97. BOOL AgeCheck( CPCString pcDate ) ;
  98. //
  99. // NAME_AND_ARTREF - structure for storing a newsgroups name, groupid, and article id.
  100. //
  101. typedef struct _NAME_AND_ARTREF {
  102. CPCString pcName;
  103. CArticleRef artref;
  104. } NAME_AND_ARTREF;
  105. //
  106. // CNAMEREFLIST - object implementing a list of newsgroups. For each newsgroup,
  107. // its name, group id and article id is recorded.
  108. //
  109. #ifndef _NO_TEMPLATES_
  110. #ifndef _NAMEREF_GROUPLIST_TEMPLATE_
  111. #define _NAMEREF_GROUPLIST_TEMPLATE_
  112. typedef CGroupList< NAME_AND_ARTREF > CNAMEREFLIST;
  113. #endif
  114. #else
  115. DECLARE_GROUPLST( NAME_AND_ARTREF )
  116. typedef INVOKE_GROUPLST( NAME_AND_ARTREF ) CNAMEREFLIST ;
  117. #endif
  118. //
  119. // An interger setting an upper limit on the number of
  120. // fields in a header can be processed.
  121. //
  122. const unsigned int uMaxFields = 60;
  123. //
  124. // Used to note that the size of the gap before the article starts is
  125. // not known.
  126. //
  127. const DWORD cchUnknownGapSize = (DWORD) -1;
  128. //
  129. // The maximum size of a component (e.g. "alt", "ms-windows") of a
  130. // newsgroup name. (Value is from the Son of 1036 spec.)
  131. //
  132. const DWORD cchMaxNewsgroups = 14;
  133. //
  134. // Define some header field keywords
  135. //
  136. const char szKwFrom[] = "From:";
  137. const char szKwDate[] = "Date:";
  138. const char szKwSubject[] = "Subject:";
  139. const char szKwNewsgroups[] = "Newsgroups:";
  140. const char szKwMessageID[] = "Message-ID:";
  141. const char szKwPath[] = "Path:";
  142. const char szKwReplyTo[] = "ReplyTo:";
  143. const char szKwSender[] = "Sender:";
  144. const char szKwFollupTo[] = "FollowupTo:";
  145. const char szKwExpires[] = "Expires:";
  146. const char szKwReferences[] = "References:";
  147. const char szKwControl[] = "Control:";
  148. const char szKwDistribution[] = "Distribution:";
  149. const char szKwOrganization[] = "Organization:";
  150. const char szKwKeywords[] = "Keywords:";
  151. const char szKwSummary[] = "Summary:";
  152. const char szKwApproved[] = "Approved:";
  153. const char szKwLines[] = "Lines:";
  154. const char szKwXref[] = "Xref:";
  155. const char szKwNNTPPostingHost[] = "NNTP-Posting-Host:";
  156. const char szKwFollowupTo[] = "Followup-To:";
  157. const char szKwXAuthLoginName[] = "X-Auth-Login-Name:";
  158. //
  159. // Used to create an array that points to header values.
  160. // The memory may be allocated in a mapped file or
  161. // dynamically.
  162. //
  163. typedef struct
  164. {
  165. CPCString pcKeyword; // The keyword upto the ":"
  166. CPCString pcValue; // The value (starting after any whitespace,
  167. //
  168. // not including newline characters
  169. //
  170. CPCString pcLine; // The whole line include any newline characters
  171. BOOL fInFile; // True if pointer to a file (rather than other memory
  172. BOOL fRemoved;
  173. } HEADERS_STRINGS;
  174. //
  175. // Forward class declarations (the full classes are declared later)
  176. //
  177. class CArticle;
  178. class CXrefField;
  179. class CPathField;
  180. class CArticleCore;
  181. //
  182. // Represents the states of a field.
  183. //
  184. typedef enum _FIELD_STATE {
  185. fsInitialized,
  186. fsFound,
  187. fsParsed,
  188. fsNotFound,
  189. } FIELD_STATE;
  190. //
  191. // Represents the types of control messages
  192. // The order should EXACTLY match the keyword array that follows
  193. //
  194. typedef enum _CONTROL_MESSAGE_TYPE {
  195. cmCancel,
  196. cmNewgroup,
  197. cmRmgroup,
  198. cmIhave,
  199. cmSendme,
  200. cmSendsys,
  201. cmVersion,
  202. cmWhogets,
  203. cmCheckgroups,
  204. } CONTROL_MESSAGE_TYPE;
  205. //
  206. // Control message strings
  207. //
  208. #define MAX_CONTROL_MESSAGES 9
  209. static char *rgchControlMessageTbl[ MAX_CONTROL_MESSAGES ] =
  210. {
  211. "cancel", "newgroup", "rmgroup", "ihave", "sendme", "sendsys",
  212. "version", "whogets", "checkgroups",
  213. };
  214. //
  215. // Switch to decide what From: header to use in the envelope of mail messages
  216. //
  217. typedef enum _MAIL_FROM_SWITCH {
  218. mfNone,
  219. mfAdmin,
  220. mfArticle,
  221. } MAIL_FROM_SWITCH;
  222. static const char* lpNewgroupDescriptorTag = "For your newsgroups file:";
  223. static const char lpModeratorTag[] = "Group submission address:";
  224. //
  225. //
  226. //
  227. // CField - pure virtual base class for manipulating a field in an
  228. // article.
  229. //
  230. // Each CArticle object can also have several CField subobjects. These
  231. // subobjects specialize in parsing and editing specific types of fields.
  232. // For example, the CNewsgroupsField object knows how to validate, get,
  233. // and set the "Newsgroups: " field.
  234. //
  235. class CField {
  236. public :
  237. //
  238. // Constructor
  239. //
  240. CField():
  241. m_pHeaderString(NULL),
  242. m_fieldState(fsInitialized)
  243. { numField++; };
  244. //
  245. // Deconstructor
  246. //
  247. virtual ~CField(void){ numField--;};
  248. //
  249. // Returns the keyword of the field on which this CField works.
  250. //
  251. virtual const char * szKeyword(void) = 0;
  252. //
  253. // Finds the field of interest in the article (if it is there)
  254. // and parses it.
  255. //
  256. BOOL fFindAndParse(
  257. CArticleCore & article,
  258. CNntpReturn & nntpReturn
  259. );
  260. //
  261. // Makes sure the keyword for this file has the correct
  262. // capitalization.
  263. //
  264. BOOL fConfirmCaps(
  265. CNntpReturn & nntpReturn
  266. );
  267. //
  268. // The derived objects will define Get(s) that return the type of interest, but
  269. // here are some virtual functions for the most common types.
  270. //
  271. //
  272. // Get the value in multisz form
  273. //
  274. virtual const char * multiSzGet(void) {
  275. return (char *) NULL;
  276. };
  277. //
  278. // Get the value in DWORD form
  279. //
  280. virtual DWORD cGet(void) {
  281. return (DWORD) -1;
  282. };
  283. //
  284. // Get the value as a CPCString
  285. //
  286. virtual CPCString pcGet(void) {
  287. return m_pc;
  288. }
  289. //
  290. // Specify friends
  291. //
  292. friend CArticle;
  293. friend CPathField;
  294. protected:
  295. // Finds this field in the article
  296. virtual BOOL fFind(
  297. CArticleCore & article,
  298. CNntpReturn & nntpReturn
  299. );
  300. // Parses this field. By default just find the begining
  301. // and end of the value.
  302. virtual BOOL fParse(
  303. CArticleCore & article,
  304. CNntpReturn & nntpReturn)
  305. {
  306. return fParseSimple(FALSE, m_pc, nntpReturn);
  307. };
  308. // One type of "find" -- Find one or zero occurances of this field.
  309. // Any other number is a error.
  310. BOOL fFindOneOrNone(
  311. CArticleCore & article,
  312. CNntpReturn & nntpReturn
  313. );
  314. // One type of "find" -- Find zero occurances of this field.
  315. // Any other number is a error.
  316. BOOL fFindNone(
  317. CArticleCore & article,
  318. CNntpReturn & nntpReturn
  319. );
  320. // One type of "parse". Just finds the beginning and end of the value.
  321. BOOL fParseSimple(
  322. BOOL fEmptyOK,
  323. CPCString & pc,
  324. CNntpReturn & nntpReturn
  325. );
  326. // One type of "parse". Splits the value into a list of items.
  327. BOOL fParseSplit(
  328. BOOL fEmptyOK,
  329. char * & multisz,
  330. DWORD & c,
  331. char const * szDelimSet,
  332. CArticleCore & article,
  333. CNntpReturn & nntpReturn
  334. );
  335. // One type of "parse". Applies the strict Newsgroups parse rules.
  336. BOOL fStrictNewsgroupsParse(
  337. BOOL fEmptyOK,
  338. char * & multiSzNewsgroups,
  339. DWORD & cNewsgroups,
  340. CArticleCore & article,
  341. CNntpReturn & nntpReturn
  342. );
  343. // One type of "parse". Applies the strict Date parse rules.
  344. // Useful for Date and Expires.
  345. BOOL fStrictDateParse(
  346. CPCString & pcDate,
  347. BOOL fEmptyOK,
  348. CNntpReturn & nntpReturn
  349. );
  350. // One type of "parse". Applies the relative Date parse rules.
  351. // Useful for Date and Expires.
  352. BOOL fRelativeDateParse(
  353. CPCString & pcDate,
  354. BOOL fEmptyOK,
  355. CNntpReturn & nntpReturn
  356. );
  357. // One type of "parse". Applies the strict From parse rules.
  358. // Useful for From, Sender, and ReplyTo
  359. BOOL fStrictFromParse(
  360. CPCString & pcFrom,
  361. BOOL fEmptyOK,
  362. CNntpReturn & nntpReturn
  363. );
  364. // Test a message id value for legal values.
  365. BOOL fTestAMessageID(
  366. const char * szMessageID,
  367. CNntpReturn & nntpReturn
  368. );
  369. // Points to the item in the article's array for this field.
  370. HEADERS_STRINGS * m_pHeaderString;
  371. // The state of this field
  372. FIELD_STATE m_fieldState;
  373. // The result of SimpleParse (this may not be used)
  374. CPCString m_pc;
  375. };
  376. //
  377. //
  378. // Pure virtual base class for manipulating an article's Date field.
  379. class CDateField : public CField {
  380. public:
  381. CDateField(){ numDateField++;};
  382. ~CDateField(void){ numDateField--;};
  383. //
  384. // Returns the keyword of the field on which this CField works.
  385. //
  386. const char * szKeyword(void) {
  387. return szKwDate;
  388. };
  389. };
  390. //
  391. //
  392. // Pure virtual base class for manipulating an article's From field.
  393. class CFromField : public CField {
  394. public:
  395. //
  396. // Returns the keyword of the field on which this CField works.
  397. //
  398. const char * szKeyword(void) {
  399. return szKwFrom;
  400. };
  401. };
  402. //
  403. //
  404. // Pure virtual base class for manipulating an article's MessageID field.
  405. class CMessageIDField : public CField {
  406. public:
  407. //
  408. // Initalize the member variable
  409. //
  410. CMessageIDField (void)
  411. {
  412. m_szMessageID[0] = '\0';
  413. }
  414. //
  415. // Returns the keyword of the field on which this CField works.
  416. //
  417. const char * szKeyword(void) {
  418. return szKwMessageID;
  419. };
  420. // Parse a message id field
  421. BOOL fParse(
  422. CArticleCore & article,
  423. CNntpReturn & nntpReturn
  424. );
  425. // Get the message id
  426. char * szGet(void) {
  427. return m_szMessageID;
  428. };
  429. protected:
  430. // a place to store the message id that parsing findds
  431. char m_szMessageID[MAX_MSGID_LEN];
  432. };
  433. //
  434. //
  435. // Pure virtual base class for manipulating an article's Subject field.
  436. class CSubjectField : public CField {
  437. public:
  438. //
  439. // Returns the keyword of the field on which this CField works.
  440. //
  441. const char * szKeyword(void) {
  442. return szKwSubject;
  443. };
  444. // The subject field is parsed with ParseSimple
  445. BOOL fParse(
  446. CArticleCore & article,
  447. CNntpReturn & nntpReturn
  448. )
  449. {
  450. return fParseSimple(TRUE, m_pc, nntpReturn);
  451. };
  452. friend CArticle;
  453. };
  454. //
  455. //
  456. // Pure virtual base class for manipulating an article's Newsgroups field.
  457. //
  458. class CNewsgroupsField : public CField {
  459. public:
  460. // Constructor
  461. CNewsgroupsField():
  462. m_multiSzNewsgroups(NULL),
  463. m_cNewsgroups((DWORD) -1),
  464. m_pAllocator(NULL)
  465. {};
  466. // Destructor
  467. virtual ~CNewsgroupsField(void){
  468. if (fsParsed == m_fieldState)
  469. {
  470. _ASSERT(m_pAllocator);
  471. m_pAllocator->Free(m_multiSzNewsgroups);
  472. }
  473. };
  474. //
  475. // Returns the keyword of the field on which this CField works.
  476. //
  477. const char * szKeyword(void) {
  478. return szKwNewsgroups;
  479. };
  480. // Parse the Newsgroups field
  481. BOOL fParse(
  482. CArticleCore & article,
  483. CNntpReturn & nntpReturn
  484. );
  485. // Return the newsgroups as a multisz
  486. const char * multiSzGet(void);
  487. // Return the number of newsgroups found
  488. DWORD cGet(void);
  489. friend CXrefField;
  490. protected:
  491. // A pointer to the dynamic memory used to hold the list of newsgroups
  492. char * m_multiSzNewsgroups;
  493. // The number of newsgroups
  494. DWORD m_cNewsgroups;
  495. // Where to allocate from
  496. CAllocator * m_pAllocator;
  497. };
  498. class CDistributionField : public CField {
  499. public:
  500. // Constructor
  501. CDistributionField():
  502. m_multiSzDistribution(NULL),
  503. m_cDistribution((DWORD) -1),
  504. m_pAllocator(NULL)
  505. {};
  506. // Destructor
  507. virtual ~CDistributionField(void){
  508. if (fsParsed == m_fieldState)
  509. {
  510. _ASSERT(m_pAllocator);
  511. m_pAllocator->Free(m_multiSzDistribution);
  512. }
  513. };
  514. //
  515. // Returns the keyword of the field on which this CField works.
  516. //
  517. const char * szKeyword(void) {
  518. return szKwDistribution;
  519. };
  520. BOOL fFind(
  521. CArticleCore & article,
  522. CNntpReturn & nntpReturn)
  523. {
  524. return fFindOneOrNone(article, nntpReturn);
  525. };
  526. // Parse the Distribution field
  527. BOOL fParse(
  528. CArticleCore & article,
  529. CNntpReturn & nntpReturn
  530. );
  531. // Return the Distribution as a multisz
  532. const char * multiSzGet(void);
  533. // Return the number of Distribution found
  534. DWORD cGet(void);
  535. protected:
  536. // A pointer to the dynamic memory used to hold the list of Distribution
  537. char * m_multiSzDistribution;
  538. // The number of Distribution
  539. DWORD m_cDistribution;
  540. // Where to allocate from
  541. CAllocator * m_pAllocator;
  542. };
  543. //
  544. // base class for manipulating an article's Control field.
  545. //
  546. class CControlField : public CField {
  547. public:
  548. //
  549. // Constructor
  550. //
  551. CControlField(){ m_cmCommand = (CONTROL_MESSAGE_TYPE)MAX_CONTROL_MESSAGES;}
  552. //
  553. // Returns the keyword of the field on which this CField works.
  554. //
  555. const char * szKeyword(void) {
  556. return szKwControl;
  557. };
  558. //
  559. // There should only be one such field in articles from clients.
  560. //
  561. BOOL fFind(
  562. CArticleCore & article,
  563. CNntpReturn & nntpReturn)
  564. {
  565. return fFindOneOrNone(article, nntpReturn);
  566. };
  567. //
  568. // Parse to get the type of control message
  569. //
  570. BOOL fParse(
  571. CArticleCore & article,
  572. CNntpReturn & nntpReturn
  573. );
  574. //
  575. // Return the type of control message
  576. //
  577. CONTROL_MESSAGE_TYPE cmGetControlMessage(){return m_cmCommand;}
  578. protected:
  579. //
  580. // Control message type
  581. //
  582. CONTROL_MESSAGE_TYPE m_cmCommand;
  583. };
  584. //
  585. //
  586. // Pure virtual base class for manipulating an article's Xref field.
  587. class CXrefField : public CField {
  588. public:
  589. //
  590. // Returns the keyword of the field on which this CField works.
  591. //
  592. const char * szKeyword(void) {
  593. return szKwXref;
  594. };
  595. // This is a way of saying that, by default, the Xref line should
  596. // never be parsed.
  597. virtual BOOL fParse(
  598. CArticle & article,
  599. CNntpReturn & nntpReturn
  600. )
  601. {
  602. _ASSERT(FALSE);
  603. return FALSE;
  604. };
  605. // Create a new Xref line.
  606. BOOL fSet(
  607. CPCString & pcHub,
  608. CNAMEREFLIST & namereflist,
  609. CArticleCore & article,
  610. CNewsgroupsField & fieldNewsgroups,
  611. CNntpReturn & nntpReturn
  612. );
  613. // Just delete any Xref lines
  614. BOOL fSet(
  615. CArticleCore & article,
  616. CNntpReturn & nntpReturn
  617. );
  618. // Return the list of newsgroup name's, groupid, and article id's
  619. CNAMEREFLIST * pNamereflistGet(void) {
  620. _ASSERT(m_namereflist.fAsBeenInited());
  621. return &m_namereflist;
  622. };
  623. // Return the number of newsgroups that we are posting to locally.
  624. DWORD cGet(void) {
  625. _ASSERT(m_namereflist.fAsBeenInited());
  626. return m_namereflist.GetCount();
  627. };
  628. friend CArticle;
  629. protected:
  630. // Store a list of the local newsgroups we are posting to.
  631. CNAMEREFLIST m_namereflist;
  632. };
  633. //
  634. //
  635. // Pure virtual base class for manipulating an article's FollowupTo field.
  636. class CFollowupToField : public CField {
  637. public:
  638. //
  639. // Returns the keyword of the field on which this CField works.
  640. //
  641. const char * szKeyword(void) {
  642. return szKwFollowupTo;
  643. };
  644. };
  645. //
  646. //
  647. // Pure virtual base class for manipulating an article's ReplyTo field.
  648. class CReplyToField : public CField {
  649. public:
  650. //
  651. // Returns the keyword of the field on which this CField works.
  652. //
  653. const char * szKeyword(void) {
  654. return szKwReplyTo;
  655. };
  656. };
  657. //
  658. //
  659. // Pure virtual base class for manipulating an article's Approved field.
  660. class CApprovedField : public CField {
  661. public:
  662. //
  663. // Returns the keyword of the field on which this CField works.
  664. //
  665. const char * szKeyword(void) {
  666. return szKwApproved;
  667. };
  668. };
  669. //
  670. //
  671. // Pure virtual base class for manipulating an article's Sender field.
  672. class CSenderField : public CField {
  673. public:
  674. //
  675. // Returns the keyword of the field on which this CField works.
  676. //
  677. const char * szKeyword(void) {
  678. return szKwSender;
  679. };
  680. };
  681. //
  682. //
  683. // Pure virtual base class for manipulating an article's Expires field.
  684. class CExpiresField : public CField {
  685. public:
  686. //
  687. // Returns the keyword of the field on which this CField works.
  688. //
  689. const char * szKeyword(void) {
  690. return szKwExpires;
  691. };
  692. };
  693. //
  694. //
  695. // Pure virtual base class for manipulating an article's Organization field.
  696. class COrganizationField : public CField {
  697. public:
  698. //
  699. // Returns the keyword of the field on which this CField works.
  700. //
  701. const char * szKeyword(void) {
  702. return szKwOrganization;
  703. };
  704. };
  705. //
  706. //
  707. // Pure virtual base class for manipulating an article's Summary field.
  708. class CSummaryField : public CField {
  709. public:
  710. //
  711. // Returns the keyword of the field on which this CField works.
  712. //
  713. const char * szKeyword(void) {
  714. return szKwSummary;
  715. };
  716. };
  717. //
  718. //
  719. // Pure virtual base class for manipulating an article's References field.
  720. class CReferencesField : public CField {
  721. public:
  722. //
  723. // Returns the keyword of the field on which this CField works.
  724. //
  725. const char * szKeyword(void) {
  726. return szKwReferences;
  727. };
  728. };
  729. //
  730. //
  731. // Pure virtual base class for manipulating an article's Lines field.
  732. //
  733. class CLinesField : public CField {
  734. public:
  735. //
  736. // Returns the keyword of the field on which this CField works.
  737. //
  738. const char * szKeyword(void) {
  739. return szKwLines;
  740. };
  741. //
  742. // There should be one or none
  743. //
  744. BOOL fFind(
  745. CArticleCore & article,
  746. CNntpReturn & nntpReturn)
  747. {
  748. return fFindOneOrNone(article, nntpReturn);
  749. };
  750. //
  751. // How to set the field.
  752. //
  753. virtual BOOL fSet(
  754. CArticleCore & article,
  755. CNntpReturn & nntpReturn
  756. );
  757. //
  758. // Do we need to back fill ?
  759. //
  760. BOOL fNeedBackFill() { return fsParsed != m_fieldState; }
  761. //
  762. // Get lines back fill offset
  763. //
  764. DWORD GetLinesOffset() { return m_dwLinesOffset; }
  765. private:
  766. //
  767. // back fill offset
  768. //
  769. DWORD m_dwLinesOffset;
  770. };
  771. //
  772. //
  773. // Pure virtual base class for manipulating an article's Keywords field.
  774. class CKeywordsField : public CField {
  775. public:
  776. //
  777. // Returns the keyword of the field on which this CField works.
  778. //
  779. const char * szKeyword(void) {
  780. return szKwKeywords;
  781. };
  782. };
  783. //
  784. //
  785. // Pure virtual base class for manipulating an article's NNTPPostingHost field.
  786. class CNNTPPostingHostField : public CField {
  787. public:
  788. //
  789. // Returns the keyword of the field on which this CField works.
  790. //
  791. const char * szKeyword(void) {
  792. return szKwNNTPPostingHost;
  793. };
  794. };
  795. //
  796. //
  797. // Pure virtual base class for manipulating an article's XAuthLoginName field.
  798. class CXAuthLoginNameField : public CField {
  799. public:
  800. //
  801. // Returns the keyword of the field on which this CField works.
  802. //
  803. const char * szKeyword(void) {
  804. return szKwXAuthLoginName;
  805. };
  806. };
  807. //
  808. // Represents the states of an article
  809. //
  810. typedef enum _ARTICLE_STATE {
  811. asUninitialized,
  812. asInitialized,
  813. asPreParsed,
  814. asModified,
  815. asSaved
  816. } ARTICLE_STATE;
  817. //
  818. // CCreateFileImpl implements the way we create the file for mapfile,
  819. // in this case we do CacheCreateFile.
  820. //
  821. class CCacheCreateFile : public CCreateFile {
  822. public:
  823. CCacheCreateFile( BOOL fOpenForRead ) :
  824. m_fOpenForRead( fOpenForRead ),
  825. m_pFIOContext( NULL )
  826. {}
  827. ~CCacheCreateFile();
  828. virtual HANDLE CreateFileHandle( LPCSTR szFileName );
  829. PFIO_CONTEXT m_pFIOContext;
  830. private:
  831. CCacheCreateFile();
  832. static HANDLE CacheCreateCallback( LPSTR szFileName,
  833. LPVOID pv,
  834. PDWORD pdwSize,
  835. PDWORD pdwSizeHigh );
  836. BOOL m_fOpenForRead;
  837. };
  838. //
  839. //
  840. //
  841. // CArticleCore - pure virtual base class for manipulating an article.
  842. // Article are derived from CRefCount. Thus, when nothing points
  843. // to an article it is freed up.
  844. class CArticleCore : public CRefCount{
  845. private :
  846. // Used for memory allocation
  847. static CPool* g_pArticlePool;
  848. // Uesd for special create file with CMapFile
  849. CCacheCreateFile m_CacheCreateFile;
  850. //
  851. // Public Members
  852. //
  853. public :
  854. // Used for memory allocation
  855. static BOOL InitClass() ;
  856. static BOOL TermClass() ;
  857. inline void* operator new( size_t size ) ;
  858. inline void operator delete( void *pv ) ;
  859. //
  860. // Constructor
  861. // Initialization Interface -
  862. // The following functions are used to create & destroy newsgroup objects.
  863. //
  864. // Lightweight Constructors -
  865. // These constructors do very simple initialization. The Init() functions
  866. // need to be called to get a functional newsgroup.
  867. //
  868. CArticleCore();
  869. //
  870. // Destructor
  871. //
  872. virtual ~CArticleCore() ;
  873. //
  874. // Initialize from a filename or handle
  875. //
  876. BOOL fInit(
  877. const char * szFilename,
  878. CNntpReturn & nntpReturn,
  879. CAllocator * pAllocator,
  880. HANDLE hFile = INVALID_HANDLE_VALUE,
  881. DWORD cBytesGapSize = cchUnknownGapSize,
  882. BOOL fCacheCreate = FALSE
  883. );
  884. //
  885. // If an incoming article was small enough to fit entirely into
  886. // a memory buffer - call this function !
  887. //
  888. BOOL fInit(
  889. char* pchHead,
  890. DWORD cbHead,
  891. DWORD cbArticle,
  892. DWORD cbBufferTotal,
  893. CAllocator* pAllocator,
  894. CNntpReturn& nntpReturn
  895. ) ;
  896. //
  897. // If an incoming article was so large that it did not fit into
  898. // a memory buffer call this initialization function !
  899. //
  900. BOOL fInit(
  901. char* pchHead,
  902. DWORD cbHead,
  903. DWORD cbArticle,
  904. DWORD cbBufferTotal,
  905. HANDLE hFile,
  906. LPSTR lpstrFileName,
  907. DWORD ibHeadOffset,
  908. CAllocator* pAllocator,
  909. CNntpReturn& nntpReturn
  910. ) ;
  911. //
  912. // create's an IStream pointer to the article contents and returns
  913. // it
  914. //
  915. BOOL fGetStream(IStream **ppStream);
  916. //
  917. // Get body - map file if needed
  918. //
  919. BOOL fGetBody(
  920. CMapFile * & pMapFile,
  921. char * & pchMappedFile,
  922. DWORD & dwLength
  923. );
  924. //
  925. // return TRUE if the article is in memory only and there is no file !
  926. //
  927. inline BOOL fIsArticleCached() {
  928. return m_szFilename == 0 ;
  929. }
  930. //
  931. // Find out where the head and body of the article are within the file !
  932. //
  933. inline void GetOffsets(
  934. WORD &wHeadStart,
  935. WORD &wHeadSize,
  936. DWORD &dwTotalSize
  937. ) {
  938. wHeadStart = (WORD)m_pcGap.m_cch ;
  939. wHeadSize = (WORD)m_pcHeader.m_cch ;
  940. dwTotalSize = m_pcArticle.m_cch ;
  941. }
  942. //
  943. // These functions get (parts of) an article for transmission.
  944. // The second in each par of functions is useful when the article
  945. // is to be encrypted.
  946. //
  947. //
  948. // Get header for file transmission
  949. //
  950. BOOL fHead(
  951. HANDLE & hFile,
  952. DWORD & dwOffset,
  953. DWORD & dwLength
  954. );
  955. //
  956. // Get header for encryption
  957. //
  958. BOOL fHead(
  959. char * & pchMappedFile,
  960. DWORD & dwLength
  961. );
  962. //
  963. // Get body for file transmission
  964. //
  965. BOOL fBody(
  966. HANDLE & hFile,
  967. DWORD & dwOffset,
  968. DWORD & dwLength
  969. );
  970. //
  971. // Get body for encryption
  972. //
  973. BOOL fBody(
  974. char * & pchMappedFile,
  975. DWORD & dwLength
  976. );
  977. //
  978. // Get body for encryption
  979. //
  980. DWORD dwBodySize(void)
  981. {
  982. return m_pcBody.m_cch;
  983. }
  984. //
  985. // Get whole article for file transmission
  986. //
  987. BOOL fWholeArticle(
  988. HANDLE & hFile,
  989. DWORD & dwOffset,
  990. DWORD & dwLength
  991. );
  992. //
  993. // Get whole article for encryption
  994. //
  995. BOOL fWholeArticle(
  996. char * & pchMappedFile,
  997. DWORD & dwLength
  998. );
  999. //
  1000. // Sets the value of a header field including any newlines.
  1001. // New values are always stored in dynamic memory allocated
  1002. // with heap_alloc from the local thread. This function also sets
  1003. // m_HeadersDirty and dwCurrentHeaderSize;
  1004. //
  1005. BOOL fSetHeaderValue(
  1006. char const * szKeyword,
  1007. const char * pchValue,
  1008. DWORD cchValue
  1009. );
  1010. //
  1011. // a header line of exactly the same length. It returns an error
  1012. // if the lines aren't the same length.
  1013. // Its expected use it to add the value of the XRef line to an
  1014. // article without having to moving anything else around.
  1015. //
  1016. BOOL fOverwriteHeaderValue(
  1017. char const * szKeyword,
  1018. const char * pchValue,
  1019. DWORD cchValue
  1020. );
  1021. //
  1022. // Should we really changed the order the header lines just because we want
  1023. // to touch "path" and "xref"?
  1024. //
  1025. // Writes out the header. This means: Writing out the known fields in the
  1026. // order they appear in the HEADER_FIELDS enumeration. If the gap is not big enough,
  1027. // this will require coping the file. Unknown headers are written after the known ones.
  1028. // This clears dwHeadersDirty, sets dwOriginalHeaderSize to be the current header size.
  1029. // If another pass of changes is required, then m_fParse must be called again.
  1030. // The parameter tell if the headers should be output in the original order or if they
  1031. // should be output in the prefered order.
  1032. //
  1033. BOOL fSaveHeader(
  1034. CNntpReturn &nntpReturn,
  1035. PDWORD pdwLinesOffset = NULL
  1036. );
  1037. BOOL fSaveCachedHeaderInternal(
  1038. CNntpReturn& nntpReturn,
  1039. PDWORD pdwLinesOffset = NULL
  1040. ) ;
  1041. BOOL fBuildNewHeader(
  1042. CPCString& pcHeaderBuf ,
  1043. CNntpReturn& nntpReturn,
  1044. PDWORD pdwLinesOffset = NULL
  1045. ) ;
  1046. //
  1047. // calling this function makes it safe to use fGetHeader after a
  1048. // call to vClose.
  1049. //
  1050. BOOL fMakeGetHeaderSafeAfterClose(CNntpReturn &nntpReturn);
  1051. BOOL fSaveHeaderInternal(
  1052. CPCString & pcHeaderBuf,
  1053. CPCString & pcNewBody,
  1054. CNntpReturn & nntpReturn,
  1055. PDWORD pdwLinesOffset = NULL
  1056. );
  1057. BOOL fGetHeader(
  1058. LPSTR lpstrHeader,
  1059. BYTE* lpbOutput,
  1060. DWORD cbOutput,
  1061. DWORD& cbReturn
  1062. ) ;
  1063. // Removes any occurance of a field
  1064. BOOL fRemoveAny(
  1065. const char * szKeyword,
  1066. CNntpReturn & nntpReturn
  1067. );
  1068. // Adds a line of text to the header
  1069. BOOL fAdd(
  1070. char * pchCurrent,
  1071. const char * pchMax,
  1072. CNntpReturn & nntpReturn
  1073. );
  1074. // Returns the article's filename
  1075. char * szFilename(void) {
  1076. return m_szFilename;
  1077. };
  1078. //
  1079. // For dynamic memory allocation
  1080. //
  1081. CAllocator * pAllocator(void)
  1082. { return m_pAllocator;}
  1083. // Returns the article's main artref
  1084. CArticleRef articleRef(void) {
  1085. return m_articleRef;
  1086. };
  1087. // Sets the article's main artref
  1088. void vSetArticleRef(CArticleRef & articleRef) {
  1089. m_articleRef = articleRef;
  1090. };
  1091. // Returns XOver information for the article.
  1092. BOOL fXOver(
  1093. CPCString & pcBuffer,
  1094. CNntpReturn & nntpReturn
  1095. );
  1096. // Closes the article's filemapping.
  1097. void vClose(void);
  1098. void vCloseIfOpen(void);
  1099. // Flush the article to disk !
  1100. void vFlush(void);
  1101. // Finds the one and only occurance of the a field in the headers.
  1102. // If there are no occurances or multiple occurances, then an error
  1103. // is returned.
  1104. BOOL fFindOneAndOnly(
  1105. const char * szKeyword,
  1106. HEADERS_STRINGS * & pHeaderString,
  1107. CNntpReturn & nntpReturn
  1108. );
  1109. friend CField;
  1110. //
  1111. // Public interface which should be used if fSaveHeader() is not called
  1112. // to fill in any initial gap within the file !
  1113. //
  1114. BOOL
  1115. fCommitHeader(
  1116. CNntpReturn & nntpReturn
  1117. ) ;
  1118. //
  1119. // Did the headers remain in the IO buffer - if so where ?
  1120. //
  1121. BOOL
  1122. FHeadersInIOBuff( char* pchStartIOBuffer, DWORD cbIOBuffer ) {
  1123. if( m_pcHeader.m_pch > pchStartIOBuffer &&
  1124. m_pcHeader.m_pch < &pchStartIOBuffer[cbIOBuffer] ) {
  1125. _ASSERT( (m_pcHeader.m_pch + m_pcHeader.m_cch) < (m_pcHeader.m_pch + cbIOBuffer) ) ;
  1126. return TRUE ;
  1127. }
  1128. return FALSE ;
  1129. }
  1130. DWORD
  1131. GetHeaderPosition( char* pchStartIOBuffer,
  1132. DWORD cbIOBuffer,
  1133. DWORD& ibOffset
  1134. ) {
  1135. //
  1136. // Only use this function if FHeadersInIOBuff() returns TRUE !
  1137. //
  1138. _ASSERT( FHeadersInIOBuff( pchStartIOBuffer, cbIOBuffer ) ) ;
  1139. ibOffset = (DWORD)(m_pcHeader.m_pch - pchStartIOBuffer) ;
  1140. return m_pcHeader.m_cch + 2 ;
  1141. }
  1142. // get the length of the headers. we add space for the \r\n
  1143. DWORD GetHeaderLength( ) {
  1144. return m_pcHeader.m_cch + 2;
  1145. }
  1146. // copy the headers into another buffer. the buffer must be at least
  1147. // GetHeaderLength characters long
  1148. void CopyHeaders(char *pszDestination) {
  1149. memmove(pszDestination, m_pcHeader.m_pch, m_pcHeader.m_cch);
  1150. memmove(pszDestination + m_pcHeader.m_cch, "\r\n", 2);
  1151. }
  1152. // get the length of the headers. no space for \r\n
  1153. DWORD GetShortHeaderLength() { return m_pcHeader.m_cch; }
  1154. char *GetHeaderPointer() {
  1155. return m_pcHeader.m_pch;
  1156. }
  1157. //
  1158. // protected Members
  1159. //
  1160. protected :
  1161. // The function that is actually used to add lines to
  1162. // the article's header.
  1163. BOOL fAddInternal(
  1164. char * & pchCurrent,
  1165. const char * pchMax,
  1166. BOOL fInFile,
  1167. CNntpReturn & nntpReturn
  1168. );
  1169. //
  1170. // the name of the article's file
  1171. //
  1172. LPSTR m_szFilename ;
  1173. //
  1174. // A handle to the article's file
  1175. //
  1176. HANDLE m_hFile;
  1177. //
  1178. // Offset to the body of the article within the file !
  1179. //
  1180. DWORD m_ibBodyOffset ;
  1181. //
  1182. // A pointer to a file mapping of the article
  1183. //
  1184. CMapFile * m_pMapFile;
  1185. //
  1186. // If we have to allocate a buffer to hold a header which grows at some
  1187. // point we will set this pointer.
  1188. //
  1189. char* m_pHeaderBuffer ;
  1190. //
  1191. // a pointer-and-count string that points to the
  1192. // whole article
  1193. //
  1194. CPCString m_pcFile;
  1195. //
  1196. // a pointer-and-count string that points to the
  1197. // gap
  1198. //
  1199. CPCString m_pcGap;
  1200. //
  1201. // a pointer-and-count string that points to the
  1202. // whole article
  1203. //
  1204. CPCString m_pcArticle;
  1205. //
  1206. // Fill the gap in the file with blanks (and other info).
  1207. //
  1208. void vGapFill(void);
  1209. //
  1210. // build an array pointing to known header types
  1211. //
  1212. BOOL fPreParse(
  1213. CNntpReturn & nntpReturn
  1214. );
  1215. //
  1216. // a pointer-and-count string that points to the
  1217. // header of the article
  1218. //
  1219. CPCString m_pcHeader;
  1220. //
  1221. // a pointer-and-count string that points to the
  1222. // body of the article.
  1223. //
  1224. CPCString m_pcBody;
  1225. //
  1226. // An array that points to the header fields
  1227. //
  1228. HEADERS_STRINGS m_rgHeaders[(unsigned int) uMaxFields];
  1229. //
  1230. // The article reference for this article
  1231. //
  1232. CArticleRef m_articleRef;
  1233. //
  1234. // For dynamic memory allocation
  1235. //
  1236. CAllocator * m_pAllocator;
  1237. //
  1238. // the number of fields in the header.
  1239. //
  1240. DWORD m_cHeaders;
  1241. //
  1242. // Removed deleted entries from the array of headers.
  1243. //
  1244. void vCompressArray(void);
  1245. //
  1246. // Find the size of the gap by looking at the file.
  1247. //
  1248. void vGapRead(void);
  1249. //
  1250. // Remove a header line.
  1251. //
  1252. void vRemoveLine(
  1253. HEADERS_STRINGS * phs
  1254. );
  1255. //
  1256. // Remove all header lines that have no values.
  1257. //
  1258. BOOL fDeleteEmptyHeader(
  1259. CNntpReturn & nntpReturn
  1260. );
  1261. //
  1262. // Record the state of the article.
  1263. //
  1264. ARTICLE_STATE m_articleState;
  1265. //
  1266. // Add more information to the XOver data.
  1267. //
  1268. BOOL fXOverAppend(
  1269. CPCString & pc,
  1270. DWORD cchLast,
  1271. const char * szKeyword,
  1272. BOOL fRequired,
  1273. BOOL fIncludeKeyword,
  1274. CNntpReturn & nntpReturn
  1275. );
  1276. //
  1277. // Add References information to the XOver data. Shorten the
  1278. // data if necessary.
  1279. //
  1280. BOOL fXOverAppendReferences(
  1281. CPCString & pc,
  1282. DWORD cchLast,
  1283. CNntpReturn & nntpReturn
  1284. );
  1285. //
  1286. // Append a string to the XOver data.
  1287. //
  1288. BOOL fXOverAppendStr(
  1289. CPCString & pc,
  1290. DWORD cchLast,
  1291. char * const sz,
  1292. CNntpReturn & nntpReturn
  1293. );
  1294. //
  1295. // Tells if the article should open the file with read/write mode.
  1296. //
  1297. virtual BOOL fReadWrite(void) { return FALSE ;}
  1298. //
  1299. // Check if the length of the article's body is not too long.
  1300. //
  1301. virtual BOOL fCheckBodyLength(
  1302. CNntpReturn & nntpReturn) { return TRUE; };
  1303. //
  1304. // Check the character following the ":" in a header.
  1305. //
  1306. virtual BOOL fCheckFieldFollowCharacter(
  1307. char chCurrent) { return TRUE; }
  1308. //
  1309. // Run "FindAndParse" on a list of fields.
  1310. //
  1311. BOOL fFindAndParseList(
  1312. CField * * rgPFields,
  1313. DWORD cFields,
  1314. CNntpReturn & nntpReturn
  1315. );
  1316. //
  1317. // Run "ConfirmCaps" on a list of fields.
  1318. //
  1319. BOOL fConfirmCapsList(
  1320. CField * * rgPFields,
  1321. DWORD cFields,
  1322. CNntpReturn & nntpReturn
  1323. );
  1324. BOOL ArtCloseHandle( HANDLE& );
  1325. friend CField;
  1326. friend CMessageIDField;
  1327. friend CNewsgroupsField;
  1328. } ;
  1329. extern const unsigned cbMAX_ARTCORE_SIZE;
  1330. inline void*
  1331. CArticleCore::operator new( size_t size )
  1332. {
  1333. _ASSERT( size <= cbMAX_ARTCORE_SIZE ) ;
  1334. return g_pArticlePool->Alloc() ;
  1335. }
  1336. inline void
  1337. CArticleCore::operator delete( void* pv )
  1338. {
  1339. g_pArticlePool->Free( pv ) ;
  1340. }
  1341. //
  1342. //
  1343. // Pure virtual base class for manipulating an article's Path field.
  1344. class CPathField : public CField {
  1345. public:
  1346. // Constructor
  1347. CPathField():
  1348. m_multiSzPath(NULL),
  1349. m_cPath((DWORD) -1),
  1350. m_pAllocator(NULL),
  1351. m_fChecked(FALSE)
  1352. {};
  1353. //
  1354. // Deconstructor
  1355. //
  1356. virtual ~CPathField(void){
  1357. if (fsParsed == m_fieldState)
  1358. {
  1359. _ASSERT(m_pAllocator);
  1360. m_pAllocator->Free(m_multiSzPath);
  1361. }
  1362. };
  1363. //
  1364. // Returns the keyword of the field on which this CField works.
  1365. //
  1366. const char * szKeyword(void) {
  1367. return szKwPath;
  1368. };
  1369. //
  1370. //!!!constize
  1371. //!!! is a null path OK?
  1372. //!!!CLIENT NEXT
  1373. //
  1374. // Parse the Path value into its components.
  1375. BOOL fParse(
  1376. CArticleCore & article,
  1377. CNntpReturn & nntpReturn
  1378. )
  1379. {
  1380. //
  1381. // Record the allocator
  1382. //
  1383. m_pAllocator = article.pAllocator();
  1384. return fParseSplit(FALSE, m_multiSzPath, m_cPath, " \t\r\n!",
  1385. article, nntpReturn);
  1386. };
  1387. // Return the path as a multsz list.
  1388. const char * multiSzGet(void);
  1389. // Set a new path by appending our hub to the old value.
  1390. BOOL fSet(
  1391. CPCString & pcHub,
  1392. CArticleCore & article,
  1393. CNntpReturn & nntpReturn
  1394. );
  1395. // Check for a loop by looking for our hub in the path (by not in the last location)
  1396. BOOL fCheck(
  1397. CPCString & pcHub,
  1398. CNntpReturn & nntpReturn
  1399. );
  1400. protected:
  1401. // A pointer to the dynamic memory that contains the path as a multisz
  1402. char * m_multiSzPath;
  1403. // The number of components in the path.
  1404. DWORD m_cPath;
  1405. // Where to allocate from
  1406. CAllocator * m_pAllocator;
  1407. // True, if and only if, the path has been checked for a loop.
  1408. BOOL m_fChecked;
  1409. };
  1410. //
  1411. // Some other functions
  1412. //
  1413. // Test a newsgroup name for legal values.
  1414. BOOL fTestComponents(
  1415. const char * szNewsgroups
  1416. );
  1417. // Tests the components of a newsgroup name (e.g. "alt", "ms-windows") for
  1418. // legal values.
  1419. BOOL fTestAComponent(
  1420. const char * szComponent
  1421. );
  1422. //
  1423. // Largest possible CArticle derived object
  1424. //
  1425. #define MAX_ARTCORE_SIZE sizeof( CArticleCore )
  1426. #define MAX_SESSIONS 15000
  1427. #define MAX_ARTICLES (2 * MAX_SESSIONS)
  1428. #define MAX_REFERENCES_FIELD 512
  1429. #endif