1 /* libobby - Network text editing library
2  * Copyright (C) 2005 0x539 dev group
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public
15  * License along with this program; if not, write to the Free
16  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18 
19 #ifndef _OBBY_USER_HPP_
20 #define _OBBY_USER_HPP_
21 
22 #include <string>
23 #include <net6/packet.hpp>
24 #include <net6/user.hpp>
25 #include <net6/address.hpp>
26 #include <net6/non_copyable.hpp>
27 #include "serialise/object.hpp"
28 #include "format_string.hpp"
29 #include "colour.hpp"
30 
31 namespace obby
32 {
33 
34 class user_table;
35 
36 /** User in a obby session.
37  */
38 class user: private net6::non_copyable
39 {
40 public:
41 	/** Flags that belong to a user.
42 	 */
43 	class flags
44 	{
45 	public:
46 		static const flags NONE;
47 		static const flags CONNECTED;
48 
operator |(flags other) const49 	        flags operator|(flags other) const { return flags(m_value | other.m_value); }
operator &(flags other) const50         	flags operator&(flags other) const { return flags(m_value & other.m_value); }
operator ^(flags other) const51 	        flags operator^(flags other) const { return flags(m_value ^ other.m_value); }
operator |=(flags other)52         	flags& operator|=(flags other) { m_value |= other.m_value; return *this; }
operator &=(flags other)53 	        flags& operator&=(flags other) { m_value &= other.m_value; return *this; }
operator ^=(flags other)54         	flags& operator^=(flags other) { m_value ^= other.m_value; return *this; }
operator ~() const55 	        flags operator~() const { return flags(~m_value); }
56 
operator bool() const57 		operator bool() const { return m_value != NONE.m_value; }
operator !() const58 		bool operator!() const { return m_value == NONE.m_value; }
operator ==(flags other) const59 	        bool operator==(flags other) const { return m_value == other.m_value; }
operator !=(flags other) const60         	bool operator!=(flags other) const { return m_value != other.m_value; }
61 
get_value() const62 	        unsigned int get_value() const { return m_value; }
63 
64 	protected:
flags(unsigned int value)65         	explicit flags(unsigned int value) : m_value(value) { }
66 
67 	        unsigned int m_value;
68 	};
69 
70 	/** User-wide privileges.
71 	 */
72 	class privileges
73 	{
74 	public:
75 		static const privileges NONE;
76 		static const privileges CREATE_DOCUMENT;
77 
operator |(privileges other) const78 	        privileges operator|(privileges other) const { return privileges(m_value | other.m_value); }
operator &(privileges other) const79         	privileges operator&(privileges other) const { return privileges(m_value & other.m_value); }
operator ^(privileges other) const80 	        privileges operator^(privileges other) const { return privileges(m_value ^ other.m_value); }
operator |=(privileges other)81         	privileges& operator|=(privileges other) { m_value |= other.m_value; return *this; }
operator &=(privileges other)82 	        privileges& operator&=(privileges other) { m_value &= other.m_value; return *this; }
operator ^=(privileges other)83         	privileges& operator^=(privileges other) { m_value ^= other.m_value; return *this; }
operator ~() const84 	        privileges operator~() const { return privileges(~m_value); }
85 
operator bool() const86 		operator bool() const { return m_value != NONE.m_value; }
operator !() const87 		bool operator!() const { return m_value == NONE.m_value; }
operator ==(privileges other) const88         	bool operator==(privileges other) const { return m_value == other.m_value; }
operator !=(privileges other) const89 	        bool operator!=(privileges other) const { return m_value != other.m_value; }
90 
get_value() const91 	        unsigned int get_value() const { return m_value; }
92 
93 	protected:
privileges(unsigned int value)94         	explicit privileges(unsigned int value) : m_value(value) { }
95 
96 	        unsigned int m_value;
97 	};
98 
99 	/** Creates a new user from an existing net6::user.
100 	 * @param id Unique obby ID for this user.
101 	 * @param user6 Underlaying net6::user object.
102 	 * @param colour User colour.
103 	 */
104 	user(unsigned int id,
105 	     const net6::user& user6,
106 	     const colour& colour);
107 
108 	/** Creates a new user that represents a client that has already left
109 	 * the obby session.
110 	 * @param id Unique obby ID for this user.
111 	 * @param name Name of the user.
112 	 * @param colour User colour.
113 	 */
114 	user(unsigned int id,
115 	     const std::string& name,
116 	     const colour& colour);
117 
118 	/** Creates a user from a serialised user object.
119 	 */
120 	user(const serialise::object& obj);
121 
122 	/** Serialises a user to a serialisation object.
123 	 */
124 	void serialise(serialise::object& obj) const;
125 
126 	/** Releases the underlaying net6::user object from this user.
127 	 * This is useful if this object gets deleted because the
128 	 * corresponding client left the obby session. The obby::user object
129 	 * itself is stored furthur to identify the client if he rejoins.
130 	 */
131 	void release_net6();
132 
133 	/** Reassigns a new net6::user to this user. This happens if a user has
134 	 * left the obby session and rejoined (maybe with another colour, in
135 	 * this case the colour in all the documents gets updated).
136 	 */
137 	void assign_net6(const net6::user& user6,
138 	                 const colour& colour);
139 
140 	/** Returns the underlaying net6::user object.
141 	 */
142 	const net6::user& get_net6() const;
143 
144 	/** Returns the user name of this user.
145 	 */
146 	const std::string& get_name() const;
147 
148 	/** Returns the address of this user. Note that the address is not
149 	 * cached, so this function throws std::logic_error if the user is not
150 	 * connected to the session. net6::not_connected_error is thrown if the
151 	 * address of the user is not known, e.g. there is no direct connection
152 	 * to this user.
153 	 */
154 	const net6::address& get_address() const;
155 
156 	/** Returns a unique ID for this user.
157 	 */
158 	unsigned int get_id() const;
159 
160 	/** Returns the user colour.
161 	 */
162 	const colour& get_colour() const;
163 
164 	/** Returns the password for this user (only available with server
165 	 * or host buffers).
166 	 */
167 	const std::string& get_password() const;
168 
169 	/** Returns the flags that are currently set for this user.
170 	 */
171 	flags get_flags() const;
172 
173 	/** Sets the three colour components of the user colour.
174 	 */
175 	void set_colour(const colour& colour);
176 
177 	/** Changes the password for this user
178 	 */
179 	void set_password(const std::string& password);
180 
181 	/** Adds the given flags to this user's flags.
182 	 */
183 	void add_flags(flags new_flags);
184 
185 	/** Removes the given flags from this user's flags.
186 	 */
187 	void remove_flags(flags old_flags);
188 
189 protected:
190 	const net6::user* m_user6;
191 
192 	unsigned int m_id;
193 	std::string m_name;
194 	colour m_colour;
195 
196 	std::string m_password;
197 
198 	flags m_flags;
199 	privileges m_privs;
200 };
201 
202 } // namespace obby
203 
204 namespace serialise
205 {
206 
207 #ifndef DOXYGEN_SHOULD_SKIP_THIS
208 // Equivalent to user_table.find(index). Implemented in user.cpp. Required
209 // to resolve the caller to user_table::find without having included
210 // user_table.hpp here.
211 const obby::user* user_table_find(const obby::user_table& user_table,
212                                   unsigned int index);
213 #endif // DOXYGEN_SHOULD_SKIP_THIS
214 
215 /** Base class for context that converts user references to a string.
216  */
217 template<typename User>
218 class user_context_to: public context_base_to<User>
219 {
220 public:
221 	typedef User data_type;
222 
223 	virtual std::string to_string(const data_type& from) const;
224 
225 protected:
226 	virtual void on_stream_setup(std::stringstream& stream) const;
227 };
228 
229 /** Converts obby::user* to a string.
230  */
231 template<>
232 class default_context_to<obby::user*>:
233 	public user_context_to<obby::user*>
234 {
235 };
236 
237 /** Converts const obby::user* to a string.
238  */
239 template<>
240 class default_context_to<const obby::user*>:
241 	public user_context_to<const obby::user*>
242 {
243 };
244 
245 /** Base class that converts a string to a user reference using
246  * a user table.
247  */
248 template<typename User>
249 class user_context_from:
250 	public context_base_from<User>
251 {
252 public:
253 	typedef User data_type;
254 
255 	user_context_from(const obby::user_table& user_table);
256 	virtual data_type from_string(const std::string& from) const;
257 
258 protected:
259 	virtual void on_stream_setup(std::stringstream& stream) const;
260 
261 	const obby::user_table& m_user_table;
262 };
263 
264 /** Stores the user ID in a hexadecimal representation.
265  */
266 template<typename User>
267 class user_hex_context_from: public user_context_from<User>
268 {
269 public:
270 	user_hex_context_from(const obby::user_table& user_table);
271 
272 protected:
273 	virtual void on_stream_setup(std::stringstream& stream) const;
274 };
275 
276 /** Converts a string to const obby::user*.
277  */
278 template<>
279 class default_context_from<const obby::user*>:
280 	public user_context_from<const obby::user*>
281 {
282 public:
283 	default_context_from(const obby::user_table& user_table);
284 };
285 
286 /** Converts a string to const obby::user*.
287  */
288 template<>
289 class hex_context_from<const obby::user*>:
290 	public user_hex_context_from<const obby::user*>
291 {
292 public:
293 	hex_context_from(const obby::user_table& user_table);
294 };
295 
296 template<typename User>
to_string(const data_type & from) const297 std::string user_context_to<User>::to_string(const data_type& from) const
298 {
299 	std::stringstream stream;
300 	on_stream_setup(stream);
301 	stream << ( (from != NULL) ? (from->get_id()) : (0) );
302 	return stream.str();
303 }
304 
305 template<typename User>
on_stream_setup(std::stringstream & stream) const306 void user_context_to<User>::on_stream_setup(std::stringstream& stream) const
307 {
308 }
309 
310 template<typename User>
user_context_from(const obby::user_table & user_table)311 user_context_from<User>::user_context_from(const obby::user_table& user_table):
312 	m_user_table(user_table)
313 {
314 }
315 
316 template<typename User>
317 typename user_context_from<User>::data_type
from_string(const std::string & from) const318 user_context_from<User>::from_string(const std::string& from) const
319 {
320 	unsigned int user_id;
321 	std::stringstream stream(from);
322 	on_stream_setup(stream);
323 	stream >> user_id;
324 
325 	if(stream.bad() )
326 		throw conversion_error("User ID must be an integer");
327 
328 	// Special meaning "no user"
329 	if(user_id == 0) return NULL;
330 
331 	data_type user = user_table_find(m_user_table, user_id);
332 
333 	if(user == NULL)
334 	{
335 		obby::format_string str("User ID %0% does not exist");
336 		str << user_id;
337 		throw conversion_error(str.str());
338 	}
339 
340 	return user;
341 }
342 
343 template<typename User>
on_stream_setup(std::stringstream & stream) const344 void user_context_from<User>::on_stream_setup(std::stringstream& stream) const
345 {
346 }
347 
348 template<typename User>
349 user_hex_context_from<User>::
user_hex_context_from(const obby::user_table & user_table)350 	user_hex_context_from(const obby::user_table& user_table):
351 	user_context_from<User>(user_table)
352 {
353 }
354 
355 template<typename User>
356 void user_hex_context_from<User>::
on_stream_setup(std::stringstream & stream) const357 	on_stream_setup(std::stringstream& stream) const
358 {
359 	stream >> std::hex;
360 }
361 
362 } // namespace serialise
363 
364 #endif // _OBBY_USER_HPP_
365