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