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);
65 static void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatMessage* msg){
66 const char *route=NULL;
67 const char *identity=linphone_core_find_best_identity(cr->lc,cr->peer_url,&route);
72 if (lp_config_get_int(cr->lc->config,"sip","chat_use_call_dialogs",0)){
73 if((call = linphone_core_get_call_by_remote_address(cr->lc,cr->peer))!=NULL){
74 if (call->state==LinphoneCallConnected ||
75 call->state==LinphoneCallStreamsRunning ||
76 call->state==LinphoneCallPaused ||
77 call->state==LinphoneCallPausing ||
78 call->state==LinphoneCallPausedByRemote){
79 ms_message("send SIP message through the existing call.");
81 call->pending_message=msg;
86 /*sending out of calls*/
87 op = sal_op_new(cr->lc->sal);
88 sal_op_set_route(op,route);
89 sal_op_set_user_pointer(op, msg); /*if out of call, directly store msg*/
90 if (msg->custom_headers){
91 sal_op_set_custom_header(op,msg->custom_headers);
92 msg->custom_headers=NULL; /*transfered to the SalOp*/
95 if (msg->external_body_url) {
96 content_type=ms_strdup_printf("message/external-body; access-type=URL; URL=\"%s\"",msg->external_body_url);
97 sal_message_send(op,identity,cr->peer,content_type, NULL);
98 ms_free(content_type);
100 sal_text_send(op, identity, cr->peer,msg->message);
105 * Send a message to peer member of this chat room.
106 * @deprecated linphone_chat_room_send_message2() gives more control on the message expedition.
107 * @param cr #LinphoneChatRoom object
108 * @param msg message to be sent
110 void linphone_chat_room_send_message(LinphoneChatRoom *cr, const char *msg) {
111 _linphone_chat_room_send_message(cr,linphone_chat_room_create_message(cr,msg));
114 bool_t linphone_chat_room_matches(LinphoneChatRoom *cr, const LinphoneAddress *from){
115 if (linphone_address_get_username(cr->peer_url) && linphone_address_get_username(from) &&
116 strcmp(linphone_address_get_username(cr->peer_url),linphone_address_get_username(from))==0) return TRUE;
120 void linphone_chat_room_message_received(LinphoneChatRoom *cr, LinphoneCore *lc, LinphoneChatMessage *msg){
123 if (lc->vtable.text_received!=NULL) lc->vtable.text_received(lc, cr, msg->from, msg->message);
124 if (lc->vtable.message_received!=NULL) lc->vtable.message_received(lc, cr,msg);
128 void linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessage *sal_msg){
130 LinphoneChatRoom *cr=NULL;
131 LinphoneAddress *addr;
133 LinphoneChatMessage* msg;
134 const SalCustomHeader *ch;
136 addr=linphone_address_new(sal_msg->from);
137 linphone_address_clean(addr);
138 for(elem=lc->chatrooms;elem!=NULL;elem=ms_list_next(elem)){
139 cr=(LinphoneChatRoom*)elem->data;
140 if (linphone_chat_room_matches(cr,addr)){
145 cleanfrom=linphone_address_as_string(addr);
147 /* create a new chat room */
148 cr=linphone_core_create_chat_room(lc,cleanfrom);
150 msg = linphone_chat_room_create_message(cr, sal_msg->text);
151 linphone_chat_message_set_from(msg, cr->peer_url);
152 msg->time=sal_msg->time;
153 ch=sal_op_get_custom_header(op);
154 if (ch) msg->custom_headers=sal_custom_header_clone(ch);
157 linphone_chat_message_set_external_body_url(msg, sal_msg->url);
159 linphone_address_destroy(addr);
160 linphone_chat_room_message_received(cr,lc,msg);
165 * Returns back pointer to LinphoneCore object.
167 LinphoneCore* linphone_chat_room_get_lc(LinphoneChatRoom *cr){
172 * Assign a user pointer to the chat room.
174 void linphone_chat_room_set_user_data(LinphoneChatRoom *cr, void * ud){
179 * Retrieve the user pointer associated with the chat room.
181 void * linphone_chat_room_get_user_data(LinphoneChatRoom *cr){
182 return cr->user_data;
186 * get peer address \link linphone_core_create_chat_room() associated to \endlink this #LinphoneChatRoom
187 * @param cr #LinphoneChatRoom object
188 * @return #LinphoneAddress peer address
190 const LinphoneAddress* linphone_chat_room_get_peer_address(LinphoneChatRoom *cr) {
195 * Create a message attached to a dedicated chat room;
196 * @param cr the chat room.
197 * @param message text message, NULL if absent.
198 * @return a new #LinphoneChatMessage
200 LinphoneChatMessage* linphone_chat_room_create_message(LinphoneChatRoom *cr, const char* message) {
201 LinphoneChatMessage* msg = ms_new0(LinphoneChatMessage,1);
202 msg->chat_room=(LinphoneChatRoom*)cr;
203 msg->message=message?ms_strdup(message):NULL;
208 * Send a message to peer member of this chat room.
209 * @param cr #LinphoneChatRoom object
210 * @param msg #LinphoneChatMessage message to be sent
211 * @param status_cb LinphoneChatMessageStateChangeCb status callback invoked when message is delivered or could not be delivered. May be NULL
212 * @param ud user data for the status cb.
213 * @note The LinphoneChatMessage must not be destroyed until the the callback is called.
215 void linphone_chat_room_send_message2(LinphoneChatRoom *cr, LinphoneChatMessage* msg,LinphoneChatMessageStateChangeCb status_cb, void* ud) {
218 _linphone_chat_room_send_message(cr, msg);
222 * Returns a #LinphoneChatMessageState as a string.
224 const char* linphone_chat_message_state_to_string(const LinphoneChatMessageState state) {
226 case LinphoneChatMessageStateIdle:return "LinphoneChatMessageStateIdle";
227 case LinphoneChatMessageStateInProgress:return "LinphoneChatMessageStateInProgress";
228 case LinphoneChatMessageStateDelivered:return "LinphoneChatMessageStateDelivered";
229 case LinphoneChatMessageStateNotDelivered:return "LinphoneChatMessageStateNotDelivered";
230 default: return "Unknown state";
236 * Returns the chatroom this message belongs to.
238 LinphoneChatRoom* linphone_chat_message_get_chat_room(LinphoneChatMessage *msg){
239 return msg->chat_room;
243 * Returns the peer (remote) address for the message.
245 const LinphoneAddress* linphone_chat_message_get_peer_address(LinphoneChatMessage *msg) {
246 return linphone_chat_room_get_peer_address(msg->chat_room);
250 *User pointer set function
252 void linphone_chat_message_set_user_data(LinphoneChatMessage* message,void* ud) {
253 message->message_userdata=ud;
257 * User pointer get function
259 void* linphone_chat_message_get_user_data(const LinphoneChatMessage* message) {
260 return message->message_userdata;
264 * Linphone message can carry external body as defined by rfc2017
265 * @param message #LinphoneChatMessage
266 * @return external body url or NULL if not present.
268 const char* linphone_chat_message_get_external_body_url(const LinphoneChatMessage* message) {
269 return message->external_body_url;
273 * Linphone message can carry external body as defined by rfc2017
275 * @param message a LinphoneChatMessage
276 * @param url ex: access-type=URL; URL="http://www.foo.com/file"
278 void linphone_chat_message_set_external_body_url(LinphoneChatMessage* message,const char* url) {
279 if (message->external_body_url) {
280 ms_free(message->external_body_url);
282 message->external_body_url=url?ms_strdup(url):NULL;
286 * Set origin of the message
287 *@param message #LinphoneChatMessage obj
288 *@param from #LinphoneAddress origin of this message (copied)
290 void linphone_chat_message_set_from(LinphoneChatMessage* message, const LinphoneAddress* from) {
291 if(message->from) linphone_address_destroy(message->from);
292 message->from=linphone_address_clone(from);
296 * Get origin of the message
297 *@param message #LinphoneChatMessage obj
298 *@return #LinphoneAddress
300 LinphoneAddress* linphone_chat_message_get_from(const LinphoneChatMessage* message) {
301 return message->from;
305 * Get the time the message was sent.
307 time_t linphone_chat_message_get_time(const LinphoneChatMessage* message) {
308 return message->time;
312 * Get text part of this message
313 * @return text or NULL if no text.
315 const char * linphone_chat_message_get_text(const LinphoneChatMessage* message) {
316 return message->message;
320 * Add custom headers to the message.
321 * @param message the message
322 * @param header_name name of the header_name
323 * @param header_value header value
325 void linphone_chat_message_add_custom_header(LinphoneChatMessage* message, const char *header_name, const char *header_value){
326 message->custom_headers=sal_custom_header_append(message->custom_headers,header_name,header_value);
330 * Retrieve a custom header value given its name.
331 * @param message the message
332 * @param header_name header name searched
334 const char * linphone_chat_message_get_custom_header(LinphoneChatMessage* message, const char *header_name){
335 return sal_custom_header_find(message->custom_headers,header_name);
339 * Duplicate a LinphoneChatMessage
341 LinphoneChatMessage* linphone_chat_message_clone(const LinphoneChatMessage* msg) {
342 /*struct _LinphoneChatMessage {
344 LinphoneChatRoom* chat_room;
345 LinphoneChatMessageStateChangeCb cb;
347 void* message_userdata;
348 char* external_body_url;
349 LinphoneAddress* from;
351 LinphoneChatMessage* new_message = linphone_chat_room_create_message(msg->chat_room,msg->message);
352 if (msg->external_body_url) new_message->external_body_url=ms_strdup(msg->external_body_url);
353 new_message->cb=msg->cb;
354 new_message->cb_ud=msg->cb_ud;
355 new_message->message_userdata=msg->message_userdata;
356 new_message->cb=msg->cb;
357 if (msg->from) new_message->from=linphone_address_clone(msg->from);
362 * Destroys a LinphoneChatMessage.
364 void linphone_chat_message_destroy(LinphoneChatMessage* msg) {
365 if (msg->message) ms_free(msg->message);
366 if (msg->external_body_url) ms_free(msg->external_body_url);
367 if (msg->from) linphone_address_destroy(msg->from);
368 if (msg->custom_headers) sal_custom_header_free(msg->custom_headers);