summaryrefslogtreecommitdiffstats
blob: 84d232a0283496b81f748ba3f76b3947cd7c4c55 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/*
 * Copyright (c) 2010-2015 Isode Limited.
 * All rights reserved.
 * See the COPYING file for more information.
 */

#pragma once

#include <Swiften/Queries/IQHandler.h>
#include <Swiften/Queries/IQRouter.h>
#include <Swiften/Elements/ErrorPayload.h>

namespace Swift {
	/**
	 * A class for handling incoming IQ Get and Set requests of a specific payload type.
	 *
	 * Concrete subclasses of this class need to implement handleGetRequest() and handleSetRequest() to
	 * implement the behavior of the responder.
	 *
	 * \tparam PAYLOAD_TYPE The type of payload this Responder handles. Only IQ requests containing this
	 *	payload type will be passed to handleGetRequest() and handleSetRequest()
	 */
	template<typename PAYLOAD_TYPE>
	class Responder : public IQHandler {
		public:
			Responder(IQRouter* router) : router_(router), isFinalResonder_(true) {
			}

			~Responder() {
			}

			/**
			 * Starts the responder.
			 *
			 * After the responder has started, it will start receiving and responding to requests.
			 *
			 * \see stop()
			 */
			void start() {
				router_->addHandler(this);
			}

			/**
			 * Stops the responder.
			 *
			 * When the responder is stopped, it will no longer receive incoming requests.
			 *
			 * \see start()
			 */
			void stop() {
				router_->removeHandler(this);
			}

		protected:
			/**
			 * Handle an incoming IQ-Get request containing a payload of class PAYLOAD_TYPE.
			 *
			 * This method is implemented in the concrete subclasses.
			 */
			virtual bool handleGetRequest(const JID& from, const JID& to, const std::string& id, boost::shared_ptr<PAYLOAD_TYPE> payload) = 0;

			/**
			 * Handle an incoming IQ-Set request containing a payload of class PAYLOAD_TYPE.
			 *
			 * This method is implemented in the concrete subclasses.
			 */
			virtual bool handleSetRequest(const JID& from, const JID& to, const std::string& id, boost::shared_ptr<PAYLOAD_TYPE> payload) = 0;

			/**
			 * Convenience function for sending an IQ response.
			 */
			void sendResponse(const JID& to, const std::string& id, boost::shared_ptr<PAYLOAD_TYPE> payload) {
				router_->sendIQ(IQ::createResult(to, id, payload));
			}

			/**
			 * Convenience function for sending an IQ response, with a specific from address.
			 */
			void sendResponse(const JID& to, const JID& from, const std::string& id, boost::shared_ptr<PAYLOAD_TYPE> payload) {
				router_->sendIQ(IQ::createResult(to, from, id, payload));
			}

			/**
			 * Convenience function for responding with an error.
			 */
			void sendError(const JID& to, const std::string& id, ErrorPayload::Condition condition, ErrorPayload::Type type, Payload::ref payload = Payload::ref()) {
				router_->sendIQ(IQ::createError(to, id, condition, type, payload));
			}

			/**
			 * Convenience function for responding with an error from a specific from address.
			 */
			void sendError(const JID& to, const JID& from, const std::string& id, ErrorPayload::Condition condition, ErrorPayload::Type type, Payload::ref payload = Payload::ref()) {
				router_->sendIQ(IQ::createError(to, from, id, condition, type, payload));
			}

			IQRouter* getIQRouter() const {
				return router_;
			}

			void setFinal(bool isFinal) {
				isFinalResonder_ = isFinal;
			}

		private:
			virtual bool handleIQ(boost::shared_ptr<IQ> iq) {
				if (iq->getType() == IQ::Set || iq->getType() == IQ::Get) {
					boost::shared_ptr<PAYLOAD_TYPE> payload(iq->getPayload<PAYLOAD_TYPE>());
					if (payload) {
						bool result;
						if (iq->getType() == IQ::Set) {
							result = handleSetRequest(iq->getFrom(), iq->getTo(), iq->getID(), payload);
						}
						else {
							result = handleGetRequest(iq->getFrom(), iq->getTo(), iq->getID(), payload);
						}
						if (!result) {
							if (isFinalResonder_) {
								router_->sendIQ(IQ::createError(iq->getFrom(), iq->getID(), ErrorPayload::NotAllowed, ErrorPayload::Cancel));
							}
							else {
								return false;
							}
						}
						return true;
					}
				}
				return false;
			}
		
		private:
			IQRouter* router_;
			bool isFinalResonder_;
	};
}