Bincimap 2.0.16
Easy Imapping
Loading...
Searching...
No Matches
operator-list.cc
Go to the documentation of this file.
1
5#include <sys/types.h>
6#include <dirent.h>
7#include <sys/stat.h>
8
9#include <string>
10#include <iostream>
11
12#include "convert.h"
13#include "depot.h"
14#include "iodevice.h"
15#include "iofactory.h"
16#include "mailbox.h"
17#include "operators.h"
18#include "recursivedescent.h"
19#include "regmatch.h"
20#include "session.h"
21
22using namespace ::std;
23using namespace Binc;
24
25namespace {
26 const time_t LIST_CACHE_TIMEOUT = 10;
27}
28
29//----------------------------------------------------------------------
31{
32 cacheTimeout = 0;
33}
34
35//----------------------------------------------------------------------
37{
38}
39
40//----------------------------------------------------------------------
41const string ListOperator::getName(void) const
42{
43 return "LIST";
44}
45
46//----------------------------------------------------------------------
48{
50}
51
52//------------------------------------------------------------------------
54 Request &command)
55{
56 Session &session = Session::getInstance();
57 const char delim = depot.getDelimiter();
58
59 // special case: if the mailbox argument is empty, then give a
60 // hard coded reply.
61 string wildcard;
62 if ((wildcard = command.getListMailbox()) == "") {
63 bincClient << "* LIST (\\Noselect) \"" << delim << "\" \"\"" << endl;
64 return OK;
65 }
66
67 // remove leading or trailing delimiter in wildcard
68 trim(wildcard, string(&delim, 1));
69
70 // convert wildcard to regular expression
71 string regex = toRegex(wildcard, depot.getDelimiter());
72 string wildcardLower = regex;
73 lowercase(wildcardLower);
74 if (wildcardLower.substr(0, 6) == "^inbox")
75 regex = "^[iI][nN][bB][oO][xX]" + regex.substr(6);
76
77 // remove leading or trailing delimiter in reference
78 string ref = command.getMailbox();
79 trim(ref, string(&delim, 1));
80 wildcardLower = ref;
81 lowercase(wildcardLower);
82 if (wildcardLower.substr(0, 6) == "^inbox")
83 ref = "^[iI][nN][bB][oO][xX]" + ref.substr(6);
84 if (wildcardLower.substr(0, 5) == "inbox"
85 && (wildcardLower.length() == 5 || wildcardLower[5] == delim))
86 ref = "INBOX" + ref.substr(5);
87
88 // a map from mailbox name to flags
89 map<string, unsigned int> mailboxes;
90
91 if (cacheTimeout == 0 || cacheTimeout < time(0) - LIST_CACHE_TIMEOUT
92 || session.mailboxchanges) {
93 session.mailboxchanges = false;
94
95 // read through all entries in depository.
96 for (Depot::iterator i = depot.begin("."); i != depot.end(); ++i) {
97 const string path = *i;
98 const string mpath = depot.filenameToMailbox(path);
99 Mailbox *m = 0;
100
101 // skip entries that are not identified as mailboxes
102 if ((m = depot.get(mpath)) == 0)
103 continue;
104
105 // convert file name to mailbox name. skip it if there is no
106 // corresponding mailbox name.
107 string tmp = toCanonMailbox(depot.filenameToMailbox(path));
108 trim(tmp, string(&delim, 1));
109 if (tmp == "") continue;
110 else {
111 // inherit flags that were already set for this mailbox.
112 int flags = DIR_SELECT;
113 if (m->isMarked(path)) flags |= DIR_MARKED;
114 if (mailboxes.find(tmp) != mailboxes.end()) flags |= mailboxes[tmp];
115 mailboxes[tmp] = flags;
116 }
117
118 // now add all superior mailboxes with no flags set if not
119 // added already.
120 string::size_type pos = tmp.rfind(delim);
121 while (pos != string::npos) {
122 tmp = tmp.substr(0, pos);
123 trim(tmp, string(&delim, 1));
124
125 if (mailboxes.find(tmp) == mailboxes.end())
126 mailboxes[tmp] = 0;
127
128 pos = tmp.rfind(delim);
129 }
130 }
131
132 // find leaf nodes O(N^2)
133 map<string, unsigned int>::iterator i;
134 for (i = mailboxes.begin(); i != mailboxes.end(); ++i) {
135 string mailbox = i->first;
136 mailbox += delim;
137
138 bool leaf = true;
139 map<string, unsigned int>::const_iterator j = mailboxes.begin();
140 for (; j != mailboxes.end(); ++j) {
141 string::size_type pos = j->first.rfind(delim);
142 if (pos == string::npos) continue;
143
144 string base = j->first.substr(0, pos + 1);
145
146 if (mailbox == base) {
147 leaf = false;
148 break;
149 }
150 }
151
152 if (leaf) {
153 unsigned int flags = i->second;
154 flags |= DIR_LEAF;
155 i->second = flags;
156 }
157 }
158
159 cache = mailboxes;
160 cacheTimeout = time(0);
161 } else {
162 mailboxes = cache;
163 cacheTimeout = time(0);
164 }
165
166 // finally, print all mailbox entries with flags.
167 map<string, unsigned int>::iterator i = mailboxes.begin();
168
169 for (; i != mailboxes.end(); ++i) {
170 if (ref == "" || (ref.length() <= i->first.length()
171 && ref == i->first.substr(0, ref.length())))
172 if (regexMatch(i->first.substr(ref.length()), regex) == 0) {
173 bincClient << "* LIST (";
174 string sep = "";
175
176 int flags = i->second;
177 bool noselect = false;
178
179 if (!(flags & DIR_SELECT)) {
180 bincClient << sep << "\\Noselect";
181 sep = " ";
182 noselect = true;
183 }
184
185 if (!noselect) {
186 if (flags & DIR_MARKED)
187 bincClient << sep << "\\Marked";
188 else
189 bincClient << sep << "\\Unmarked";
190 sep = " ";
191 }
192
193 if (flags & DIR_LEAF)
194 bincClient << sep << "\\HasNoChildren";
195 else
196 bincClient << sep << "\\HasChildren";
197 sep = " ";
198
199 if (flags & DIR_NOINFERIORS)
200 bincClient << sep << "\\Noinferiors";
201
202 bincClient << ") \"" << depot.getDelimiter() << "\" "
203 << toImapString(i->first) << endl;
204 }
205 }
206
207 return OK;
208}
209
210//----------------------------------------------------------------------
212{
213 Session &session = Session::getInstance();
214
215 if (c_in.getUidMode()) return REJECT;
216
218 if ((res = expectSPACE()) != ACCEPT) {
219 session.setLastError("Expected SPACE after LIST");
220 return res;
221 }
222
223 string mailbox;
224 if ((res = expectMailbox(mailbox)) != ACCEPT) {
225 session.setLastError("Expected mailbox after LIST SPACE");
226 return res;
227 }
228
229 c_in.setMailbox(mailbox);
230
231 if ((res = expectSPACE()) != ACCEPT) {
232 session.setLastError("Expected SPACE after LIST SPACE mailbox");
233 return res;
234 }
235
236 string listmailbox;
237 if ((res = expectListMailbox(listmailbox)) != ACCEPT) {
238 session.setLastError("Expected list_mailbox after LIST SPACE"
239 " mailbox SPACE");
240 return res;
241 }
242
243 if ((res = expectCRLF()) != ACCEPT) {
244 session.setLastError("Expected CRLF after LIST SPACE mailbox"
245 " SPACE list_mailbox");
246 return res;
247 }
248
249 c_in.setListMailbox(listmailbox);
250 c_in.setName("LIST");
251 return ACCEPT;
252}
virtual Mailbox * get(const std::string &path) const
Definition: depot.cc:107
virtual iterator begin(const std::string &) const
Definition: depot.cc:537
virtual const iterator & end(void) const
Definition: depot.cc:552
const char getDelimiter(void) const
Definition: depot.cc:163
virtual std::string filenameToMailbox(const std::string &m) const =0
virtual ParseResult parse(Request &) const
int getState(void) const
std::map< std::string, unsigned int > cache
Definition: operators.h:218
ProcessResult process(Depot &, Request &)
const std::string getName(void) const
virtual bool isMarked(const std::string &) const =0
void setMailbox(const std::string &s_in)
Definition: imapparser.cc:155
void setName(const std::string &s_in)
Definition: imapparser.cc:70
const std::string & getListMailbox(void) const
Definition: imapparser.cc:173
const std::string & getMailbox(void) const
Definition: imapparser.cc:161
bool getUidMode(void) const
Definition: imapparser.cc:40
void setListMailbox(const std::string &s_in)
Definition: imapparser.cc:167
bool mailboxchanges
Definition: session.h:33
void setLastError(const std::string &error) const
Definition: session.cc:185
@ AUTHENTICATED
Definition: session.h:37
static Session & getInstance(void)
Definition: session.cc:33
Declaration of miscellaneous convertion functions.
Declaration of the IODevice class.
Declaration of the IOFactory class.
#define bincClient
Definition: iofactory.h:31
Declaration of the Mailbox class (Mailbox is logical container)
Definition: bincimapd.cc:9
std::string toImapString(const std::string &s_in)
Definition: convert.h:103
Operator::ParseResult expectSPACE(void)
std::string toCanonMailbox(const std::string &s_in)
Definition: convert.h:216
std::string toRegex(const std::string &s_in, char delimiter)
Definition: convert.h:231
int regexMatch(const std::string &data_in, const std::string &p_in)
Operator::ParseResult expectListMailbox(std::string &s_in)
void lowercase(std::string &input)
Definition: convert.h:122
void trim(std::string &s_in, const std::string &chars=" \t\r\n")
Definition: convert.h:137
Operator::ParseResult expectCRLF(void)
Operator::ParseResult expectMailbox(std::string &s_in)
Declaration of all operators.
Declaration of a recursive descent IMAP command parser.