summaryrefslogtreecommitdiffstats
path: root/src/im/msg_session.h
blob: 8fff10f5571d2c5d10f4e28a46708fb7437fe452 (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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
/*
    Copyright (C) 2005-2009  Michel de Boer <michel@twinklephone.com>

    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
    (at your option) 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, see <https://www.gnu.org/licenses/>.
*/

/**
 * @file
 * Instant message session.
 * SIP does not have a concept of message sessions. It's up to the
 * user interface to create the illusion of a session by grouping
 * messages between 2 users.
 */

#ifndef _MSG_SESSION_H
#define _MSG_SESSION_H

#include <string>
#include <time.h>

#include "id_object.h"
#include "exceptions.h"
#include "user.h"
#include "sockets/url.h"
#include "parser/media_type.h"
#include "patterns/observer.h"

using namespace std;

namespace im {

/** 
 * Maximum length for inline text messages. Longer texts are shown
 * as attachments.
 */
const size_t MAX_INLINE_TEXT_LEN = 10240;

/** Message direction. */
enum t_direction {
	MSG_DIR_IN,	/**< Incoming. */
	MSG_DIR_OUT	/**< Outgoing. */
};

/** Text format. */
enum t_text_format {
	TXT_PLAIN,	/**< Plain */
	TXT_HTML,	/**< HTML */
};

/** Message composing state. */
enum t_composing_state {
	COMPOSING_STATE_IDLE,
	COMPOSING_STATE_ACTIVE
};

/**
 * Convert a state name a conveyed in an im_iscomposing body to a state.
 * @param state_name [in] The state name to convert.
 * @return The composing state. If the state name is unknown, then 
 *         COMPOSING_STATE_IDE is returned.
 */
t_composing_state string2composing_state(const string &state_name);

/**
 * Convert a composing state to a string for an im_iscomposing body.
 * @param state [in] The composing state to convert.
 * @return The string.
 */
string composing_state2string(t_composing_state state);

/** 
 * Single message with meta information. 
 * In the current implementation a message either contains a text message
 * or an attachment.
 * TODO: use multipart MIME to send a text message with an attachment.
 */
class t_msg : public t_id_object {
public:
	string		subject;	/**< Subject of the message. */
	string		message;	/**< The message text. */
	t_direction	direction;	/**< Direction of the message. */
	time_t		timestamp;	/**< Timestamp of the message. */
	t_text_format	format;		/**< Text format. */
	bool		has_attachment;	/**< Indicates if an attachment is present. */
	string		attachment_filename; /**< File name of stored attachment. */
	t_media		attachment_media; /**< Media type of attachment */
	string		attachment_save_as_name; /**< Suggested 'save as' filename */
	
	/** Constructor. */
	t_msg();
	
	/**
	 * Constructor.
	 * Sets the timestamp to the current time.
	 * @param msg [in] The message.
	 * @param dir [in] Direction of the message.
	 * @param fmt [in] Text format of the message.
	 */
	t_msg(const string &msg, t_direction dir, t_text_format fmt);
	
	/**
	 * Add an attachment to the message.
	 * @param filename [in] File name (full path) of the attachment.
	 * @param media [in] Media type of the attachment.
	 * @param save_as [in] Suggested file name for saving.
	 */
	void set_attachment(const string &filename, const t_media &media, const string &save_as);
};

/** 
 * Message session. 
 * It's up to the user interface to create a message session and store
 * all messages in it. The session is just a container to store a
 * collection of page-mode messages.
 */
class t_msg_session : public patterns::t_subject {
private:
	t_user		*user_config;	/**< User profile of the local user. */
	t_display_url	remote_party;	/**< Remote party. */
	list<t_msg>	messages;	/**< Messages sent/received. */
	
	/** Indicates if a new message has been added to the list of message. */
	bool		new_message_added;
	
	bool		error_recvd;	/**< Indicates that an error has been received. */
	string		error_msg;	/**< Received error message. */
	
	/** Indicates that a delivery notification has been received. */
	bool		delivery_notification_recvd;
	
	/** Received delivery notification. */
	string		delivery_notification;
	
	bool		msg_in_flight;	/**< Indicates if an outgoing message is in flight. */
	
	/** Indicates if a composing state indication must be sent to the remote party. */
	bool		send_composing_state;
	
	/** Message composing state of the local party. */
	t_composing_state	local_composing_state;
	
	/** Timeout in seconds till the active state of the local party expires. */
	time_t		local_idle_timeout;
	
	/** Timeout in seconds till a refresh of the active state indication must be sent. */
	time_t		local_refresh_timeout;
	
	/** Message composing state of the remote party. */
	t_composing_state	remote_composing_state;
	
	/** Timeout in seconds till the active state of the remote party expires. */
	time_t		remote_idle_timeout;
	
public:
	/**
	 * Constructor.
	 * @param u [in] User profile of the local user.
	 */
	t_msg_session(t_user *u);

	/**
	 * Constructor.
	 * @param u [in] User profile of the local user.
	 * @param _remote_party [in] URL of remote party.
	 */
	t_msg_session(t_user *u, t_display_url _remote_party);
	
	/** Destructor. */
	~t_msg_session();
	
	/** @name getters */
	//@{
	t_user *get_user(void) const;
	t_display_url get_remote_party(void) const;
	const list<t_msg> &get_messages(void) const;
	t_composing_state get_remote_composing_state(void) const;
	//@}
	
	/** @name setters */
	//@{
	void set_user(t_user *u);
	void set_remote_party(const t_display_url &du);
	void set_send_composing_state(bool enable);
	//@}
	
	/**
	 * Get the last message of the session.
	 * @return The last message.
	 * @throws empty_list_exception  There are no messages.
	 */
	t_msg get_last_message(void);
	
	/** Check if a new message has been added. */
	bool is_new_message_added(void) const;
	
	/**
	 * Set the display name of the remote party if it is not yet set.
	 * @param display [in] The display name to set.
	 */
	void set_display_if_empty(const string &display);
	
	/**
	 * Add a received message to the session.
	 * @param msg [in] The message to add.
	 */
	void recv_msg(const t_msg &msg);
	
	/**
	 * Send a message to the remote party.
	 * The message will be added to the list of messages.
	 * @param message [in] Message to be sent.
	 * @param format [in] Text format of the message.
	 */
	void send_msg(const string &message, t_text_format format);
	
	/**
	 * Send a message with file attachment to the remote party.
	 * The message will be added to the list of messages.
	 * @param filename [in] Name of file to be sent.
	 * @param media [in] Mime type of the file.
	 * @param subject [in] Subject of message.
	 */
	void send_file(const string &filename, const t_media &media, const string &subject);
	
	/**
	 * Set the error message of the session.
	 * @param message [in] Error message.
	 * @post @ref error_msg == message
	 * @post @ref error_recvd == true
	 */
	void set_error(const string &message);
	
	/**
	 * Check if an error has been received.
	 * @return true, if an error has been received.
	 * @return false, otherwise
	 */
	bool error_received(void) const;
	
	/**
	 * Take the error message from the session.
	 * @return Error message.
	 * @pre @ref error_received() == true
	 * @post @ref error_received() == false
	 */
	string take_error(void);
	
	/**
	 * Set the delivery notification of the session.
	 * @param notification [in] Delivery notification.
	 * @post @ref delivery_notification == notification
	 * @post @ref delivery_notification_recvd == true
	 */
	void set_delivery_notification(const string &notification);
	
	/**
	 * Check if a delivery notification has been received.
	 * @return true, if an error has been received.
	 * @return false, otherwise
	 */
	bool delivery_notification_received(void) const;
	
	/**
	 * Take the delivery notification from the session.
	 * @return Delivery notification.
	 * @pre @ref delivery_notification_received() == true
	 * @post @ref delivery_notification_received() == false
	 */
	string take_delivery_notification(void);
	
	/**
	 * Check if the session matches with a particular user and
	 * remote party.
	 * @param user [in] The user
	 * @param remote_party [in] URL of the remote party
	 * @return true, if there is a match
	 * @return false, otherwise
	 */
	bool match(t_user *user, t_url _remote_party);
	
	/**
	 * Set the message in flight indicator.
	 * @param in_flight [in] Indicator value to set.
	 */
	void set_msg_in_flight(bool in_flight);
	
	/**
	 * Check if a message is in flight.
	 * @return true, message is in flight.
	 * @return false, no message is in flight.
	 */
	bool is_msg_in_flight(void) const;
	
	/**
	 * Set the local composing state.
	 * If the state transitions to a new state, then a composing indication
	 * is sent to the remote party.
	 * The local idle timeout and refresh timeout timers are updated depending
	 * on the current state.
	 * @param state [in] The new local composing state.
	 */
	void set_local_composing_state(t_composing_state state);
	
	/**
	 * Set the remote composing state.
	 * The remote idle timeout timer is updated depending on the state.
	 * @param state [in] The new remote composing state.
	 * @param idle_timeout [in] The idle timeout value when state == active.
	 * @note When state == idle, then the idle_timout argument has no meaning.
	 */
	void set_remote_composing_state(t_composing_state state, time_t idle_timeout = 120);
	
	/**
	 * Decrement the timeout values for the local composing state if
	 * the current state is active.
	 * If the idle timeout reaches zero, then the state transitions
	 * to idle, and an idle indication is sent to the remote party.
	 * If the refresh timeout reaches zero, then an active indication
	 * is sent to the remote party.
	 * If the current state is idle, then nothing is done.
	 */
	void dec_local_composing_timeout(void);
	
	/** Decrement the timeout values for the remote composing state if
	 * the current state is active.
	 * If the idle timeout reaches zero, then the state transitions
	 * to idle.
	 * If the current state is idle, then nothing is done.
	 */
	void dec_remote_composing_timeout(void);
};

}; // end namespace

#endif