6 * Copyright (C) 2014-2015 SIPE Project <http://sipe.sourceforge.net/>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 #include "sip-transport.h"
28 #include "sipe-backend.h"
29 #include "sipe-common.h"
30 #include "sipe-core.h"
31 #include "sipe-core-private.h"
32 #include "sipe-ft-lync.h"
33 #include "sipe-media.h"
34 #include "sipe-mime.h"
35 #include "sipe-utils.h"
39 struct sipe_file_transfer_lync
{
40 struct sipe_file_transfer
public;
48 struct sipe_media_call
*call
;
50 #define SIPE_FILE_TRANSFER ((struct sipe_file_transfer *) ft_private)
51 #define SIPE_FILE_TRANSFER_PRIVATE ((struct sipe_file_transfer_lync *) ft)
54 sipe_file_transfer_lync_free(struct sipe_file_transfer_lync
*ft_private
)
56 g_free(ft_private
->file_name
);
57 g_free(ft_private
->sdp
);
58 g_free(ft_private
->id
);
63 send_ms_filetransfer_msg(char *body
, struct sipe_file_transfer_lync
*ft_private
,
64 TransCallback callback
)
66 sip_transport_info(sipe_media_get_sipe_core_private(ft_private
->call
),
67 "Content-Type: application/ms-filetransfer+xml\r\n",
69 sipe_media_get_sip_dialog(ft_private
->call
),
76 send_ms_filetransfer_response(struct sipe_file_transfer_lync
*ft_private
,
77 const gchar
*code
, const gchar
*reason
,
78 TransCallback callback
)
80 static const gchar
*RESPONSE_STR
=
81 "<response xmlns=\"http://schemas.microsoft.com/rtc/2009/05/filetransfer\" requestId=\"%d\" code=\"%s\" %s%s%s/>";
83 send_ms_filetransfer_msg(g_strdup_printf(RESPONSE_STR
,
84 ft_private
->request_id
, code
,
85 reason
? "reason=\"" : "",
88 ft_private
, callback
);
92 mime_mixed_cb(gpointer user_data
, const GSList
*fields
, const gchar
*body
,
95 struct sipe_file_transfer_lync
*ft_private
= user_data
;
96 const gchar
*ctype
= sipe_utils_nameval_find(fields
, "Content-Type");
98 /* Lync 2010 file transfer */
99 if (g_str_has_prefix(ctype
, "application/ms-filetransfer+xml")) {
100 sipe_xml
*xml
= sipe_xml_parse(body
, length
);
101 const sipe_xml
*node
;
103 const gchar
*request_id_str
= sipe_xml_attribute(xml
, "requestId");
104 if (request_id_str
) {
105 ft_private
->request_id
= atoi(request_id_str
);
108 node
= sipe_xml_child(xml
, "publishFile/fileInfo/name");
110 ft_private
->file_name
= sipe_xml_data(node
);
113 node
= sipe_xml_child(xml
, "publishFile/fileInfo/id");
115 ft_private
->id
= sipe_xml_data(node
);
118 node
= sipe_xml_child(xml
, "publishFile/fileInfo/size");
120 gchar
*size_str
= sipe_xml_data(node
);
122 ft_private
->file_size
= atoi(size_str
);
126 } else if (g_str_has_prefix(ctype
, "application/sdp")) {
127 ft_private
->sdp
= g_strndup(body
, length
);
132 candidate_pair_established_cb(SIPE_UNUSED_PARAMETER
struct sipe_media_call
*call
,
133 struct sipe_media_stream
*stream
)
135 struct sipe_file_transfer_lync
*ft_private
;
136 static const gchar
*DOWNLOAD_FILE_REQUEST
=
137 "<request xmlns=\"http://schemas.microsoft.com/rtc/2009/05/filetransfer\" requestId=\"%d\">"
146 g_return_if_fail(sipe_strequal(stream
->id
, "data"));
148 ft_private
= sipe_media_stream_get_data(stream
);
150 send_ms_filetransfer_response(ft_private
, "success", NULL
, NULL
);
152 send_ms_filetransfer_msg(g_strdup_printf(DOWNLOAD_FILE_REQUEST
,
153 ++ft_private
->request_id
,
155 ft_private
->file_name
),
160 ft_lync_incoming_init(struct sipe_file_transfer
*ft
,
161 SIPE_UNUSED_PARAMETER
const gchar
*filename
,
162 SIPE_UNUSED_PARAMETER gsize size
,
163 SIPE_UNUSED_PARAMETER
const gchar
*who
)
165 struct sipe_media_call
*call
= SIPE_FILE_TRANSFER_PRIVATE
->call
;
168 sipe_backend_media_accept(call
->backend_private
, TRUE
);
173 ft_lync_deallocate(struct sipe_file_transfer
*ft
)
175 struct sipe_media_call
*call
= SIPE_FILE_TRANSFER_PRIVATE
->call
;
178 sipe_backend_media_hangup(call
->backend_private
, TRUE
);
180 sipe_file_transfer_lync_free(SIPE_FILE_TRANSFER_PRIVATE
);
184 process_incoming_invite_ft_lync(struct sipe_core_private
*sipe_private
,
187 struct sipe_file_transfer_lync
*ft_private
;
188 struct sipe_media_call
*call
;
189 struct sipe_media_stream
*stream
;
191 ft_private
= g_new0(struct sipe_file_transfer_lync
, 1);
192 sipe_mime_parts_foreach(sipmsg_find_header(msg
, "Content-Type"),
193 msg
->body
, mime_mixed_cb
, ft_private
);
195 if (!ft_private
->file_name
|| !ft_private
->file_size
|| !ft_private
->sdp
) {
196 sip_transport_response(sipe_private
, msg
, 488, "Not Acceptable Here", NULL
);
197 sipe_file_transfer_lync_free(ft_private
);
201 /* Replace multipart message body with the selected SDP part and
202 * initialize media session as if invited to a media call. */
204 msg
->body
= ft_private
->sdp
;
205 msg
->bodylen
= strlen(msg
->body
);
206 ft_private
->sdp
= NULL
;
208 ft_private
->call
= process_incoming_invite_call(sipe_private
, msg
);
209 if (!ft_private
->call
) {
210 sip_transport_response(sipe_private
, msg
, 500, "Server Internal Error", NULL
);
211 sipe_file_transfer_lync_free(ft_private
);
215 call
= ft_private
->call
;
216 call
->candidate_pair_established_cb
= candidate_pair_established_cb
;
218 ft_private
->public.ft_init
= ft_lync_incoming_init
;
219 ft_private
->public.ft_deallocate
= ft_lync_deallocate
;
221 stream
= sipe_core_media_get_stream_by_id(call
, "data");
222 sipe_media_stream_add_extra_attribute(stream
, "recvonly", NULL
);
223 sipe_media_stream_set_data(stream
, ft_private
, NULL
);
225 sipe_backend_ft_incoming(SIPE_CORE_PUBLIC
, SIPE_FILE_TRANSFER
,
226 call
->with
, ft_private
->file_name
,
227 ft_private
->file_size
);