1 /***************************************************************************
4 * Sun Jun 5 19:34:18 2005
5 * Copyright 2005 Simon Morlat
6 * Email simon dot morlat at linphone dot org
7 ****************************************************************************/
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 #include "linphonecore.h"
30 * @addtogroup chatroom
35 * Create a new chat room for messaging from a sip uri like sip:joe@sip.linphone.org
36 * @param lc #LinphoneCore object
37 * @param to destination address for messages
38 * @return #LinphoneChatRoom where messaging can take place.
40 LinphoneChatRoom * linphone_core_create_chat_room(LinphoneCore *lc, const char *to){
41 LinphoneAddress *parsed_url=NULL;
43 if ((parsed_url=linphone_core_interpret_url(lc,to))!=NULL){
44 LinphoneChatRoom *cr=ms_new0(LinphoneChatRoom,1);
46 cr->peer=linphone_address_as_string(parsed_url);
47 cr->peer_url=parsed_url;
48 lc->chatrooms=ms_list_append(lc->chatrooms,(void *)cr);
55 * Destroy a LinphoneChatRoom.
56 * @param cr #LinphoneChatRoom object
58 void linphone_chat_room_destroy(LinphoneChatRoom *cr){
59 LinphoneCore *lc=cr->lc;
60 lc->chatrooms=ms_list_remove(lc->chatrooms,(void *) cr);
61 linphone_address_destroy(cr->peer_url);
67 static inline char *my_ctime_r(const time_t *t, char *buf){
73 #define my_ctime_r ctime_r
76 static void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatMessage* msg){
77 const char *route=NULL;
78 const char *identity=linphone_core_find_best_identity(cr->lc,cr->peer_url,&route);
86 if (lp_config_get_int(cr->lc->config,"sip","chat_use_call_dialogs",0)){
87 if((call = linphone_core_get_call_by_remote_address(cr->lc,cr->peer))!=NULL){
88 if (call->state==LinphoneCallConnected ||
89 call->state==LinphoneCallStreamsRunning ||
90 call->state==LinphoneCallPaused ||
91 call->state==LinphoneCallPausing ||
92 call->state==LinphoneCallPausedByRemote){
93 ms_message("send SIP message through the existing call.");
95 call->pending_message=msg;
101 /*sending out of calls*/
102 op = sal_op_new(cr->lc->sal);
103 sal_op_set_route(op,route);
104 sal_op_set_user_pointer(op, msg); /*if out of call, directly store msg*/
105 if (msg->custom_headers){
106 sal_op_set_custom_header(op,msg->custom_headers);
107 msg->custom_headers=NULL; /*transfered to the SalOp*/
110 if (msg->external_body_url) {
111 content_type=ms_strdup_printf("message/external-body; access-type=URL; URL=\"%s\"",msg->external_body_url);
112 sal_message_send(op,identity,cr->peer,content_type, NULL,my_ctime_r(&t,buf));
113 ms_free(content_type);
115 sal_text_send(op, identity, cr->peer,msg->message,my_ctime_r(&t,buf));
117 to=linphone_address_as_string_uri_only (cr->peer_url);
118 linphone_core_set_history_message(cr,identity,to,OUTGOING,msg->message,
119 my_ctime_r(&t,buf),READ,LinphoneChatMessageStateInProgress);
124 * Send a message to peer member of this chat room.
125 * @deprecated linphone_chat_room_send_message2() gives more control on the message expedition.
126 * @param cr #LinphoneChatRoom object
127 * @param msg message to be sent
129 void linphone_chat_room_send_message(LinphoneChatRoom *cr, const char *msg) {
130 _linphone_chat_room_send_message(cr,linphone_chat_room_create_message(cr,msg));
133 bool_t linphone_chat_room_matches(LinphoneChatRoom *cr, const LinphoneAddress *from){
134 if (linphone_address_get_username(cr->peer_url) && linphone_address_get_username(from) &&
135 strcmp(linphone_address_get_username(cr->peer_url),linphone_address_get_username(from))==0) return TRUE;
139 void linphone_chat_room_message_received(LinphoneChatRoom *cr, LinphoneCore *lc, LinphoneChatMessage *msg){
142 if (lc->vtable.text_received!=NULL) lc->vtable.text_received(lc, cr, msg->from, msg->message);
143 if (lc->vtable.message_received!=NULL) lc->vtable.message_received(lc, cr,msg);
147 void linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessage *sal_msg){
149 LinphoneChatRoom *cr=NULL;
150 LinphoneAddress *addr;
154 LinphoneChatMessage* msg;
155 const SalCustomHeader *ch;
158 addr=linphone_address_new(sal_msg->from);
159 linphone_address_clean(addr);
160 for(elem=lc->chatrooms;elem!=NULL;elem=ms_list_next(elem)){
161 cr=(LinphoneChatRoom*)elem->data;
162 if (linphone_chat_room_matches(cr,addr)){
167 to=linphone_core_get_identity(lc);
168 cleanfrom=linphone_address_as_string(addr);
169 from=linphone_address_as_string_uri_only(addr);
171 /* create a new chat room */
172 cr=linphone_core_create_chat_room(lc,cleanfrom);
174 msg = linphone_chat_room_create_message(cr, sal_msg->text);
175 linphone_chat_message_set_from(msg, cr->peer_url);
176 msg->time=sal_msg->time;
177 msg->state=LinphoneChatMessageStateDelivered;
178 ch=sal_op_get_custom_header(op);
179 if (ch) msg->custom_headers=sal_custom_header_clone(ch);
182 linphone_chat_message_set_external_body_url(msg, sal_msg->url);
184 linphone_address_destroy(addr);
185 linphone_chat_room_message_received(cr,lc,msg);
186 linphone_core_set_history_message(cr,to,from,INCOMING,
187 msg->message,my_ctime_r(&msg->time,buf),NOT_READ,
188 LinphoneChatMessageStateDelivered);
194 * Returns back pointer to LinphoneCore object.
196 LinphoneCore* linphone_chat_room_get_lc(LinphoneChatRoom *cr){
201 * Assign a user pointer to the chat room.
203 void linphone_chat_room_set_user_data(LinphoneChatRoom *cr, void * ud){
208 * Retrieve the user pointer associated with the chat room.
210 void * linphone_chat_room_get_user_data(LinphoneChatRoom *cr){
211 return cr->user_data;
215 * get peer address \link linphone_core_create_chat_room() associated to \endlink this #LinphoneChatRoom
216 * @param cr #LinphoneChatRoom object
217 * @return #LinphoneAddress peer address
219 const LinphoneAddress* linphone_chat_room_get_peer_address(LinphoneChatRoom *cr) {
224 * Create a message attached to a dedicated chat room;
225 * @param cr the chat room.
226 * @param message text message, NULL if absent.
227 * @return a new #LinphoneChatMessage
229 LinphoneChatMessage* linphone_chat_room_create_message(LinphoneChatRoom *cr, const char* message) {
230 LinphoneChatMessage* msg = ms_new0(LinphoneChatMessage,1);
231 msg->chat_room=(LinphoneChatRoom*)cr;
232 msg->message=message?ms_strdup(message):NULL;
237 * Send a message to peer member of this chat room.
238 * @param cr #LinphoneChatRoom object
239 * @param msg #LinphoneChatMessage message to be sent
240 * @param status_cb LinphoneChatMessageStateChangeCb status callback invoked when message is delivered or could not be delivered. May be NULL
241 * @param ud user data for the status cb.
242 * @note The LinphoneChatMessage must not be destroyed until the the callback is called.
244 void linphone_chat_room_send_message2(LinphoneChatRoom *cr, LinphoneChatMessage* msg,LinphoneChatMessageStateChangeCb status_cb, void* ud) {
247 msg->state=LinphoneChatMessageStateInProgress;
248 _linphone_chat_room_send_message(cr, msg);
252 * Returns a #LinphoneChatMessageState as a string.
254 const char* linphone_chat_message_state_to_string(const LinphoneChatMessageState state) {
256 case LinphoneChatMessageStateIdle:return "LinphoneChatMessageStateIdle";
257 case LinphoneChatMessageStateInProgress:return "LinphoneChatMessageStateInProgress";
258 case LinphoneChatMessageStateDelivered:return "LinphoneChatMessageStateDelivered";
259 case LinphoneChatMessageStateNotDelivered:return "LinphoneChatMessageStateNotDelivered";
260 default: return "Unknown state";
266 * Returns the chatroom this message belongs to.
268 LinphoneChatRoom* linphone_chat_message_get_chat_room(LinphoneChatMessage *msg){
269 return msg->chat_room;
273 * Returns the peer (remote) address for the message.
275 const LinphoneAddress* linphone_chat_message_get_peer_address(LinphoneChatMessage *msg) {
276 return linphone_chat_room_get_peer_address(msg->chat_room);
280 *User pointer set function
282 void linphone_chat_message_set_user_data(LinphoneChatMessage* message,void* ud) {
283 message->message_userdata=ud;
287 * User pointer get function
289 void* linphone_chat_message_get_user_data(const LinphoneChatMessage* message) {
290 return message->message_userdata;
294 * Linphone message can carry external body as defined by rfc2017
295 * @param message #LinphoneChatMessage
296 * @return external body url or NULL if not present.
298 const char* linphone_chat_message_get_external_body_url(const LinphoneChatMessage* message) {
299 return message->external_body_url;
303 * Linphone message can carry external body as defined by rfc2017
305 * @param message a LinphoneChatMessage
306 * @param url ex: access-type=URL; URL="http://www.foo.com/file"
308 void linphone_chat_message_set_external_body_url(LinphoneChatMessage* message,const char* url) {
309 if (message->external_body_url) {
310 ms_free(message->external_body_url);
312 message->external_body_url=url?ms_strdup(url):NULL;
316 * Set origin of the message
317 *@param message #LinphoneChatMessage obj
318 *@param from #LinphoneAddress origin of this message (copied)
320 void linphone_chat_message_set_from(LinphoneChatMessage* message, const LinphoneAddress* from) {
321 if(message->from) linphone_address_destroy(message->from);
322 message->from=linphone_address_clone(from);
326 * Get origin of the message
327 *@param message #LinphoneChatMessage obj
328 *@return #LinphoneAddress
330 LinphoneAddress* linphone_chat_message_get_from(const LinphoneChatMessage* message) {
331 return message->from;
335 * Get the time the message was sent.
337 time_t linphone_chat_message_get_time(const LinphoneChatMessage* message) {
338 return message->time;
342 * Get the state of the message
343 *@param message #LinphoneChatMessage obj
344 *@return #LinphoneChatMessageState
346 LinphoneChatMessageState linphone_chat_message_get_state(const LinphoneChatMessage* message) {
347 return message->state;
351 * Get text part of this message
352 * @return text or NULL if no text.
354 const char * linphone_chat_message_get_text(const LinphoneChatMessage* message) {
355 return message->message;
359 * Add custom headers to the message.
360 * @param message the message
361 * @param header_name name of the header_name
362 * @param header_value header value
364 void linphone_chat_message_add_custom_header(LinphoneChatMessage* message, const char *header_name, const char *header_value){
365 message->custom_headers=sal_custom_header_append(message->custom_headers,header_name,header_value);
369 * Retrieve a custom header value given its name.
370 * @param message the message
371 * @param header_name header name searched
373 const char * linphone_chat_message_get_custom_header(LinphoneChatMessage* message, const char *header_name){
374 return sal_custom_header_find(message->custom_headers,header_name);
378 * Duplicate a LinphoneChatMessage
380 LinphoneChatMessage* linphone_chat_message_clone(const LinphoneChatMessage* msg) {
381 /*struct _LinphoneChatMessage {
383 LinphoneChatRoom* chat_room;
384 LinphoneChatMessageStateChangeCb cb;
386 void* message_userdata;
387 char* external_body_url;
388 LinphoneAddress* from;
390 SalCustomHeader *custom_headers;
391 LinphoneChatMessageState state;
393 LinphoneChatMessage* new_message = linphone_chat_room_create_message(msg->chat_room,msg->message);
394 if (msg->external_body_url) new_message->external_body_url=ms_strdup(msg->external_body_url);
395 new_message->cb=msg->cb;
396 new_message->cb_ud=msg->cb_ud;
397 new_message->message_userdata=msg->message_userdata;
398 new_message->cb=msg->cb;
399 new_message->time=msg->time;
400 new_message->state=msg->state;
401 if (msg->from) new_message->from=linphone_address_clone(msg->from);
406 * Destroys a LinphoneChatMessage.
408 void linphone_chat_message_destroy(LinphoneChatMessage* msg) {
409 if (msg->message) ms_free(msg->message);
410 if (msg->external_body_url) ms_free(msg->external_body_url);
411 if (msg->from) linphone_address_destroy(msg->from);
412 if (msg->custom_headers) sal_custom_header_free(msg->custom_headers);