1 
2 // C++ class to manage a mail message
3 
4 #ifndef _mailmsg_h
5 #define _mailmsg_h
6 
7 extern "C" {
8 #include <sys/types.h>
9 #include <stdio.h>
10 }
11 
12 #include "my_regex.h"
13 #include "fifo.tmpl"
14 #include "iobottle.h"
15 #include "mime.h"
16 
17 #define CACHED_HEADER	"CACHED HEADER"
18 
19 /* Notes on the thread structure:
20 
21 	All messages have next and previous pointers that point to the
22 	indexed messages before and after them.  They also have thread
23 	next and previous pointers that point to the logical messages
24 	before and after them, following threads.  Messages within a
25 	thread have "threaded" and "thread_next" set.  Messages heading
26 	a thread have "thread_next" set, but "threaded" is not set.
27 */
28 #define NO_THREADS	0
29 #define HIDE_THREADS	1
30 #define SHOW_THREADS	2
31 
32 /* Forward declaration mailbox data */
33 class mailmsg;
34 struct mbox_data {
35 	mbox_data(IObottle *mailfile);
36 
37 	IObottle *MailFile;
38 	mailmsg *head;
39 	mailmsg *tail;
40 	int nmessages;
41 	int showthreads;
42 	bool aborted;
43 	bool saveall;
44 };
45 
46 class buflen;
47 class mailmsg {
48 
49 public:
50 	mailmsg(mbox_data *MBox);
51 	mailmsg(mbox_data *MBox, FILE *cache);
52 	void Add(mailmsg *msg);
Abort()53 	void Abort() { mbox->aborted = true; }
Aborted()54 	bool Aborted() { return(mbox->aborted); }
SetSave(bool doit)55 	void SetSave(bool doit) { mbox->saveall = doit; }
Saving(void)56 	bool Saving(void) { return(mbox->saveall); }
MBox()57 	mbox_data *MBox() { return mbox; }
58 	~mailmsg();
59 
60 	/* Mailbox stuff */
61 	void ThreadPass1();
62 	void ThreadPass2();
63 	int ThreadedOn(mailmsg *msg);
ShowThreads(int showthem)64 	void ShowThreads(int showthem) {
65 		mbox->showthreads = showthem;
66 	}
ShowThreads(void)67 	int ShowThreads(void) {
68 		return(mbox->showthreads);
69 	}
NumMessages(void)70 	int NumMessages(void) {
71 		return(mbox->nmessages);
72 	}
73 	/* Thread navigation stuff */
74 	mailmsg *ByIndex(int the_index);
75 	mailmsg *ByStatus(const char *the_status);
76 	mailmsg *ByMessageID(const char *messageID);
77 	int ThreadSize(void);
78 	int ThreadIndex(void);
ThreadNext(void)79 	mailmsg *ThreadNext(void) {
80 		return(thread_next);
81 	}
RawNext(void)82 	mailmsg *RawNext(void) { return privnext; }
83 	mailmsg *Next(void);
84 	mailmsg *Next(int howmany);
RawPrev(void)85 	mailmsg *RawPrev(void) { return privprev; }
86 	mailmsg *Prev(void);
87 	mailmsg *Prev(int howmany);
First(void)88 	mailmsg *First(void) {
89 		return mbox->head;
90 	}
Last(void)91 	mailmsg *Last(void) {
92 		return mbox->tail;
93 	}
SetNext(mailmsg * newnext)94 	void SetNext(mailmsg *newnext) {
95 		next = newnext;
96 	}
SetPrev(mailmsg * newprev)97 	void SetPrev(mailmsg *newprev) {
98 		prev = newprev;
99 	}
ReOrder(void)100 	void ReOrder(void) {
101 		next = privnext;
102 		prev = privprev;
103 	}
104 
105 	/* Header fields */
106 	char *GetHeader(char **keyholder);
107 	const char *GetField(const char *str);
MessageID(void)108 	const char *MessageID(void) {
109 		return messageID;
110 	}
Importance(void)111 	char Importance(void) {
112 		return importance;
113 	}
From(void)114 	const char *From(void) {
115 		const char *from;
116 
117 		from = GetField("From");
118 		if ( from == NULL ) {
119 			from = GetField("Reply-To");
120 		}
121 		return(from ? from : "Unknown");
122 	}
To(void)123 	const char *To(void) {
124 		const char *to;
125 
126 		to = GetField("To");
127 		if ( to == NULL ) {
128 			to = GetField("Apparently-To");
129 		}
130 		if ( to == NULL ) {
131 			to = GetField("X-Apparently-To");
132 		}
133 		if ( to == NULL ) {
134 			to = GetField("Cc");
135 		}
136 		return(to ? to : "Unknown");
137 	}
138 	/* Extract a human name from an email address, if possible */
139 	const char *Author();
140 	const char *Recipient();
141 	/* Return the message's subject */
Subject(void)142 	const char *Subject(void) {
143 		const char *subject = GetField("Subject");
144 		return(subject ? subject : "<no subject>");
145 	}
Subject_Key(void)146 	const char *Subject_Key(void) {
147 		return(subject_key ? subject_key : "");
148 	}
149 	/* Return the message's date in "Month Day" format */
150 	char *MonthDay(void);
151 
SetIndex(int newindex)152 	void SetIndex(int newindex) {
153 		index = newindex;
154 	}
Index(void)155 	int Index(void) {
156 		return(index);
157 	}
158 
159 	/* See/Set the status of the message */
160 	const char *Status(bool in_listing = false);
161 	const char *DiskStatus(void);
162 	void Status(const char *newstatus);
Changed(void)163 	bool Changed(void) {
164 		return(changed);
165 	}
NoChange(void)166 	void NoChange(void) {
167 		changed = false;
168 	}
169 	mailmsg *SkipDeleted(int *nrows);
170 
171 	/* Get the body of the message */
172 	MIME_body *Body(void);
173 	/* Make sure the body hasn't changed */
174 	bool Verify(void);
175 	/* Save the message to a file */
176 	int Save(char *filename);
177 	/* Save the status to the mailfile */
178 	int SaveStatus();
179 	/* Save the message to the mailfile */
180 	int SaveToDisk(Fifo<buflen> *ringbuf, int &gap);
181 	/* Save the header to the cache */
182 	int SaveToCache(FILE *cache);
183 
184 	/* Get the message offset in the mailfile */
SetOffset(long offset)185 	void SetOffset(long offset) { mstart = offset; }
SetLength(long length)186 	void SetLength(long length) { mlength = length; }
Offset(void)187 	long Offset(void) { return mstart; }
Length(void)188 	long Length(void) { return mlength; }
189 
190 private:
191 	static char *boundary[];	/* The message separator */
192 
193 	/* Real variables. :-) */
194 	int          index;
195 	IObottle    *MailFile;
196 	mbox_data   *mbox;
197 	const char  *messageID;
198 	char        *status;
199 	long         mstart;		/* Offset of mail message */
200 	long         mlength;		/* Length of message */
201 	char         checksum[33];	/* header checksum (text) */
202 	Hash<char *> fieldtab;		/* Header fields */
203 	MIME_body   *body;
204 	bool         changed;
205 
206 	/* String of messages stuff */
207 	mailmsg *privnext, *privprev;
208 	mailmsg *next, *prev;
209 	mailmsg *thread_next, *thread_prev;
210 	const char *thread_key;
211 	char  importance;
212 	char *author;
213 	char *recipient;
214 	char *subject_key;
215 	int   subject_hash;
216 	int   threaded;
217 	int   thread_size;
218 	int   threaded_to;
219 	char *NormalizeSubject(const char *subject);
220 	int   HashString(char *str);
221 
222 	/* Return a translation of the given status string */
TranslateStatus(const char * str)223 	const char *TranslateStatus(const char *str) {
224 		if ( ! str )
225 			str = "N";
226 		else if ( *str == 'R' )
227 			str = " ";
228 		return(str);
229 	}
230 	void FinishInit();
231 	void ThreadMe(mailmsg *msg);
232 	void NewField(const char *name, const char *value);
233 };
234 
235 #endif /* _mailmsg_h */
236