// imapd/Command.hh
// This file is part of Decimail; see http://decimail.org
// (C) 2004 Philip Endecott
 
 
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
#ifndef Imapd_Command_hh
#define Imapd_Command_hh

#include "Session.hh"

#include <string>
#include <iostream>
#include <list>


namespace Imapd {

  class RespondNo: public pbe::Exception {
  private:
    const std::string msg;
  public:
    RespondNo(std::string m): msg(m) {}
    RespondNo(const pbe::Exception& E);
    void report(std::ostream& strm) const;
    std::string get_msg(void) const { return msg; }
  };

  class RespondBad: public pbe::Exception {
  private:
    const std::string msg;
  public:
    RespondBad(std::string m): msg(m) {}
    void report(std::ostream& strm) const;
    std::string get_msg(void) const { return msg; }
  };


  class Command {
  public:
    Command(std::string t, std::string n): tag(t), name(n) {}
    virtual ~Command() {}
    void run(Session& session);
  protected:
    const std::string tag;
    const std::string name;
    std::string response_code;
    virtual void runbody(Session& session) = 0;
  };


  class UidableCmd: public Command {
  protected:
    bool uid_mode;
    friend class UidCmd;
  public:
    UidableCmd(std::string t, std::string n): Command(t,n), uid_mode(false) {}
    void set_uid_mode(void) { uid_mode=true; }
  };


  class MessageSet {
  public:
    virtual void select_seqnum(const Session& session,
			       std::list<int>& wanted_msgids) const = 0;
    virtual void select_uid(const Session& session,
			    std::list<int>& wanted_msgids) const = 0;
    virtual ~MessageSet() {}
  };

  class MessageSetSingleton: public MessageSet {
  private:
    const int msgnum;
  public:
    MessageSetSingleton(int m): msgnum(m) {}
    void select_seqnum(const Session& session,
		       std::list<int>& wanted_msgids) const;
    void select_uid(const Session& session,
		    std::list<int>& wanted_msgids) const;
  };

  class MessageSetRange: public MessageSet {
  private:
    const int start;
    const int end;
  public:
    MessageSetRange(int s, int e): start(s), end(e) {}
    void select_seqnum(const Session& session,
		       std::list<int>& wanted_msgids) const;
    void select_uid(const Session& session,
		    std::list<int>& wanted_msgids) const;
  };

  class MessageSetSet: public MessageSet {
  private:
    const MessageSet* set1;
    const MessageSet* set2;
  public:
    MessageSetSet(MessageSet* s1, MessageSet* s2): set1(s1), set2(s2) {}
    virtual ~MessageSetSet() { delete set1; delete set2; }
    void select_seqnum(const Session& session,
		       std::list<int>& wanted_msgids) const;
    void select_uid(const Session& session,
		    std::list<int>& wanted_msgids) const;
  };

  class MessageSetCmd: public UidableCmd {
  private:
    const MessageSet* msgset;
  protected:
    void get_msg_ids(const Session& session, std::list<int>& msg_ids);
  public:
    MessageSetCmd(std::string t, std::string n, const MessageSet* ms):
      UidableCmd(t,n), msgset(ms) {}
    ~MessageSetCmd();
  };

};


#endif
