Bincimap 2.0.16
Easy Imapping
Loading...
Searching...
No Matches
operator-append.cc
Go to the documentation of this file.
1
7#include <algorithm>
8#include <string>
9
10#include <fcntl.h>
11
12#include "depot.h"
13#include "iodevice.h"
14#include "iofactory.h"
15#include "mailbox.h"
16#include "operators.h"
17#include "recursivedescent.h"
18#include "pendingupdates.h"
19#include "session.h"
20
21using namespace ::std;
22using namespace Binc;
23
24//----------------------------------------------------------------------
26{
27}
28
29//----------------------------------------------------------------------
31{
32}
33
34//----------------------------------------------------------------------
35const string AppendOperator::getName(void) const
36{
37 return "APPEND";
38}
39
40//----------------------------------------------------------------------
42{
44}
45
46//------------------------------------------------------------------------
48 Request &command)
49{
50 Session &session = Session::getInstance();
51
52 const string &srcmailbox = command.getMailbox();
53 const string &canonmailbox = toCanonMailbox(srcmailbox);
54 Mailbox *mailbox = 0;
55
56 if ((mailbox = depot.get(canonmailbox)) == 0) {
57 session.setResponseCode("TRYCREATE");
58 session.setLastError("invalid destination mailbox "
59 + toImapString(srcmailbox));
60 return NO;
61 }
62
63 // mask all passed flags together
64 unsigned int newflags = (unsigned int) Message::F_NONE;
65 vector<string>::const_iterator f_i = command.flags.begin();
66 while (f_i != command.flags.end()) {
67 if (*f_i == "\\Deleted") newflags |= Message::F_DELETED;
68 if (*f_i == "\\Answered") newflags |= Message::F_ANSWERED;
69 if (*f_i == "\\Seen") newflags |= Message::F_SEEN;
70 if (*f_i == "\\Draft") newflags |= Message::F_DRAFT;
71 if (*f_i == "\\Flagged") newflags |= Message::F_FLAGGED;
72 ++f_i;
73 }
74
75 int mday, year, hour, minute, second;
76 char month[4];
77
78 struct tm mytm;
79 if (command.getDate() != "") {
80 sscanf(command.getDate().c_str(), "%2i-%3s-%4i %2i:%2i:%2i",
81 &mday, month, &year, &hour, &minute, &second);
82
83 month[3] = '\0';
84 string monthstr = month;
85 lowercase(monthstr);
86 mytm.tm_sec = second;
87 mytm.tm_min = minute;
88 mytm.tm_hour = hour;
89 mytm.tm_year = year - 1900;
90 mytm.tm_mday = mday;
91 if (monthstr == "jan") mytm.tm_mon = 0;
92 else if (monthstr == "feb") mytm.tm_mon = 1;
93 else if (monthstr == "mar") mytm.tm_mon = 2;
94 else if (monthstr == "apr") mytm.tm_mon = 3;
95 else if (monthstr == "may") mytm.tm_mon = 4;
96 else if (monthstr == "jun") mytm.tm_mon = 5;
97 else if (monthstr == "jul") mytm.tm_mon = 6;
98 else if (monthstr == "aug") mytm.tm_mon = 7;
99 else if (monthstr == "sep") mytm.tm_mon = 8;
100 else if (monthstr == "oct") mytm.tm_mon = 9;
101 else if (monthstr == "nov") mytm.tm_mon = 10;
102 else if (monthstr == "dec") mytm.tm_mon = 11;
103 mytm.tm_isdst = -1;
104 }
105
106 // Read number of characters in literal. Literal is required here.
107 char c;
108 if (!bincClient.readChar(&c)) return ABORT;
109
110 if (c != '{') {
111 session.setLastError("expected literal");
112 return BAD;
113 }
114
115 string nr;
116 bool literalPlus = false;
117 while (1) {
118 if (!bincClient.readChar(&c)) {
119 session.setLastError("unexcepted EOF");
120 return BAD;
121 }
122
123 if (c == '}') break;
124
125 // Support LITERAL+
126 if (c == '+' && !literalPlus) {
127 literalPlus = true;
128 continue;
129 }
130
131 if (!isdigit(c)) {
132 session.setLastError("unexcepted non-digit character");
133 return BAD;
134 }
135
136 if (literalPlus) {
137 session.setLastError("expected '}'");
138 return BAD;
139 }
140
141 nr += (char) c;
142 }
143
144 int nchars = atoi(nr.c_str());
145 if (nchars < 0) {
146 session.setLastError("expected positive size of appended message");
147 return BAD;
148 }
149
150 if (!bincClient.readChar(&c)) return ABORT;
151
152 if (c != '\r') {
153 session.setLastError("expected CR");
154 return BAD;
155 }
156
157 if (!bincClient.readChar(&c)) return ABORT;
158
159 if (c != '\n') {
160 session.setLastError("expected LF");
161 return BAD;
162 }
163
164 time_t newtime = (command.getDate() != "") ? mktime(&mytm) : time(0);
165 if (newtime == -1) newtime = time(0);
166 Message *dest = mailbox->createMessage(depot.mailboxToFilename(canonmailbox),
167 newtime);
168 if (!dest) {
169 session.setLastError(mailbox->getLastError());
170 return NO;
171 }
172
173 if (!literalPlus) {
174 bincClient << "+ go ahead with " << nchars << " characters" << endl;
175 bincClient.flush();
176 }
177
179
180 while (nchars > 0) {
181 // Read in chunks of 8192, followed by an optional chunk at the
182 // end which is < 8192 bytes.
183 string s;
184 int bytesToRead = nchars > 8192 ? 8192 : nchars;
185 if (!bincClient.readStr(&s, bytesToRead)) {
186 mailbox->rollBackNewMessages();
187 session.setLastError(bincClient.getLastErrorString());
188 return NO;
189 }
190
191 // Write the chunk to the message.
192 if (!dest->appendChunk(s)) {
193 mailbox->rollBackNewMessages();
194 session.setLastError(dest->getLastError());
195 return NO;
196 }
197
198 // Update the message count.
199 nchars -= s.size();
200 }
201
202 // Read the trailing CRLF after the message data.
203 if (!bincClient.readChar(&c)) return ABORT;
204
205 if (c != '\r') {
206 mailbox->rollBackNewMessages();
207 session.setLastError("expected CR");
208 return BAD;
209 }
210
211 if (!bincClient.readChar(&c)) return ABORT;
212
213 if (c != '\n') {
214 mailbox->rollBackNewMessages();
215 session.setLastError("expected LF");
216 return BAD;
217 }
218
219 // Commit the message.
220 dest->close();
221 dest->setStdFlag(newflags);
222 dest->setInternalDate(mktime(&mytm));
223
224 if (!mailbox->commitNewMessages(depot.mailboxToFilename(canonmailbox))) {
225 session.setLastError("failed to commit after successful APPEND: "
226 + mailbox->getLastError());
227 return NO;
228 }
229
230 if (mailbox == depot.getSelected()) {
233 | PendingUpdates::FLAGS, true, false, true);
234 }
235
236 return OK;
237}
238
239//----------------------------------------------------------------------
241{
242 Session &session = Session::getInstance();
244
245 if (c_in.getUidMode())
246 return REJECT;
247
248 if ((res = expectSPACE()) != ACCEPT) {
249 session.setLastError("Expected SPACE after APPEND");
250 return res;
251 }
252
253 string mailbox;
254 if ((res = expectMailbox(mailbox)) != ACCEPT) {
255 session.setLastError("Expected mailbox after APPEND SPACE");
256 return res;
257 }
258
259 c_in.setMailbox(mailbox);
260
261 if ((res = expectSPACE()) != ACCEPT) {
262 session.setLastError("Expected SPACE after APPEND SPACE mailbox");
263 return res;
264 }
265
266 if ((res = expectThisString("(")) == ACCEPT) {
267 if ((res = expectFlag(c_in.getFlags())) == ACCEPT)
268 while (1) {
269 if ((res = expectSPACE()) != ACCEPT) break;
270 if ((res = expectFlag(c_in.getFlags())) != ACCEPT) {
271 session.setLastError("expected a flag after the '('");
272 return res;
273 }
274 }
275
276 if ((res = expectThisString(")")) != ACCEPT) {
277 session.setLastError("expected a ')'");
278 return res;
279 }
280
281 if ((res = expectSPACE()) != ACCEPT) {
282 session.setLastError("expected a SPACE after the flag list");
283 return res;
284 }
285 }
286
287 string date;
288 if ((res = expectDateTime(date)) == ACCEPT)
289 if ((res = expectSPACE()) != ACCEPT) {
290 session.setLastError("expected a SPACE after date_time");
291 return res;
292 }
293
294 c_in.setDate(date);
295 c_in.setName("APPEND");
296 return ACCEPT;
297}
virtual ParseResult parse(Request &) const
int getState(void) const
ProcessResult process(Depot &, Request &)
const std::string getName(void) const
virtual Mailbox * get(const std::string &path) const
Definition: depot.cc:107
virtual std::string mailboxToFilename(const std::string &m) const =0
virtual Mailbox * getSelected(void) const
Definition: depot.cc:183
virtual bool rollBackNewMessages(void)=0
const std::string & getLastError(void) const
Definition: mailbox.cc:103
virtual bool commitNewMessages(const std::string &mbox)=0
virtual Message * createMessage(const std::string &mbox, time_t idate=0)=0
The Message class provides an interface for IMAP messages.
Definition: message.h:31
virtual void setInternalDate(time_t)=0
virtual void close(void)=0
virtual void setStdFlag(unsigned char)=0
virtual bool appendChunk(const std::string &)=0
const std::string & getLastError(void) const
Definition: message.h:145
const std::string & getDate(void) const
Definition: imapparser.cc:112
void setDate(const std::string &s_in)
Definition: imapparser.cc:106
void setMailbox(const std::string &s_in)
Definition: imapparser.cc:155
std::vector< std::string > & getFlags(void)
Definition: imapparser.cc:215
void setName(const std::string &s_in)
Definition: imapparser.cc:70
const std::string & getMailbox(void) const
Definition: imapparser.cc:161
std::vector< std::string > flags
Definition: imapparser.h:112
bool getUidMode(void) const
Definition: imapparser.cc:40
void setLastError(const std::string &error) const
Definition: session.cc:185
@ AUTHENTICATED
Definition: session.h:37
void setResponseCode(const std::string &error) const
Definition: session.cc:197
static Session & getInstance(void)
Definition: session.cc:33
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
Operator::ParseResult expectFlag(std::vector< std::string > &v_in)
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
Operator::ParseResult expectThisString(const std::string &s_in)
bool pendingUpdates(Mailbox *, int type, bool rescan, bool showAll=false, bool forceScan=false, bool uidfetchflags=false)
Operator::ParseResult expectDateTime(std::string &s_in)
int atoi(const std::string &s_in)
Definition: convert.h:55
void lowercase(std::string &input)
Definition: convert.h:122
Operator::ParseResult expectMailbox(std::string &s_in)
Declaration of all operators.
Declaration of a recursive descent IMAP command parser.