operator-store.cc (5836B)
1 /* -*- Mode: c++; -*- */ 2 /* -------------------------------------------------------------------- 3 * Filename: 4 * operator-store.cc 5 * 6 * Description: 7 * Implementation of the STORE command. 8 * 9 * Authors: 10 * Andreas Aardal Hanssen <andreas-binc curly bincimap spot org> 11 * 12 * Bugs: 13 * 14 * ChangeLog: 15 * 16 * -------------------------------------------------------------------- 17 * Copyright 2002-2005 Andreas Aardal Hanssen 18 * 19 * This program is free software; you can redistribute it and/or modify 20 * it under the terms of the GNU General Public License as published by 21 * the Free Software Foundation; either version 2 of the License, or 22 * (at your option) any later version. 23 * 24 * This program is distributed in the hope that it will be useful, 25 * but WITHOUT ANY WARRANTY; without even the implied warranty of 26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 27 * GNU General Public License for more details. 28 * 29 * You should have received a copy of the GNU General Public License 30 * along with this program; if not, write to the Free Software 31 * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA. 32 * -------------------------------------------------------------------- 33 */ 34 #ifdef HAVE_CONFIG_H 35 #include <config.h> 36 #endif 37 38 #include <string> 39 #include <iostream> 40 41 #include "imapparser.h" 42 #include "mailbox.h" 43 #include "pendingupdates.h" 44 #include "io.h" 45 46 #include "recursivedescent.h" 47 48 #include "session.h" 49 #include "depot.h" 50 #include "operators.h" 51 52 using namespace ::std; 53 using namespace Binc; 54 55 //---------------------------------------------------------------------- 56 StoreOperator::StoreOperator(void) 57 { 58 } 59 60 //---------------------------------------------------------------------- 61 StoreOperator::~StoreOperator(void) 62 { 63 } 64 65 //---------------------------------------------------------------------- 66 const string StoreOperator::getName(void) const 67 { 68 return "STORE"; 69 } 70 71 //---------------------------------------------------------------------- 72 int StoreOperator::getState(void) const 73 { 74 return Session::SELECTED; 75 } 76 77 //------------------------------------------------------------------------ 78 Operator::ProcessResult StoreOperator::process(Depot &depot, 79 Request &command) 80 { 81 Mailbox *mailbox = depot.getSelected(); 82 83 // mask all passed flags together 84 unsigned int newflags = (unsigned int) Message::F_NONE; 85 vector<string>::const_iterator f_i = command.flags.begin(); 86 while (f_i != command.flags.end()) { 87 if (*f_i == "\\Deleted") newflags |= Message::F_DELETED; 88 if (*f_i == "\\Answered") newflags |= Message::F_ANSWERED; 89 if (*f_i == "\\Seen") newflags |= Message::F_SEEN; 90 if (*f_i == "\\Draft") newflags |= Message::F_DRAFT; 91 if (*f_i == "\\Flagged") newflags |= Message::F_FLAGGED; 92 ++f_i; 93 } 94 95 // pass through all messages 96 unsigned int mode 97 = command.getUidMode() ? Mailbox::UID_MODE : Mailbox::SQNR_MODE; 98 99 Mailbox::iterator i 100 = mailbox->begin(command.bset, Mailbox::SKIP_EXPUNGED | mode); 101 102 for (; i != mailbox->end(); ++i) { 103 Message &message = *i; 104 105 // get and reset the old flags 106 unsigned int oldflags = (unsigned int) message.getStdFlags(); 107 unsigned int flags = oldflags; 108 109 bool recent = (flags & Message::F_RECENT) != 0; 110 flags &= (~Message::F_RECENT); 111 112 // add, remove or set flags 113 if (command.getMode()[0] == '+') flags |= newflags; 114 else if (command.getMode()[0] == '-') flags &= ~newflags; 115 else flags = newflags; 116 117 // set new flags, even if they weren't changed. 118 if (recent) flags |= Message::F_RECENT; 119 message.resetStdFlags(); 120 message.setStdFlag(flags); 121 } 122 123 // commit flag changes to mailbox (might change mailbox) 124 mailbox->updateFlags(); 125 126 // check mailbox for updates, and report them 127 if (command.getMode().find(".SILENT") != string::npos) 128 pendingUpdates(mailbox, 129 PendingUpdates::EXISTS 130 | PendingUpdates::RECENT, false, false, false, 131 command.getUidMode()); 132 else 133 pendingUpdates(mailbox, 134 PendingUpdates::EXISTS 135 | PendingUpdates::RECENT 136 | PendingUpdates::EXPUNGE 137 | PendingUpdates::FLAGS, false, false, false, 138 command.getUidMode()); 139 140 return OK; 141 } 142 143 //---------------------------------------------------------------------- 144 Operator::ParseResult StoreOperator::parse(Request & c_in) const 145 { 146 Session &session = Session::getInstance(); 147 148 Operator::ParseResult res; 149 if ((res = expectSPACE()) != ACCEPT) { 150 session.setLastError("Expected SPACE"); 151 return res; 152 } 153 154 if ((res = expectSet(c_in.getSet())) != ACCEPT) { 155 session.setLastError("Expected Set"); 156 return res; 157 } 158 159 if ((res = expectSPACE()) != ACCEPT) { 160 session.setLastError("Expected SPACE"); 161 return res; 162 } 163 164 string mode; 165 if ((res = expectThisString("+")) == ACCEPT) 166 mode = "+"; 167 else if ((res = expectThisString("-")) == ACCEPT) 168 mode = "-"; 169 170 if ((res = expectThisString("FLAGS")) != ACCEPT) { 171 session.setLastError("Expected FLAGS"); 172 return res; 173 } else 174 mode += "FLAGS"; 175 176 if ((res = expectThisString(".SILENT")) == ACCEPT) 177 mode += ".SILENT"; 178 179 c_in.setMode(mode); 180 181 if ((res = expectSPACE()) != ACCEPT) { 182 session.setLastError("Expected SPACE"); 183 return res; 184 } 185 186 bool paren = false; 187 if ((res = expectThisString("(")) == ACCEPT) 188 paren = true; 189 190 if ((res = expectFlag(c_in.getFlags())) == ACCEPT) 191 while (1) { 192 if ((res = expectSPACE()) != ACCEPT) 193 break; 194 195 if ((res = expectFlag(c_in.getFlags())) != ACCEPT) { 196 session.setLastError("Expected flag after SPACE"); 197 return res; 198 } 199 } 200 201 if (paren) 202 if ((res = expectThisString(")")) != ACCEPT) { 203 session.setLastError("Expected )"); 204 return res; 205 } 206 207 if ((res = expectCRLF()) != ACCEPT) { 208 session.setLastError("Expected CRLF"); 209 return res; 210 } 211 212 return ACCEPT; 213 }