From c36477c1d12027a61f63df7e0ec5047deb99358e Mon Sep 17 00:00:00 2001 From: Jakub Adam Date: Tue, 16 Feb 2010 08:34:53 +0000 Subject: [PATCH] =?utf8?q?filetransfer:=20contribution=20by=20Jakub=20Adam?= =?utf8?q?=20and=20Tom=C3=A1=C5=A1=20Hrab=C4=8D=C3=ADk=20Thank=20you=20a?= =?utf8?q?=20lot=20for=20your=20contribution!=20Original=20source:=20https?= =?utf8?q?://sourceforge.net/tracker/=3Ffunc=3Ddetail&aid=3D2952332&group?= =?utf8?q?=5Fid=3D194563&atid=3D949933?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- src/core/Makefile.am | 2 ++ src/core/sipe-session.c | 32 ++++++++++++++++++++++++- src/core/sipe-session.h | 38 +++++++++++++++++++++++++++++ src/core/sipe.c | 63 +++++++++++++++++++++++++++++++------------------ src/core/sipe.h | 5 ++++ src/core/sipmsg.c | 63 +++++++++++++++++++++++++++++-------------------- src/core/sipmsg.h | 1 + 7 files changed, 154 insertions(+), 50 deletions(-) diff --git a/src/core/Makefile.am b/src/core/Makefile.am index 01d04aa7..7d297d47 100644 --- a/src/core/Makefile.am +++ b/src/core/Makefile.am @@ -38,6 +38,8 @@ libsipe_la_SOURCES = \ sip-sec-ntlm.c \ sipe-sign.h \ sipe-sign.c \ + sipe-ft.h \ + sipe-ft.c \ uuid.h \ uuid.c diff --git a/src/core/sipe-session.c b/src/core/sipe-session.c index 3d126ebf..9f341da7 100644 --- a/src/core/sipe-session.c +++ b/src/core/sipe-session.c @@ -166,7 +166,10 @@ sipe_session_remove(struct sipe_account_data *sip, struct sip_session *session) entry = session->outgoing_message_queue; while (entry) { - g_free(entry->data); + struct queued_message *msg = entry->data; + g_free(msg->body); + g_free(msg->content_type); + g_free(msg); entry = entry->next; } g_slist_free(session->outgoing_message_queue); @@ -200,6 +203,33 @@ sipe_session_remove_all(struct sipe_account_data *sip) } } +void +sipe_session_enqueue_message(struct sip_session *session, + const gchar *body, const gchar *content_type) +{ + struct queued_message *msg = g_new0(struct queued_message,1); + msg->body = g_strdup(body); + if (content_type != NULL) + msg->content_type = g_strdup(content_type); + + session->outgoing_message_queue = g_slist_append(session->outgoing_message_queue, msg); +} + +GSList * +sipe_session_dequeue_message(struct sip_session *session) +{ + if (session->outgoing_message_queue == NULL) + return NULL; + + struct queued_message *msg = session->outgoing_message_queue->data; + session->outgoing_message_queue = g_slist_remove(session->outgoing_message_queue, msg); + g_free(msg->body); + g_free(msg->content_type); + g_free(msg); + + return session->outgoing_message_queue; +} + /* Local Variables: mode: c diff --git a/src/core/sipe-session.h b/src/core/sipe-session.h index d35b976a..dbaf5d3a 100644 --- a/src/core/sipe-session.h +++ b/src/core/sipe-session.h @@ -71,6 +71,23 @@ struct sip_session { }; /** + * An item in outgoing message queue. + * + * Messages are put in the queue until a response to initial INVITE is received + * from remote dialog participant. + */ +struct queued_message { + /** Body of the message. */ + gchar *body; + /** + * Content type of message body, e.g. text/plain for chat messages, + * text/x-msmsgsinvite for filetransfer initialization. Setting this to NULL + * means default value text/plain. + */ + gchar *content_type; +}; + +/** * Add a new chat session * * @param sip (in) SIP account data. May be NULL @@ -179,3 +196,24 @@ sipe_session_remove(struct sipe_account_data *sip, */ void sipe_session_remove_all(struct sipe_account_data *sip); + +/** + * Add a message to outgoing queue. + * + * @param session (in) SIP session + * @param body (in) message to send + * @param content_type (in) content type of the message body + */ +void +sipe_session_enqueue_message(struct sip_session *session, + const gchar *body, const gchar *content_type); + +/** + * Removes and deallocates the first item in outgoing message queue. + * + * @param session (in) SIP session + * + * @return pointer to new message queue head + */ +GSList * +sipe_session_dequeue_message(struct sip_session *session); diff --git a/src/core/sipe.c b/src/core/sipe.c index 4333fb48..dddd5f5e 100644 --- a/src/core/sipe.c +++ b/src/core/sipe.c @@ -82,6 +82,7 @@ #include "sipe-nls.h" #include "sipe-session.h" #include "sipe-utils.h" +#include "sipe-ft.h" #include "sipmsg.h" #include "sipe-sign.h" #include "dnssrv.h" @@ -3968,8 +3969,6 @@ sipe_present_message_undelivered_err(struct sipe_account_data *sip, } -static void sipe_im_process_queue (struct sipe_account_data * sip, struct sip_session * session); - static gboolean process_message_response(struct sipe_account_data *sip, struct sipmsg *msg, SIPE_UNUSED_PARAMETER struct transaction *trans) @@ -4092,7 +4091,7 @@ process_info_response(struct sipe_account_data *sip, struct sipmsg *msg, return TRUE; } -static void sipe_send_message(struct sipe_account_data *sip, struct sip_dialog *dialog, const char *msg) +static void sipe_send_message(struct sipe_account_data *sip, struct sip_dialog *dialog, const char *msg, const char *content_type) { gchar *hdr; gchar *tmp; @@ -4117,7 +4116,10 @@ static void sipe_send_message(struct sipe_account_data *sip, struct sip_dialog * //hdr = g_strdup("Content-Type: text/plain; charset=UTF-8\r\n"); //hdr = g_strdup("Content-Type: text/rtf\r\n"); //hdr = g_strdup("Content-Type: text/plain; charset=UTF-8;msgr=WAAtAE0ATQBTAC....AoADQA\r\nSupported: timer\r\n"); - hdr = g_strdup_printf("Contact: %s\r\nContent-Type: text/plain; charset=UTF-8%s\r\n", tmp, msgr); + if (content_type == NULL) + content_type = "text/plain"; + + hdr = g_strdup_printf("Contact: %s\r\nContent-Type: %s; charset=UTF-8%s\r\n", tmp, content_type, msgr); g_free(tmp); g_free(msgr); @@ -4127,18 +4129,18 @@ static void sipe_send_message(struct sipe_account_data *sip, struct sip_dialog * } -static void +void sipe_im_process_queue (struct sipe_account_data * sip, struct sip_session * session) { GSList *entry2 = session->outgoing_message_queue; while (entry2) { - char *queued_msg = entry2->data; + struct queued_message *msg = entry2->data; /* for multiparty chat or conference */ if (session->is_multiparty || session->focus_uri) { gchar *who = sip_uri_self(sip); serv_got_chat_in(sip->gc, session->chat_id, who, - PURPLE_MESSAGE_SEND, queued_msg, time(NULL)); + PURPLE_MESSAGE_SEND, msg->body, time(NULL)); g_free(who); } @@ -4148,16 +4150,15 @@ sipe_im_process_queue (struct sipe_account_data * sip, struct sip_session * sess if (dialog->outgoing_invite) continue; /* do not send messages as INVITE is not responded. */ key = g_strdup_printf("<%s><%d><%s>", dialog->callid, (dialog->cseq) + 1, dialog->with); - g_hash_table_insert(session->unconfirmed_messages, g_strdup(key), g_strdup(queued_msg)); + g_hash_table_insert(session->unconfirmed_messages, g_strdup(key), g_strdup(msg->body)); purple_debug_info("sipe", "sipe_im_process_queue: added message %s to unconfirmed_messages(count=%d)\n", key, g_hash_table_size(session->unconfirmed_messages)); g_free(key); - sipe_send_message(sip, dialog, queued_msg); + sipe_send_message(sip, dialog, msg->body, msg->content_type); } SIPE_DIALOG_FOREACH_END; - entry2 = session->outgoing_message_queue = g_slist_remove(session->outgoing_message_queue, queued_msg); - g_free(queued_msg); + entry2 = sipe_session_dequeue_message(session); } } @@ -4271,11 +4272,7 @@ process_invite_response(struct sipe_account_data *sip, struct sipmsg *msg, struc if(g_slist_find_custom(dialog->supported, "ms-text-format", (GCompareFunc)g_ascii_strcasecmp)) { purple_debug_info("sipe", "process_invite_response: remote system accepted message in INVITE\n"); - if (session->outgoing_message_queue) { - char *queued_msg = session->outgoing_message_queue->data; - session->outgoing_message_queue = g_slist_remove(session->outgoing_message_queue, queued_msg); - g_free(queued_msg); - } + sipe_session_dequeue_message(session); } sipe_im_process_queue(sip, session); @@ -4546,7 +4543,7 @@ static int sipe_im_send(PurpleConnection *gc, const char *who, const char *what, dialog = sipe_dialog_find(session, uri); // Queue the message - session->outgoing_message_queue = g_slist_append(session->outgoing_message_queue, g_strdup(what)); + sipe_session_enqueue_message(session, what, NULL); if (dialog && !dialog->outgoing_invite) { sipe_im_process_queue(sip, session); @@ -4571,8 +4568,7 @@ static int sipe_chat_send(PurpleConnection *gc, int id, const char *what, // Queue the message if (session && session->dialogs) { - session->outgoing_message_queue = g_slist_append(session->outgoing_message_queue, - g_strdup(what)); + sipe_session_enqueue_message(session,what,NULL); sipe_im_process_queue(sip, session); } else if (sip) { gchar *chat_name = purple_find_chat(sip->gc, id)->name; @@ -4586,8 +4582,7 @@ static int sipe_chat_send(PurpleConnection *gc, int id, const char *what, session->is_multiparty = FALSE; session->focus_uri = g_strdup(proto_chat_id); - session->outgoing_message_queue = g_slist_append(session->outgoing_message_queue, - g_strdup(what)); + sipe_session_enqueue_message(session, what, NULL); sipe_invite_conf_focus(sip, session); } } @@ -4880,6 +4875,25 @@ static void process_incoming_message(struct sipe_account_data *sip, struct sipms xmlnode_free(isc); send_sip_response(sip->gc, msg, 200, "OK", NULL); found = TRUE; + } else if (g_str_has_prefix(contenttype, "text/x-msmsgsinvite")) { + gchar **lines = g_strsplit(msg->body,"\r\n",0); + int result = sipmsg_parse_and_append_header(msg,lines); + g_strfreev(lines); + + if (result == TRUE) { + gchar *invitation_command = sipmsg_find_header(msg, "Invitation-Command"); + + if (!strcmp(invitation_command,"INVITE")) { + sipe_ft_incoming_transfer(sip->gc->account,msg); + found = TRUE; + } else if (!strcmp(invitation_command,"CANCEL")) { + sipe_ft_incoming_cancel(sip->gc->account, msg); + found = TRUE; + } else if (!strcmp(invitation_command,"ACCEPT")) { + sipe_ft_incoming_accept(sip->gc->account, msg); + found = TRUE; + } + } } if (!found) { gchar *callid = sipmsg_find_header(msg, "Call-ID"); @@ -8378,6 +8392,8 @@ static void sipe_login(PurpleAccount *account) sip->subscriptions = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)sipe_subscription_free); + sip->filetransfers = g_hash_table_new_full(g_str_hash, g_str_equal,g_free,NULL); + purple_connection_update_progress(gc, _("Connecting"), 1, 2); g_free(sip->status); @@ -8579,6 +8595,7 @@ static void sipe_close(PurpleConnection *gc) g_hash_table_destroy(sip->our_publications); g_hash_table_destroy(sip->user_state_publications); g_hash_table_destroy(sip->subscriptions); + g_hash_table_destroy(sip->filetransfers); if (sip->groups) { GSList *entry = sip->groups; @@ -9863,8 +9880,8 @@ static PurplePluginProtocolInfo prpl_info = NULL, /* roomlist_cancel */ NULL, /* roomlist_expand_category */ NULL, /* can_receive_file */ - NULL, /* send_file */ - NULL, /* new_xfer */ + sipe_ft_send_file, /* send_file */ + sipe_ft_new_xfer, /* new_xfer */ NULL, /* offline_message */ NULL, /* whiteboard_prpl_ops */ sipe_send_raw, /* send_raw */ diff --git a/src/core/sipe.h b/src/core/sipe.h index 0d550c84..5ec12065 100644 --- a/src/core/sipe.h +++ b/src/core/sipe.h @@ -226,6 +226,7 @@ struct sipe_account_data { GSList *sessions; GSList *openconns; GSList *groups; + GHashTable *filetransfers; sipe_transport_type transport; gboolean auto_transport; PurpleSslConnection *gsc; @@ -401,6 +402,10 @@ void sipe_process_pending_invite_queue(struct sipe_account_data *sip, struct sip_session *session); +void +sipe_im_process_queue (struct sipe_account_data * sip, struct sip_session * session); + + /*** THE BIG SPLIT END ***/ #define SIPE_INVITE_TEXT "ms-text-format: text/plain; charset=UTF-8%s;ms-body=%s\r\n" diff --git a/src/core/sipmsg.c b/src/core/sipmsg.c index ec230d42..ffec9bb3 100644 --- a/src/core/sipmsg.c +++ b/src/core/sipmsg.c @@ -47,15 +47,45 @@ struct sipmsg *sipmsg_parse_msg(const gchar *msg) { return smsg; } +int sipmsg_parse_and_append_header(struct sipmsg *msg, gchar **lines) { + int i; + gchar **parts; + gchar *dummy; + gchar *dummy2; + gchar *tmp; + + for(i = 0; lines[i] && strlen(lines[i]) > 2; i++) { + parts = g_strsplit(lines[i], ":", 2); + if(!parts[0] || !parts[1]) { + g_strfreev(parts); + return FALSE; + } + dummy = parts[1]; + dummy2 = 0; + while(*dummy==' ' || *dummy=='\t') dummy++; + dummy2 = g_strdup(dummy); + while(lines[i+1] && (lines[i+1][0]==' ' || lines[i+1][0]=='\t')) { + i++; + dummy = lines[i]; + while(*dummy==' ' || *dummy=='\t') dummy++; + tmp = g_strdup_printf("%s %s",dummy2, dummy); + g_free(dummy2); + dummy2 = tmp; + } + sipmsg_add_header_now(msg, parts[0], dummy2); + g_free(dummy2); + g_strfreev(parts); + } + + return TRUE; +} + struct sipmsg *sipmsg_parse_header(const gchar *header) { struct sipmsg *msg = g_new0(struct sipmsg,1); gchar **lines = g_strsplit(header,"\r\n",0); gchar **parts; - gchar *dummy; - gchar *dummy2; gchar *tmp; gchar *contentlength; - int i=1; if(!lines[0]) { g_strfreev(lines); g_free(msg); @@ -77,29 +107,10 @@ struct sipmsg *sipmsg_parse_header(const gchar *header) { msg->response = 0; } g_strfreev(parts); - for(i=1; lines[i] && strlen(lines[i])>2; i++) { - parts = g_strsplit(lines[i], ":", 2); - if(!parts[0] || !parts[1]) { - g_strfreev(parts); - g_strfreev(lines); - sipmsg_free(msg); - return NULL; - } - dummy = parts[1]; - dummy2 = 0; - while(*dummy==' ' || *dummy=='\t') dummy++; - dummy2 = g_strdup(dummy); - while(lines[i+1] && (lines[i+1][0]==' ' || lines[i+1][0]=='\t')) { - i++; - dummy = lines[i]; - while(*dummy==' ' || *dummy=='\t') dummy++; - tmp = g_strdup_printf("%s %s",dummy2, dummy); - g_free(dummy2); - dummy2 = tmp; - } - sipmsg_add_header_now(msg, parts[0], dummy2); - g_free(dummy2); - g_strfreev(parts); + if (sipmsg_parse_and_append_header(msg,lines + 1) == FALSE) { + g_strfreev(lines); + sipmsg_free(msg); + return NULL; } g_strfreev(lines); contentlength = sipmsg_find_header(msg, "Content-Length"); diff --git a/src/core/sipmsg.h b/src/core/sipmsg.h index 9769562a..eff146bf 100644 --- a/src/core/sipmsg.h +++ b/src/core/sipmsg.h @@ -51,6 +51,7 @@ struct sipendpoint { struct sipmsg *sipmsg_parse_msg(const gchar *msg); +int sipmsg_parse_and_append_header(struct sipmsg *msg, gchar **lines); struct sipmsg *sipmsg_parse_header(const gchar *header); void sipmsg_print(const struct sipmsg *msg); void sipmsg_add_header_now(struct sipmsg *msg, const gchar *name, const gchar *value); -- 2.11.4.GIT