1 /*
2 ** Copyright 2002, Double Precision Inc.
3 **
4 ** See COPYING for distribution information.
5 */
6 #ifndef libmail_mbox_H
7 #define libmail_mbox_H
8 
9 #include "libmail_config.h"
10 #include "mail.H"
11 
12 #include <courier-unicode.h>
13 #include "maildir/maildirkeywords.h"
14 
15 #include <time.h>
16 #include <unistd.h>
17 #include <stdio.h>
18 #include <queue>
19 #include <map>
20 #include <set>
21 #include <vector>
22 
23 #include "mboxmagictag.H"
24 #include "generic.H"
25 
26 #include "namespace.H"
27 
28 struct ll_mail;
29 
30 LIBMAIL_START
31 
32 class file;
33 
34 /////////////////////////////////////////////////////////////////////////
35 //
36 // Legacy mbox driver.
37 //
38 //
39 class mbox : public mail::account, public generic {
40 
41 	void resumed();
42 	void handler(std::vector<pollfd> &fds, int &timeout);
43 
44 	bool calledDisconnected; // True if the disconnect callback was invoked
45 	bool magicInbox;	// True if this account uses INBOX
46 	std::string inboxSpoolPath; // Path to the system spool inbox
47 	std::string inboxMailboxPath; // $HOME/mboxAccount
48 
49 	std::string rootPath;   // Root path for folders.
50 
51 	class folder : public mail::folder {
52 
53 		std::string path;
54 		std::string name;
55 		mbox &mboxAccount;
56 
57 		bool saveHasMessages;
58 		bool saveHasFolders;
59 
60 		class closeCallback : public mail::callback {
61 
reportProgress(size_t bytesCompleted,size_t bytesEstimatedTotal,size_t messagesCompleted,size_t messagesEstimatedTotal)62 			void reportProgress(size_t bytesCompleted,
63 					    size_t bytesEstimatedTotal,
64 
65 					    size_t messagesCompleted,
66 					    size_t messagesEstimatedTotal) {}
67 			//TODO
68 
69 		public:
70 			ptr<mbox> origmbox;
71 			mail::callback &origCallback;
72 			mail::callback::folder &origFolderCallback;
73 			std::string origPath;
74 
75 			closeCallback(mbox *origmboxArg,
76 				      mail::callback &origCallbackArg,
77 				      mail::callback::folder
78 				      &origFolderCallbackarg,
79 				      std::string origPathArg);
80 			~closeCallback();
81 
82 			void success(std::string);
83 			void fail(std::string);
84 		};
85 
86 		class add;
87 
88 	public:
89 		friend class mbox;
90 
91 		folder(std::string pathArg,
92 		       mbox &mboxArg);
93 		~folder();
94 
95 		folder(const mbox::folder &);
96 
97 		static std::string defaultName(std::string path);
98 
99 		void sameServerAsHelperFunc() const;
100 
101 		std::string getName() const;
102 		std::string getPath() const;
103 
104 		bool hasMessages() const;
105 		bool hasSubFolders() const;
106 
107 		bool isParentOf(std::string path) const;
108 
109 		void hasMessages(bool);
110 		void hasSubFolders(bool);
111 
112 
113 		void getParentFolder(callback::folderList &callback1,
114 				     callback &callback2) const;
115 
116 		void readFolderInfo( mail::callback::folderInfo
117 				     &callback1,
118 				     mail::callback &callback2) const;
119 
120 		void readSubFolders( mail::callback::folderList &callback1,
121 				     mail::callback &callback2) const;
122 
123 		mail::addMessage *addMessage(mail::callback &callback) const;
124 
125 		void createSubFolder(std::string name, bool isDirectory,
126 				     mail::callback::folderList &callback1,
127 				     mail::callback &callback2) const;
128 
129 		void create(bool isDirectory,
130 			    mail::callback &callback) const;
131 
132 		void destroy(mail::callback &callback, bool destroyDir)
133 			const;
134 
135 		void renameFolder(const mail::folder *newParent,
136 				  std::string newName,
137 				  mail::callback::folderList &callback1,
138 				  callback &callback) const;
139 
140 		mail::folder *clone() const;
141 		std::string toString() const;
142 
143 		void open(mail::callback &openCallback,
144 			  snapshot *restoreSnapshot,
145 			  mail::callback::folder &folderCallback) const;
146 	};
147 
148 	// Special folders
149 
150 	folder inboxFolder, hierarchyFolder;
151 
152 	// Stuff gets done by creating a task object, and pushing it into
153 	// the tasks queue (see below).  The first task in the queue gets
154 	// its doit() method called.  doit() receives the timeout parameter
155 	// from mbox::handler(), which it can adjust, if necessary.
156 	//
157 	// The doit() method should invoke done() when its done, otherwise
158 	// it can simply exit, and be re-invoked the next time the handler
159 	// is invoked.
160 	//
161 	// The task's disconnected() method gets invoked if the mbox
162 	// object is destroyed in mid-stream, or if there's a fatal timeout
163 	// trying to lock the mboxAccount file.  disconnected() should NOT invoke
164 	// done(), because that's going to happen anyway as soon as
165 	// disconnected() wraps up.  disconnected() is present so that
166 	// the task can invoke any application callbacks the task is
167 	// responsible for.
168 
169 	class task {
170 
171 	protected:
172 		mbox &mboxAccount;
173 
174 	public:
175 		task(mbox &mboxAccount);
176 		virtual ~task();
177 
178 		virtual void doit(int &timeout)=0;
179 		virtual void disconnected()=0;
180 
181 		virtual void done();
182 	};
183 
184 	// TimedTask subclasses from task, to provide a task with a timeout.
185 	//
186 	// Subclasses should implement bool doit().  bool doit() should return
187 	// true if the task succeeded, or failed.  If the task is deferred,
188 	// the subclass's doit() method should return false.
189 	//
190 	// The subclass should call either fail() or success(), which invokes
191 	// the callback's method, then invokes done().
192 	//
193 	// The timedOut() method invokes the callback's fail method, if this
194 	// tasks times out.  The subclass can override this method to provide
195 	// some value-added functionality.
196 	//
197 
198 	class TimedTask : public mbox::task {
199 
200 		time_t timeout;
201 		time_t nextTry;
202 
203 	protected:
204 		mail::callback &callback;
205 	public:
206 		TimedTask(mbox &mboxAccount,
207 			  mail::callback &callbackArg, int timeoutArg=60);
208 		~TimedTask();
209 
210 		void doit(int &timeout);
211 
212 		void fail(std::string errmsg);
213 		virtual bool doit()=0;
214 		virtual void timedOut();
215 		virtual void disconnected();
216 	};
217 
218 	// This is a wrapper for liblock's locking functions
219 
220 	class lock {
221 		struct ll_mail *ll;
222 
223 		int fd;
224 
225 		bool readOnlyLock;
226 
227 		lock();
228 
229 	public:
230 		lock(std::string filename); // File to create an mboxAccount lock for.
231 		~lock();
232 
233 		bool operator()(bool readOnly=false);
234 		// Attempt to lock this mboxAccount file, via liblock.
235 		// Set readOnly to true if a read-only lock is permissible.
236 
getfd()237 		int getfd() const { return fd; }
238 		// Success - return the file descriptor of locked file.
239 
readOnly()240 		bool readOnly() const { return readOnlyLock; }
241 		// Indicator whether the file was locked in read-only mode.
242 
243 
244 		lock *copy();
245 		// Copy this lock structure to another object, used for
246 		// optimizing consecutive parallel locks.
247 
248 	};
249 
250 	class StatusTask;
251 	class sighandler;
252 	class OpenTask;
253 	class CheckNewMailTask;
254 
255 	class LockTask;
256 	class GenericReadTask;
257 	class GenericGetMessageTask;
258 	class ExpungeTask;
259 
260 	class MultiLock;
261 	class MultiLockGenericMessageRead;
262 	class MultiLockGenericAttributes;
263 	class MultiLockRelease;
264 	class RenameTask;
265 
266 	std::queue<task *> tasks;
267 
268 	void installTask(task *);
269 
270 	// The currently open folder.
271 
272 	std::string currentFolder;
273 	bool currentFolderReadOnly;	// Folder opened in readonly mode.
274 
275 	off_t folderSavedSize;
276 	time_t folderSavedTimestamp;
277 	// Detect if someone else modified the folder file.
278 
279 	std::string multiLockFilename;
280 	lock *multiLockLock;
281 
282 	bool folderDirty;
283 	// Set to true when message metadata has been modified, but the
284 	// folder file has not been updated to reflect these changes.
285 
286 	bool newMessages;
287 	// Set when index is updated from folderMessageIndex, and new messages
288 	// were found.
289 
290 	////////////////////////////////////////////////////////
291 	//
292 	// The actual parsed contents of the folder:
293 
294 	struct mboxMessageIndex {
295 
296 		off_t startingPos;	// Starting offset
297 		time_t internalDate;	// Synthesized message arrival date
298 		mboxMagicTag tag;	// The synthesized UID.
299 	};
300 
301 	mail::keywords::Hashtable keywordHashtable;
302 	std::vector<mboxMessageIndex> folderMessageIndex; // The folder
303 
304 	std::map<std::string, size_t> uidmap;	// Look up index from uid.
305 
306 	// Generic interface caches the temporary file with the most recently
307 	// opened message:
308 
309 	std::string cachedMessageUid;	// The cached uid
310 	struct rfc2045 *cachedMessageRfcp;
311 	FILE *cachedMessageFp;
312 
313 	void resetFolder();
314 
315 	mail::callback::folder *currentFolderCallback;
316 
317 	// The application sees the following index:
318 
319 	std::vector<mail::messageInfo> index;
320 
321 	// Update the mboxAccount file.  This is where everything happens.
322 
323 	bool scan(file &scanFile,
324 		  file *saveFile,
325 		  bool reopening,
326 		  std::set<std::string> *deleteMsgs,
327 		  bool rewrite,
328 		  mail::callback *progress);
329 
330 	void checkNewMail();
331 
332 public:
333 	friend class folder;
334 	friend class task;
335 	friend class TimedTask;
336 	friend class StatusTask;
337 	friend class OpenTask;
338 	friend class CheckNewMailTask;
339 	friend class RenameTask;
340 
341 	friend class LockTask;
342 	friend class GenericReadTask;
343 	friend class GenericGetMessageTask;
344 	friend class ExpungeTask;
345 	friend class MultiLock;
346 	friend class MultiLockGenericMessageRead;
347 	friend class MultiLockGenericAttributes;
348 	friend class MultiLockRelease;
349 
350 	mbox(bool magicInboxArg,
351 		   std::string folderRootArg, mail::callback &callback,
352 		   mail::callback::disconnect &disconnect_callback);
353 	~mbox();
354 
355 	void logout(mail::callback &callback);
356 	void checkNewMail(mail::callback &callback);
357 
358 	bool hasCapability(std::string capability);
359 	std::string getCapability(std::string capability);
360 
361 	mail::folder *folderFromString(std::string);
362 
363 	void readTopLevelFolders(mail::callback::folderList &callback1,
364 				 mail::callback &callback2);
365 
366 	void findFolder(std::string folder,
367 			mail::callback::folderList &callback1,
368 			mail::callback &callback2);
369 	std::string translatePath(std::string path);
370 
371 	static std::string translatePathCommon(std::string path,
372 					       const char *sep);
373 
374 	void readMessageAttributes(const std::vector<size_t> &messages,
375 				   MessageAttributes attributes,
376 				   mail::callback::message &callback);
377 
378 	void readMessageContent(const std::vector<size_t> &messages,
379 				bool peek,
380 				enum mail::readMode readType,
381 				mail::callback::message &callback);
382 
383 	void readMessageContent(size_t messageNum,
384 				bool peek,
385 				const mimestruct &msginfo,
386 				enum mail::readMode readType,
387 				mail::callback::message &callback);
388 
389 	void readMessageContentDecoded(size_t messageNum,
390 				       bool peek,
391 				       const mimestruct &msginfo,
392 				       mail::callback::message &callback);
393 
394 	size_t getFolderIndexSize();
395 	mail::messageInfo getFolderIndexInfo(size_t);
396 
397 	void saveFolderIndexInfo(size_t,
398 					 const mail::messageInfo &,
399 					 mail::callback &);
400 
401 	void updateFolderIndexFlags(const std::vector<size_t> &messages,
402 				    bool doFlip,
403 				    bool enableDisable,
404 				    const mail::messageInfo &flags,
405 				    mail::callback &callback);
406 
407 	void updateFolderIndexInfo(mail::callback &);
408 
409 
410 	void updateKeywords(const std::vector<size_t> &messages,
411 			    const std::set<std::string> &keywords,
412 			    bool setOrChange,
413 			    // false: set, true: see changeTo
414 			    bool changeTo,
415 			    callback &cb);
416 	void getFolderKeywordInfo(size_t, std::set<std::string> &);
417 
418 	bool genericProcessKeyword(size_t messageNumber,
419 				   generic::updateKeywordHelper &helper);
420 
421 	void removeMessages(const std::vector<size_t> &messages,
422 			    callback &cb);
423 
424 	void copyMessagesTo(const std::vector<size_t> &messages,
425 			    mail::folder *copyTo,
426 			    mail::callback &callback);
427 
428 	void searchMessages(const class mail::searchParams &searchInfo,
429 			    class mail::searchCallback &callback);
430 
431 	bool verifyUid(std::string uid, size_t &messageNumber,
432 		       mail::callback &callback);
433 
434 
435 	void genericMessageRead(std::string uid,
436 				size_t messageNumber,
437 				bool peek,
438 				mail::readMode,
439 				mail::callback::message &callback);
440 
441 	void genericMessageSize(std::string uid,
442 				size_t messageNumber,
443 				mail::callback::message &callback);
444 
445 	void genericGetMessageFd(std::string uid,
446 				 size_t messageNumber,
447 				 bool peek,
448 				 int &fdRet,
449 				 mail::callback &callback);
450 
451 	void genericGetMessageStruct(std::string uid,
452 				     size_t messageNumber,
453 				     struct rfc2045 *&structRet,
454 				     mail::callback &callback);
455 
456 	bool genericCachedUid(std::string uid);
457 
458 	void genericGetMessageFdStruct(std::string uid,
459 				       size_t messageNumber,
460 				       bool peek,
461 				       int &fdRet,
462 				       struct rfc2045 *&structret,
463 				       mail::callback &callback);
464 	void genericMarkRead(size_t messageNumber);
465 };
466 
467 LIBMAIL_END
468 
469 #endif
470