Milán Major

netscape-revival

1 branch
Code

lib/libmsg/mailsum.h

/* -*- Mode: C; tab-width: 4 -*-
   mailsum.h --- definitions for the mail summary file format.
   Copyright © 1996 Netscape Communications Corporation, all rights reserved.
   Created: Jamie Zawinski <jwz@netscape.com>, 10-May-95.
 */

#ifndef _MAILSUM_H_
#define _MAILSUM_H_

#include "xp_mcom.h"
#include "xp_core.h"
#include "xp_hash.h"
#include "xp_file.h"
#include "ntypes.h"


/* The summary file format is as follows:

   MAGIC_NUMBER VERSION FOLDER_SIZE FOLDER_DATE PARSED_THRU NMSGS NVALIDMSGS
    NUNREADMSGS EXPUNGED_BYTES STRING_TABLE [ MSG_DESC ]*

   MAGIC_NUMBER   := '# Netscape folder cache\r\n'
   VERSION        := uint32 (file format version number; this is version 4)

   FOLDER_SIZE    := uint32 (the size of the folder itself, so that we can
                     easily detect an out-of-date summary file)
   FOLDER_DATE    := uint32 (time_t of the folder; same purpose as above)
   PARSED_THRU	  := uint32 (the last position in the folder that we have
							 parsed data for.  Normally the same as 
							 FOLDER_SIZE, but if we append messages to a file,
							 we can just update FOLDER_SIZE and FOLDER_SIZE and
							 use this field to tell us what part of the
							 folder needs to be parsed.)
   NMSGS		  := uint32 (total number of messages in this folder, including
   							 expunged messages)
   NVALIDMSGS	  := uint32 (total number of non-expunged messages in this
   							 folder)
   NUNREADMSGS	  := uint32 (total number of unread messages in this folder)
   EXPUNGED_BYTES := uint32 (number of bytes of messages which have been
                     expunged from the summary, but not yet compacted out
                     of the folder file itself.  The messages in question
                     have the EXPUNGED bit set in their flags.)

   STRING_TABLE   := ST_LENGTH [ ST_STRING ]+
   ST_LENGTH      := uint16
   ST_STRING      := null terminated string

   MSG_DESC       := SENDER RECIPIENT SUBJECT DATE ID REFERENCES
                     FLAGS POS LENGTH STATUSINDEX
   SENDER         := uint16 (index into STRING_TABLE)
   RECIPIENT      := uint16 (index into STRING_TABLE)
   SUBJECT        := uint16 (index into STRING_TABLE)
   DATE           := uint32 (time_t)
   FLAGS          := uint32 (bitfield of other attributes of the message)
   POS            := uint32 (byte index into file)
   LENGTH         := uint32 (length in bytes from envelope to end of last line)
   STATUSOFFSET   := uint16 (Offset from beginning of message envelope for
							 X-Mozilla-Status header)
   LINES          := uint16 (length in lines)
   ID             := uint16 (index into STRING_TABLE)
   REFERENCES     := RLENGTH [ ID ]*
   RLENGTH        := uint16

   The basic idea here is that every string that we store in the summary
   information is stored exactly once, and we reference it with a 16 bit
   index.  The references field, since it refers to other message IDs, is
   a list of indexes into the table.  References to messages which are not
   in this folder are ignored, since we don't have a way of getting to those
   messages anyway (we have no way of knowing what folder they happen to be
   in.)

   This should be an extremely compact format.  The fact that we're using
   16 bit indexes should be ok, since any folder with more than sixty-five
   thousand messages is going to be too huge to deal with anyway.

   This data is used internally to the "mailbox" protocol module, whose
   URLs take a form analagous to "file" URLs:

  'mailbox:' [ '//' HOSTNAME ]? PATHNAME
             ['?' KEY '=' VALUE ['&' KEY '=' VALUE ]*]?

   for example,

       mailbox:/u/jwz/Mail/inbox?id=199505110554.WAA14855&num=5@netscape.com

   or

       mailbox://mail-server/jwz/inbox?id=199505110554.WAA14855@netscape.com

   Currently, the only things which may appear after the "?" is "id=" followed
   by a message ID in that folder, or "num=" followed by a message number in
   the folder.  It takes a key/value form to allow for future expansion
   (additional parameters, different index methods, whatever.)
 */

#define mail_SUMMARY_MAGIC_NUMBER "# Netscape folder cache" CRLF
#define mail_SUMMARY_VERSION 4L

#define mail_MSG_ARRAY_SIZE	128

typedef struct mail_FolderData
{
  char **string_table;					/* All of the strings */
  XP_HashTable message_id_table;		/* Hashes message ID strings into
										   indexes into the `msgs' array. */

  /* `message_count' is the number of messages in the folder, including
	 any expunged messages.

	 During the process of threading, we sometimes need to manufacture
	 placeholder messages to represent expired (or otherwise
	 unavailable) parents of siblings of the same thread.  Those are
	 not included in 'message_count'. */

  uint16 message_count;

  time_t folderdate;			/* The date we believe that the folder */
								/* was last changed.  If this date ever */
								/* differs from the actual date of the */
								/* folder, we had better reparse the */
								/* folder! */

  long foldersize;				/* The number of bytes in the folder. */
								/* Again, if this ever differs from the */
								/* actual folder size, we'd better reparse */
								/* it! */

  uint32 expunged_bytes;		/* Number of bytes of messages which have been
								   expunged from the summary, but not yet
								   compacted out of the folder file itself.
								   The messages in question have the EXPUNGED
								   bit set in their flags. */

  uint32 unread_messages;		/* How many messages there are in the folder
								   without their READ flag set.*/
  uint32 total_messages;		/* How many messages in the folder that
								   are not expunged. */

  struct MSG_ThreadEntry *msgs;

  struct MSG_ThreadEntry* expungedmsgs;	/* All the messages that have the */
										/* expunged bit on in their flags.*/

  struct MSG_ThreadEntry* hiddenmsgs; /* The messages that are in the folder
										 but that we're not showing right now
										 (because, for example, we are not
										 showing any messages that have been
										 read) */

  XP_AllocStructInfo msg_blocks; /* Used to allocate all the MSG_ThreadEntry*
									entries referenced by this struct. */

  /* The below is used only for mail. */

  MSG_ThreadEntry*** msglist;	/* Array of arrays of every message in this
								   structure in message number order, including
								   hidden or expunged messages, but not
								   including expired messages. Each array
								   contains mail_MSG_ARRAY_SIZE slots; there
								   are a total of
								   (message_count/mail_MSG_ARRAY_SIZE)+1 arrays
								   present.  (This structure was chosen to use
								   memory in an efficient and non-fragmenting
								   way). */


} mail_FolderData;


XP_BEGIN_PROTOS

/* Initializes and returns an opaque object representing the parse
   state of a mailbox file.  If folder_data is NULL (the usual case),
   then it will create a new mail_FolderData structure; otherwise, it
   will append the new messages to the given folder_data structure.
   The first message parsed is considered to be at the given
   fileposition; fileposition should be the byte position in the file
   at which the first line of the first message appears.  */
extern struct msg_FolderParseState *
msg_BeginParsingFolder (MWContext* context,
						struct mail_FolderData* folder_data,
						uint32 fileposition);

/* Pass each line of the folder to this, along with the "state" object.
 */
extern int32 msg_ParseFolderLine (char *line, uint32 line_size, void *closure);



/* Done parsing a mailbox file - frees the state object and returns a folder.
 */
extern struct mail_FolderData *
msg_DoneParsingFolder (struct msg_FolderParseState *state,
					   MSG_SORT_KEY sort_key, XP_Bool sort_forward_p,
					   XP_Bool thread_p,
					   XP_Bool merge_before_sort /* If TRUE, then new messages
													are merged in with the
													old ones and the combo
													is sorted.  If FALSE,
													then the new messages
													are sorted separately and
													then tacked onto the
													end of the old ones.*/
					   );



/* Frees a struct mail_FolderData structure and all objects pointed to
   by it, including its string table and MSG_ThreadEntry structures.
 */
extern void msg_FreeFolderData (struct mail_FolderData *data);

/* Read a summary file and return a folder object, or 0.
   This does blocking reads.  Note that it is also passed the filename
   of the folder, in case the summary file contains only part of the
   data.  If the returned data contains more info than is on disk in the
   summary file (because we parsed part of the folder), then the
   provided needs_save flag is set to TRUE.
 */
extern struct mail_FolderData *msg_ReadFolderSummaryFile (MWContext* context,
														  XP_File input,
														  const char* fname,
														  XP_Bool* needs_save);

/* Given a folder, write a summary file.
   This does blocking writes.
 */
extern int msg_WriteFolderSummaryFile (struct mail_FolderData *data,
									   XP_File output);


/* Returns whether the summary file for the given folder is considered
   to have up-to-date info.  The given XP_StatStruct must be filled by
   a very recent call to XP_FileStat on the folder itself. */

extern XP_Bool msg_IsSummaryValid(const char* pathname,
								  XP_StatStruct* folderst);


/* Set the summary for given folder as having up-to-date info.  (This call
   should only be made if a recent call to msg_IsSummaryValid() returned TRUE,
   and if the only changes since made to the folder were appends.)  "num" new
   messages must have been appended, with "numunread" of them not having the
   read bit set on them.  If the given folder is being shown in the mail
   context, then the context's display and data structures will be updated with
   the new messages. */
extern void msg_SetSummaryValid(const char* pathname, int num, int numunread);


/* Get the unread and total message counts for the given folder.  If
   the summary file isn't valid, returns FALSE. */
extern XP_Bool msg_GetSummaryTotals(const char* pathname,
									uint32* unread, uint32* total,
									uint32* wasted, uint32* bytes);


/* Rethread the messages in the given structure according to the current
   sort order for the context.
 */
extern int msg_Rethread (MWContext* context, struct mail_FolderData* data);


XP_END_PROTOS

#endif /* _MAILSUM_H_ */