1 /*
2 ** Copyright 2002-2004, Double Precision Inc.
3 **
4 ** See COPYING for distribution information.
5 */
6 #include "libmail_config.h"
7 #include "maildir/config.h"
8 #include "maildir/maildirmisc.h"
9 #include <courier-unicode.h>
10 #include "maildirfolder.H"
11 #include "maildiradd.H"
12 #include "mbox.H"
13 #include "misc.H"
14 #include <list>
15 #include <algorithm>
16 #include <errno.h>
17 #include <string.h>
18 #include <fcntl.h>
19
20 #include <sys/stat.h>
21 #include <sys/types.h>
22 #include <iostream>
23
24 #if HAVE_DIRENT_H
25 # include <dirent.h>
26 # define NAMLEN(dirent) strlen((dirent)->d_name)
27 #else
28 # define dirent direct
29 # define NAMLEN(dirent) (dirent)->d_namlen
30 # if HAVE_SYS_NDIR_H
31 # include <sys/ndir.h>
32 # endif
33 # if HAVE_SYS_DIR_H
34 # include <sys/dir.h>
35 # endif
36 # if HAVE_NDIR_H
37 # include <ndir.h>
38 # endif
39 #endif
40
41 using namespace std;
42
folder(mail::maildir * maildirArg,string pathArg)43 mail::maildir::folder::folder(mail::maildir *maildirArg,
44 string pathArg)
45 : mail::folder(maildirArg),
46 maildirAccount(maildirArg),
47 path(pathArg),
48 hasMessagesFlag(true),
49 hasSubfoldersFlag(true)
50 {
51 name=pathArg;
52
53 size_t p=name.rfind('.');
54
55 if (p != std::string::npos)
56 name=name.substr(p+1);
57
58 // Convert the name of the folder from modified UTF-7
59 // (Courier compatibility) to the current charset.
60
61 char *s=unicode_convert_tobuf(name.c_str(),
62 unicode_x_smap_modutf8,
63 unicode_default_chset(),
64 NULL);
65
66 if (s)
67 {
68 try {
69 name=s;
70 free(s);
71 } catch (...) {
72 free(s);
73 }
74 }
75 }
76
~folder()77 mail::maildir::folder::~folder()
78 {
79 }
80
sameServerAsHelperFunc()81 void mail::maildir::folder::sameServerAsHelperFunc() const
82 {
83 }
84
getName()85 string mail::maildir::folder::getName() const
86 {
87 if (path == "INBOX")
88 return hasSubFolders() ? "Folders":"INBOX";
89
90 return name;
91 }
92
getPath()93 string mail::maildir::folder::getPath() const
94 {
95 return path;
96 }
97
hasMessages()98 bool mail::maildir::folder::hasMessages() const
99 {
100 return hasMessagesFlag;
101 }
102
hasSubFolders()103 bool mail::maildir::folder::hasSubFolders() const
104 {
105 return hasSubfoldersFlag;
106 }
107
isParentOf(string otherPath)108 bool mail::maildir::folder::isParentOf(string otherPath) const
109 {
110 string s=path + ".";
111
112 return (strncmp(otherPath.c_str(), s.c_str(), s.size()) == 0);
113 }
114
hasMessages(bool flag)115 void mail::maildir::folder::hasMessages(bool flag)
116 {
117 hasMessagesFlag=flag;
118 }
119
hasSubFolders(bool flag)120 void mail::maildir::folder::hasSubFolders(bool flag)
121 {
122 hasSubfoldersFlag=flag;
123 }
124
125 class mail::maildir::indexSort {
126 public:
127 indexSort();
128 ~indexSort();
129
130 bool operator()(const mail::maildir::maildirMessageInfo &a,
131 const mail::maildir::maildirMessageInfo &b);
132 };
133
indexSort()134 mail::maildir::indexSort::indexSort()
135 {
136 }
137
~indexSort()138 mail::maildir::indexSort::~indexSort()
139 {
140 }
141
142 // Sort messages in some reasonable order. Rely on the timestamp component
143 // of the maildirfilename.
144
operator()145 bool mail::maildir::indexSort::operator()
146 (const mail::maildir::maildirMessageInfo &a,
147 const mail::maildir::maildirMessageInfo &b)
148 {
149 unsigned long at=atol(a.lastKnownFilename.c_str()),
150 bt=atol(b.lastKnownFilename.c_str());
151
152 if ( at != bt)
153 return at < bt;
154
155 return strcmp(a.lastKnownFilename.c_str(),
156 b.lastKnownFilename.c_str()) < 0;
157 }
158
159 // Scan a maildirAccount
160
scan(string folderStr,vector<maildirMessageInfo> & index,bool scanNew)161 bool mail::maildir::scan(string folderStr, vector<maildirMessageInfo> &index,
162 bool scanNew)
163 {
164 string p;
165
166 char *d=maildir_name2dir(path.c_str(), folderStr.c_str());
167
168 if (!d)
169 return false;
170
171 try {
172 p=d;
173 free(d);
174 } catch (...) {
175 free(d);
176 LIBMAIL_THROW(LIBMAIL_THROW_EMPTY);
177 }
178
179 static const char * const subdirs[]={"/cur","/new"};
180
181 size_t i;
182
183 for (i=0; i<(scanNew ? 2:1); i++)
184 {
185 string n=p + subdirs[i];
186
187 DIR *dirp=opendir(n.c_str());
188
189 try {
190 struct dirent *de;
191
192 while (dirp && (de=readdir(dirp)) != NULL)
193 {
194 if (de->d_name[0] == '.')
195 continue;
196
197
198 maildirMessageInfo newInfo;
199
200 newInfo.lastKnownFilename=de->d_name;
201
202 // Use the filename as the uid
203
204 newInfo.uid=de->d_name;
205
206 size_t p=newInfo.uid.find(MDIRSEP[0]);
207
208 if (p != std::string::npos)
209 newInfo.uid=newInfo.uid.substr(0, p);
210
211 mail::maildir::updateFlags(de->d_name,
212 newInfo);
213 newInfo.recent= i > 0;
214 index.push_back(newInfo);
215 }
216
217 if (dirp)
218 closedir(dirp);
219 } catch (...) {
220 if (dirp)
221 closedir(dirp);
222 LIBMAIL_THROW(LIBMAIL_THROW_EMPTY);
223 }
224 }
225
226 sort(index.begin(), index.end(), indexSort());
227 return true;
228 }
229
getParentFolder(callback::folderList & callback1,callback & callback2)230 void mail::maildir::folder::getParentFolder(callback::folderList &callback1,
231 callback &callback2) const
232 {
233 if (isDestroyed(callback2))
234 return;
235
236 size_t n;
237
238 n=path.rfind('.');
239
240 if (n == std::string::npos)
241 n=0;
242
243 maildirAccount->findFolder(path.substr(0, n),
244 callback1,
245 callback2);
246 }
247
readFolderInfo(mail::callback::folderInfo & callback1,mail::callback & callback2)248 void mail::maildir::folder::readFolderInfo( mail::callback::folderInfo
249 &callback1,
250 mail::callback &callback2) const
251 {
252 if (isDestroyed(callback2))
253 return;
254
255 callback1.messageCount=0;
256 callback1.unreadCount=0;
257
258 vector<maildirMessageInfo> dummyIndex;
259
260 if (!maildirAccount->scan(path, dummyIndex, true))
261 {
262 callback1.success();
263 callback2.fail("Invalid folder");
264 return;
265 }
266
267 vector<maildirMessageInfo>::iterator b=dummyIndex.begin(),
268 e=dummyIndex.end();
269
270 while (b != e)
271 {
272 callback1.messageCount++;
273 if ( b->unread)
274 callback1.unreadCount++;
275 b++;
276 }
277
278 callback1.success();
279 callback2.success("OK");
280 }
281
listinfo()282 mail::maildir::folder::listinfo::listinfo()
283 {
284 }
285
~listinfo()286 mail::maildir::folder::listinfo::~listinfo()
287 {
288 }
289
290 // Callback that lists maildirAccount folders.
291 // The callback filters only the folders under the list path
292
maildir_list_callback(const char * folder,void * vp)293 void mail::maildir::folder::maildir_list_callback(const char *folder,
294 void *vp)
295 {
296 mail::maildir::folder::listinfo *li=
297 (mail::maildir::folder::listinfo *)vp;
298
299 if (strncmp(folder, li->path.c_str(), li->path.size()) ||
300 folder[li->path.size()] != '.')
301 return; // Outside the hierarchy being listed.
302
303 folder += li->path.size();
304 ++folder;
305
306 // If the remaining portion of the name has another period, there's
307 // a subdirectory there. Otherwise, it's a file.
308 // It's ok when we get multiple folders in the same subdirectory,
309 // subdirs is a STL set, which gets rid of duplicates
310
311 const char *p=strchr(folder, '.');
312
313 if (p)
314 li->subdirs.insert(string(folder, p));
315 else
316 li->list.insert(string(folder));
317 }
318
readSubFolders(mail::callback::folderList & callback1,mail::callback & callback2)319 void mail::maildir::folder::readSubFolders( mail::callback::folderList
320 &callback1,
321 mail::callback &callback2) const
322 {
323 if (isDestroyed(callback2))
324 return;
325
326 if (path.size() == 0)
327 {
328 maildirAccount->readTopLevelFolders(callback1, callback2);
329 return;
330 }
331
332 listinfo li;
333
334 li.path=path;
335
336 maildir_list(maildirAccount->path.c_str(),
337 &mail::maildir::folder::maildir_list_callback,
338 &li);
339
340 list<mail::folder *> folderList;
341 list<mail::folder *>::iterator b, e;
342
343 try {
344 // Create a list of folder objects from the list of folder
345 // names in listinfo. Create a list in two passes.
346
347 // First pass - build names of folders. If the folder is
348 // also found in the subdirectory list, make it a dual-purpose
349 // folder/directory.
350
351 buildFolderList(folderList, &li.list, &li.subdirs);
352
353 // Second pass - build remaining subdirs.
354
355 buildFolderList(folderList, NULL, &li.subdirs);
356
357 // Cleanup for the callback
358 vector<const mail::folder *> myList;
359
360 b=folderList.begin();
361 e=folderList.end();
362
363 while (b != e)
364 myList.push_back(*b++);
365
366 callback1.success(myList);
367 callback2.success("OK");
368
369 } catch (...) {
370 b=folderList.begin();
371 e=folderList.end();
372
373 while (b != e)
374 {
375 delete *b;
376
377 b++;
378 }
379 LIBMAIL_THROW(LIBMAIL_THROW_EMPTY);
380 }
381
382 b=folderList.begin();
383 e=folderList.end();
384
385 while (b != e)
386 {
387 delete *b;
388
389 b++;
390 }
391 }
392
buildFolderList(list<mail::folder * > & folderList,set<string> * folders,set<string> * dirs)393 void mail::maildir::folder::buildFolderList(list<mail::folder *> &folderList,
394 set<string> *folders,
395 set<string> *dirs) const
396 {
397 set<string>::iterator b, e;
398
399 if (folders)
400 {
401 b=folders->begin();
402 e=folders->end();
403 }
404 else
405 {
406 b=dirs->begin();
407 e=dirs->end();
408 }
409
410 while (b != e)
411 {
412 string name= *b++;
413
414 folder *p=new folder(maildirAccount, path + "." + name);
415
416 if (!p)
417 LIBMAIL_THROW(strerror(errno));
418
419 try {
420 if (folders)
421 {
422 p->hasMessages(true);
423 p->hasSubFolders(false);
424
425 if (dirs->count(name) > 0)
426 // Also a subdir
427 {
428 p->hasSubFolders(true);
429 dirs->erase(name);
430 // Don't add this folder when we do
431 // a directory.
432 }
433 }
434 else
435 {
436 p->hasMessages(false);
437 p->hasSubFolders(true);
438 }
439
440 folderList.push_back(p);
441 } catch (...) {
442 delete p;
443 LIBMAIL_THROW(LIBMAIL_THROW_EMPTY);
444 }
445 }
446 }
447
addMessage(mail::callback & callback)448 mail::addMessage *mail::maildir::folder::addMessage(mail::callback
449 &callback) const
450 {
451 if (isDestroyed(callback))
452 return NULL;
453
454 string folderPath;
455
456 char *p=maildir_name2dir(maildirAccount->path.c_str(), path.c_str());
457
458 if (!p)
459 {
460 callback.fail(strerror(errno));
461 return NULL;
462 }
463
464 try {
465 folderPath=p;
466 free(p);
467 } catch (...) {
468 free(p);
469 LIBMAIL_THROW(LIBMAIL_THROW_EMPTY);
470 }
471
472 mail::maildir::addmessage *m=new
473 mail::maildir::addmessage(maildirAccount, folderPath, callback);
474
475 if (!m)
476 {
477 callback.fail(strerror(errno));
478 return NULL;
479 }
480
481 return m;
482 }
483
moveMessagesTo(const vector<size_t> & messages,mail::folder * copyTo,mail::callback & callback)484 void mail::maildir::moveMessagesTo(const vector<size_t> &messages,
485 mail::folder *copyTo,
486 mail::callback &callback)
487 {
488 sameServerFolderPtr=NULL;
489 copyTo->sameServerAsHelperFunc();
490
491 if (sameServerFolderPtr == NULL)
492 {
493 mail::account::moveMessagesTo(messages, copyTo, callback);
494 return;
495 }
496
497 string destFolderPath;
498
499 char *p=maildir_name2dir(path.c_str(),
500 sameServerFolderPtr->path.c_str());
501
502 if (!p)
503 {
504 callback.fail(strerror(errno));
505 return;
506 }
507
508 try {
509 destFolderPath=p;
510 free(p);
511 } catch (...) {
512 free(p);
513 LIBMAIL_THROW(LIBMAIL_THROW_EMPTY);
514 }
515
516 vector<size_t>::const_iterator b=messages.begin(), e=messages.end();
517
518 while (b != e)
519 {
520 size_t n=*b++;
521
522 string messageFn=getfilename(n);
523
524 if (messageFn.size() > 0)
525 {
526 string destName= destFolderPath
527 + messageFn.substr(messageFn.rfind('/'));
528
529 rename(messageFn.c_str(), destName.c_str());
530 }
531 }
532 updateFolderIndexInfo(&callback, false);
533 }
534
createSubFolder(string name,bool isDirectory,mail::callback::folderList & callback1,mail::callback & callback2)535 void mail::maildir::folder::createSubFolder(string name, bool isDirectory,
536 mail::callback::folderList
537 &callback1,
538 mail::callback &callback2) const
539 {
540 if (isDestroyed(callback2))
541 return;
542
543 // The name of the folder is translated from the local charset
544 // to modified UTF-7 (Courier-IMAP compatibility), with the following
545 // blacklisted characters:
546
547 char *p=unicode_convert_tobuf(name.c_str(), unicode_default_chset(),
548 unicode_x_smap_modutf8, NULL);
549
550 if (!p)
551 {
552 callback2.fail(strerror(errno));
553 return;
554 }
555
556 std::string nameutf7;
557
558 errno=ENOMEM;
559 try {
560 nameutf7=p;
561 free(p);
562 } catch (...) {
563 free(p);
564 callback2.fail(strerror(errno));
565 return;
566 }
567
568 mail::maildir::folder newFolder(maildirAccount, path + "." + nameutf7);
569
570 newFolder.hasMessagesFlag= ! (newFolder.hasSubfoldersFlag=
571 isDirectory);
572
573 if (!newFolder.doCreate(isDirectory))
574 {
575 callback2.fail(strerror(errno));
576 return;
577 }
578
579 vector<const mail::folder *> folders;
580
581 folders.push_back(&newFolder);
582 callback1.success( folders );
583 callback2.success("Mail folder created");
584 }
585
doCreate(bool isDirectory)586 bool mail::maildir::folder::doCreate(bool isDirectory) const
587 {
588 if (isDirectory)
589 return true; // Pretend
590
591 if (maildirAccount->ispop3maildrop)
592 {
593 errno=EPERM;
594 return false; // POP3 maildrops don't have folders.
595 }
596
597 string subdir;
598
599 char *d=maildir_name2dir(maildirAccount->path.c_str(), path.c_str());
600 // Checks for name validity.
601
602 if (!d)
603 return false;
604
605 try {
606 subdir=d;
607 free(d);
608 } catch (...) {
609 free(d);
610 LIBMAIL_THROW(LIBMAIL_THROW_EMPTY);
611 }
612
613 return mail::maildir::maildirmake(subdir, true);
614 }
615
616
maildirmake(string subdir,bool isFolder)617 bool mail::maildir::maildirmake(string subdir, bool isFolder)
618 {
619 string nsubdir=subdir + "/new",
620 csubdir=subdir + "/cur",
621 tsubdir=subdir + "/tmp";
622
623 if (mkdir(subdir.c_str(), 0700) == 0)
624 {
625 if (mkdir(nsubdir.c_str(), 0700) == 0)
626 {
627 if (mkdir(tsubdir.c_str(), 0700) == 0)
628 {
629 if (mkdir(csubdir.c_str(), 0700) == 0)
630 {
631 if (!isFolder)
632 return true;
633
634 string f=subdir +
635 "/maildirfolder";
636
637 int fd=::open(f.c_str(),
638 O_CREAT |
639 O_RDWR, 0666);
640
641 if (fd >= 0)
642 {
643 close(fd);
644 return true;
645 }
646 rmdir(csubdir.c_str());
647 }
648 rmdir(tsubdir.c_str());
649 }
650 rmdir(nsubdir.c_str());
651 }
652 rmdir(subdir.c_str());
653 }
654
655 return false;
656 }
657
create(bool isDirectory,mail::callback & callback)658 void mail::maildir::folder::create(bool isDirectory,
659 mail::callback &callback) const
660 {
661 if (!doCreate(isDirectory))
662 {
663 callback.fail(strerror(errno));
664 }
665 else
666 {
667 callback.success("Mail folder created");
668 }
669 }
670
destroy(mail::callback & callback,bool destroyDir)671 void mail::maildir::folder::destroy(mail::callback &callback,
672 bool destroyDir) const
673 {
674 if (isDestroyed(callback))
675 return;
676
677 if (!destroyDir) // Folder directories are imaginary, cannot be nuked
678 {
679 string s;
680 char *d=maildir_name2dir(maildirAccount->path.c_str(),
681 path.c_str());
682 if (!d)
683 {
684 callback.fail(strerror(errno));
685 return;
686 }
687
688 try {
689 s=d;
690 free(d);
691 } catch (...) {
692 free(d);
693 LIBMAIL_THROW(LIBMAIL_THROW_EMPTY);
694 }
695
696 if (!mail::maildir::maildirdestroy(s))
697 {
698 callback.fail(strerror(errno));
699 return;
700 }
701 }
702
703 callback.success("Mail folder deleted");
704 }
705
renameFolder(const mail::folder * newParent,std::string newName,mail::callback::folderList & callback1,mail::callback & callback2)706 void mail::maildir::folder::renameFolder(const mail::folder *newParent,
707 std::string newName,
708 mail::callback::folderList &callback1,
709 mail::callback &callback2) const
710 {
711 if (isDestroyed(callback2))
712 return;
713
714 if (maildirAccount->folderPath.size() > 0)
715 {
716 size_t l=path.size();
717
718 if (strncmp(maildirAccount->folderPath.c_str(),
719 path.c_str(), l) == 0 &&
720 ((maildirAccount->folderPath.c_str())[l] == 0 ||
721 (maildirAccount->folderPath.c_str())[l] == '.'))
722 {
723 callback2.fail("Cannot RENAME currently open folder.");
724 return;
725 }
726 }
727
728 // The name of the folder is translated from the local charset
729 // to modified UTF-7 (Courier-IMAP compatibility), with the following
730 // blacklisted characters:
731
732 char *s=unicode_convert_tobuf(newName.c_str(),
733 unicode_default_chset(),
734 unicode_x_smap_modutf8, NULL);
735
736 if (!s)
737 {
738 callback2.fail(strerror(errno));
739 return;
740 }
741
742 std::string nameutf7;
743
744 errno=ENOMEM;
745 try {
746 nameutf7=s;
747 free(s);
748 } catch (...) {
749 free(s);
750 callback2.fail(strerror(errno));
751 return;
752 }
753
754 mail::maildir::folder newFolder(maildirAccount,
755 (newParent ?
756 newParent->getPath() + ".":
757 string("")) + nameutf7);
758
759 newFolder.hasMessages( hasMessages() );
760 newFolder.hasSubFolders( hasSubFolders() );
761
762 vector<const mail::folder *> folders;
763
764 // Paths are INBOX.foo
765
766 string from, to;
767
768 char *p=maildir_name2dir(".", path.c_str());
769
770 if (p)
771 try {
772 from=p+2; // Skip ./
773 free(p);
774 } catch (...) {
775 free(p);
776 LIBMAIL_THROW(LIBMAIL_THROW_EMPTY);
777 }
778
779 p=maildir_name2dir(".", newFolder.path.c_str());
780 if (p)
781 try {
782 to=p+2; // Skip ./
783 free(p);
784 } catch (...) {
785 free(p);
786 LIBMAIL_THROW(LIBMAIL_THROW_EMPTY);
787 }
788
789
790 if (from.size() > 0 &&
791 to.size() > 0 &&
792 maildir_rename(maildirAccount->path.c_str(),
793 from.c_str(), to.c_str(),
794 MAILDIR_RENAME_FOLDER |
795 MAILDIR_RENAME_SUBFOLDERS, NULL))
796 {
797 callback2.fail(strerror(errno));
798 }
799 else
800 {
801 folders.push_back(&newFolder);
802 callback1.success( folders );
803 callback2.success("Mail folder renamed");
804 }
805 }
806
maildirdestroy(string d)807 bool mail::maildir::maildirdestroy(string d)
808 {
809 list<string> contents;
810
811 DIR *dirp=opendir(d.c_str());
812
813 try {
814 struct dirent *de;
815
816 while (dirp && (de=readdir(dirp)) != NULL)
817 {
818 if (strcmp(de->d_name, ".") == 0)
819 continue;
820 if (strcmp(de->d_name, "..") == 0)
821 continue;
822
823 contents.push_back(de->d_name);
824 }
825
826 if (dirp)
827 closedir(dirp);
828 } catch (...) {
829 if (dirp)
830 closedir(dirp);
831 LIBMAIL_THROW(LIBMAIL_THROW_EMPTY);
832 }
833
834 list<string>::iterator b=contents.begin(), e=contents.end();
835
836 while (b != e)
837 {
838 string s=d + "/" + *b++;
839
840 if (unlink(s.c_str()) < 0 && errno != ENOENT)
841 {
842 if (errno == EISDIR)
843 {
844 if (!maildirdestroy(s))
845 return false;
846 continue;
847 }
848 return false;
849 }
850 }
851 rmdir(d.c_str());
852 return true;
853 }
854
clone()855 mail::folder *mail::maildir::folder::clone() const
856 {
857 if (isDestroyed())
858 return NULL;
859
860 mail::maildir::folder *p=new mail::maildir::folder(maildirAccount,
861 path);
862
863 if (p)
864 {
865 p->hasMessagesFlag=hasMessagesFlag;
866 p->hasSubfoldersFlag=hasSubfoldersFlag;
867 return p;
868 }
869 return NULL;
870 }
871
872
findFolder(string folder,mail::callback::folderList & callback1,mail::callback & callback2)873 void mail::maildir::findFolder(string folder,
874 mail::callback::folderList &callback1,
875 mail::callback &callback2)
876 {
877 mail::maildir::folder tempFolder(this, folder);
878
879 vector<const mail::folder *> folderList;
880
881 folderList.push_back(&tempFolder);
882
883 callback1.success(folderList);
884 callback2.success("OK");
885 }
886
translatePath(string path)887 string mail::maildir::translatePath(string path)
888 {
889 return mail::mbox::translatePathCommon(path, ".");
890 }
891
encword(string s)892 static string encword(string s)
893 {
894 string r="";
895
896 string::iterator b=s.begin(), e=s.end();
897 string::iterator p=b;
898
899 while ( b != e )
900 {
901 if ( *b == ':' || *b == '\\')
902 {
903 r.insert(r.end(), p, b);
904 r += "\\";
905 p=b;
906 }
907 b++;
908 }
909
910 r.insert(r.end(), p, b);
911 return r;
912 }
913
914
getword(string & s)915 static string getword(string &s)
916 {
917 string r="";
918
919 string::iterator b=s.begin(), e=s.end(), p=b;
920
921 while (b != e)
922 {
923 if (*b == ':')
924 break;
925
926 if (*b == '\\')
927 {
928 r.insert(r.end(), p, b);
929
930 b++;
931 p=b;
932
933 if (b == e)
934 break;
935 }
936 b++;
937 }
938
939 r.insert(r.end(), p, b);
940
941 if (b != e)
942 {
943 b++;
944 s=string(b, s.end());
945 }
946
947 return r;
948 }
949
toString()950 string mail::maildir::folder::toString() const
951 {
952 return encword(path) + ":" + encword(name) + ":" +
953 (hasMessagesFlag ? "M":"") +
954 (hasSubfoldersFlag ? "S":"");
955 }
956
957
folderFromString(string folderName)958 mail::folder *mail::maildir::folderFromString(string folderName)
959 {
960 string path=getword(folderName);
961 string name=getword(folderName);
962
963 mail::maildir::folder *f=new mail::maildir::folder(this, path);
964
965 if (!f)
966 return NULL;
967
968 f->hasMessagesFlag= folderName.find('M') != std::string::npos;
969 f->hasSubfoldersFlag= folderName.find('S') != std::string::npos;
970
971 return f;
972 }
973
open(mail::callback & openCallback,mail::snapshot * restoreSnapshot,mail::callback::folder & folderCallback)974 void mail::maildir::folder::open(mail::callback &openCallback,
975 mail::snapshot *restoreSnapshot,
976 mail::callback::folder &folderCallback) const
977 {
978 if (isDestroyed(openCallback))
979 return;
980
981 maildirAccount->open(path, openCallback, folderCallback);
982 }
983
984
readTopLevelFolders(mail::callback::folderList & callback1,mail::callback & callback2)985 void mail::maildir::readTopLevelFolders(mail::callback::folderList &callback1,
986 mail::callback &callback2)
987 {
988 mail::maildir::folder inbox(this, INBOX);
989 mail::maildir::folder folders(this, INBOX);
990
991 inbox.hasSubfoldersFlag=false;
992 folders.hasMessagesFlag=false;
993
994 vector<const mail::folder *> folderList;
995
996 folderList.push_back(&inbox);
997
998 if (!ispop3maildrop)
999 folderList.push_back(&folders);
1000
1001 callback1.success(folderList);
1002 callback2.success("OK");
1003 }
1004