# HG changeset patch # User Stu Tomlinson # Date 1101059289 0 # Node ID ecf3ce2e2ab1a2762eeda871116b3152c44dead7 # Parent ef7f9e69f03e62547f3790f79a8dc547c33e8e89 [gaim-migrate @ 11357] This is mostly a patch from Felipe Contreras that eliminates MSN switchboard errors and fixes MSN buddy icon syncronization, with some tweaks by me. Thank Felipe if it works, blame me if something broke. I also fixed a couple of text markup escaping things, fixed a glib warning that was bugging me, fix a rare SILC crash, and make gtkstatusselector.c compile (but do nothing) with gtk < 2.4 committer: Tailor Script diff -r ef7f9e69f03e -r ecf3ce2e2ab1 src/ft.c --- a/src/ft.c Sun Nov 21 06:16:23 2004 +0000 +++ b/src/ft.c Sun Nov 21 17:48:09 2004 +0000 @@ -246,7 +246,7 @@ static void gaim_xfer_ask_recv(GaimXfer *xfer) { - char *buf, *size_buf; + char *buf, *size_buf, *escaped; size_t size; /* If we have already accepted the request, ask the destination file @@ -255,10 +255,12 @@ size = gaim_xfer_get_size(xfer); size_buf = gaim_str_size_to_units(size); + escaped = g_markup_escape_text(gaim_xfer_get_filename(xfer), -1); buf = g_strdup_printf(_("%s wants to send you %s (%s)"), - xfer->who, gaim_xfer_get_filename(xfer), + xfer->who, escaped, size_buf); g_free(size_buf); + g_free(escaped); if (xfer->message != NULL) serv_got_im(gaim_account_get_connection(xfer->account), @@ -904,14 +906,16 @@ gaim_xfer_cancel_local(GaimXfer *xfer) { GaimXferUiOps *ui_ops; - char *msg = NULL; + char *msg = NULL, *escaped; g_return_if_fail(xfer != NULL); gaim_xfer_set_status(xfer, GAIM_XFER_STATUS_CANCEL_LOCAL); + escaped = g_markup_escape_text(gaim_xfer_get_filename(xfer), -1); msg = g_strdup_printf(_("You canceled the transfer of %s"), - gaim_xfer_get_filename(xfer)); + escaped); + g_free(escaped); gaim_xfer_conversation_write(xfer, msg, FALSE); g_free(msg); @@ -953,15 +957,17 @@ gaim_xfer_cancel_remote(GaimXfer *xfer) { GaimXferUiOps *ui_ops; - gchar *msg; + gchar *msg, *escaped; g_return_if_fail(xfer != NULL); gaim_request_close_with_handle(xfer); gaim_xfer_set_status(xfer, GAIM_XFER_STATUS_CANCEL_REMOTE); + escaped = g_markup_escape_text(gaim_xfer_get_filename(xfer), -1); msg = g_strdup_printf(_("%s canceled the transfer of %s"), - xfer->who, gaim_xfer_get_filename(xfer)); + xfer->who, escaped); + g_free(escaped); gaim_xfer_conversation_write(xfer, msg, TRUE); gaim_xfer_error(gaim_xfer_get_type(xfer), xfer->who, msg); g_free(msg); diff -r ef7f9e69f03e -r ecf3ce2e2ab1 src/gtkrequest.c --- a/src/gtkrequest.c Sun Nov 21 06:16:23 2004 +0000 +++ b/src/gtkrequest.c Sun Nov 21 17:48:09 2004 +0000 @@ -1433,7 +1433,8 @@ filesel = gtk_file_selection_new(title ? title : (savedialog ? _("Save File...") : _("Open File..."))); - gtk_file_selection_set_filename(GTK_FILE_SELECTION(filesel), filename); + if (filename != NULL) + gtk_file_selection_set_filename(GTK_FILE_SELECTION(filesel), filename); g_signal_connect_swapped(G_OBJECT(GTK_FILE_SELECTION(filesel)), "delete_event", G_CALLBACK(file_cancel_cb), data); g_signal_connect_swapped(G_OBJECT(GTK_FILE_SELECTION(filesel)->cancel_button), diff -r ef7f9e69f03e -r ecf3ce2e2ab1 src/gtkstatusselector.c --- a/src/gtkstatusselector.c Sun Nov 21 06:16:23 2004 +0000 +++ b/src/gtkstatusselector.c Sun Nov 21 17:48:09 2004 +0000 @@ -38,14 +38,11 @@ GtkWidget *entry; GtkWidget *frame; -#if GTK_CHECK_VERSION(2,4,0) GtkListStore *model; -#endif guint entry_timer; }; -#if GTK_CHECK_VERSION(2,4,0) enum { COLUMN_STATUS_TYPE_ID, @@ -53,15 +50,16 @@ COLUMN_NAME, NUM_COLUMNS }; -#endif /* GTK >= 2.4.0 */ static void gaim_gtk_status_selector_class_init(GaimGtkStatusSelectorClass *klass); static void gaim_gtk_status_selector_init(GaimGtkStatusSelector *selector); static void gaim_gtk_status_selector_finalize(GObject *obj); static void gaim_gtk_status_selector_destroy(GtkObject *obj); +#if GTK_CHECK_VERSION (2,4,0) static void status_switched_cb(GtkWidget *combo, GaimGtkStatusSelector *selector); static gboolean key_press_cb(GtkWidget *entry, GdkEventKey *event, gpointer user_data); static void signed_on_off_cb(GaimConnection *gc, GaimGtkStatusSelector *selector); +#endif static void rebuild_list(GaimGtkStatusSelector *selector); static GtkVBox *parent_class = NULL; @@ -112,11 +110,11 @@ static void gaim_gtk_status_selector_init(GaimGtkStatusSelector *selector) { +#if GTK_CHECK_VERSION(2,4,0) GtkWidget *combo; GtkWidget *entry; GtkWidget *toolbar; GtkWidget *frame; -#if GTK_CHECK_VERSION(2,4,0) GtkCellRenderer *renderer; #endif @@ -145,11 +143,9 @@ g_signal_connect(G_OBJECT(combo), "changed", G_CALLBACK(status_switched_cb), selector); -#else /* GTK < 2.4.0 */ /* TODO */ -#endif /* GTK < 2.4.0 */ gtk_widget_show(combo); gtk_box_pack_start(GTK_BOX(selector), combo, FALSE, FALSE, 0); @@ -172,6 +168,7 @@ selector); rebuild_list(selector); +#endif /* GTK < 2.4.0 */ } static void @@ -206,6 +203,7 @@ GTK_OBJECT_CLASS(parent_class)->destroy(obj); } +#if GTK_CHECK_VERSION(2,4,0) static void status_switched_cb(GtkWidget *combo, GaimGtkStatusSelector *selector) { @@ -280,10 +278,12 @@ gtk_widget_hide(selector->priv->frame); } } +#endif static gboolean insert_text_timeout_cb(gpointer data) { +#if GTK_CHECK_VERSION(2,4,0) GaimGtkStatusSelector *selector = (GaimGtkStatusSelector *)data; GtkTreeIter iter; const char *status_type_id; @@ -335,6 +335,7 @@ } } } +#endif return FALSE; } diff -r ef7f9e69f03e -r ecf3ce2e2ab1 src/protocols/msn/cmdproc.c --- a/src/protocols/msn/cmdproc.c Sun Nov 21 06:16:23 2004 +0000 +++ b/src/protocols/msn/cmdproc.c Sun Nov 21 17:48:09 2004 +0000 @@ -250,6 +250,10 @@ if (cmd->trId) trans = msn_history_find(cmdproc->history, cmd->trId); + if (trans != NULL) + if (trans->timer) + gaim_timeout_remove(trans->timer); + if (g_ascii_isdigit(cmd->command[0])) { if (trans != NULL) @@ -258,11 +262,17 @@ int error; error = atoi(cmd->command); - if (cmdproc->cbs_table->errors != NULL) + + if (trans->error_cb != NULL) + error_cb = trans->error_cb; + + if (error_cb == NULL && cmdproc->cbs_table->errors != NULL) error_cb = g_hash_table_lookup(cmdproc->cbs_table->errors, trans->command); if (error_cb != NULL) + { error_cb(cmdproc, trans, error); + } else { #if 1 diff -r ef7f9e69f03e -r ecf3ce2e2ab1 src/protocols/msn/msg.c --- a/src/protocols/msn/msg.c Sun Nov 21 06:16:23 2004 +0000 +++ b/src/protocols/msn/msg.c Sun Nov 21 17:48:09 2004 +0000 @@ -25,11 +25,12 @@ #include "msg.h" MsnMessage * -msn_message_new(void) +msn_message_new(MsnMsgType type) { MsnMessage *msg; msg = g_new0(MsnMessage, 1); + msg->type = type; msg->attr_table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); @@ -45,11 +46,11 @@ MsnMessage *msg; char *message_cr; - msg = msn_message_new(); + msg = msn_message_new(MSN_MSG_TEXT); msn_message_set_attr(msg, "User-Agent", "Gaim/" VERSION); msn_message_set_content_type(msg, "text/plain"); msn_message_set_charset(msg, "UTF-8"); - msn_message_set_flag(msg, 'N'); + msn_message_set_flag(msg, 'A'); msn_message_set_attr(msg, "X-MMS-IM-Format", "FN=MS%20Sans%20Serif; EF=; CO=0; PF=0"); @@ -65,7 +66,7 @@ { MsnMessage *msg; - msg = msn_message_new(); + msg = msn_message_new(MSN_MSG_SLP); msn_message_set_attr(msg, "User-Agent", NULL); @@ -226,7 +227,7 @@ g_return_val_if_fail(cmd != NULL, NULL); - msg = msn_message_new(); + msg = msn_message_new(MSN_MSG_UNKNOWN); msg->remote_user = g_strdup(cmd->params[0]); /* msg->size = atoi(cmd->params[2]); */ @@ -612,6 +613,20 @@ return table; } +char * +msn_message_to_string(MsnMessage *msg) +{ + size_t body_len; + const char *body; + + g_return_val_if_fail(msg != NULL, NULL); + g_return_val_if_fail(msg->type == MSN_MSG_TEXT, NULL); + + body = msn_message_get_bin_data(msg, &body_len); + + return g_strndup(body, body_len); +} + void msn_message_show_readable(MsnMessage *msg, const char *info, gboolean text_body) diff -r ef7f9e69f03e -r ecf3ce2e2ab1 src/protocols/msn/msg.h --- a/src/protocols/msn/msg.h Sun Nov 21 06:16:23 2004 +0000 +++ b/src/protocols/msn/msg.h Sun Nov 21 17:48:09 2004 +0000 @@ -32,6 +32,9 @@ #include "command.h" #include "transaction.h" +typedef void (*MsnCb)(void *data); + +/* typedef enum { MSN_MSG_NORMAL, @@ -39,6 +42,17 @@ MSN_MSG_SLP_DC } MsnMsgType; +*/ + +typedef enum +{ + MSN_MSG_UNKNOWN, + MSN_MSG_TEXT, + MSN_MSG_TYPING, + MSN_MSG_CAPS, + MSN_MSG_SLP + +} MsnMsgType; typedef struct { @@ -88,7 +102,7 @@ MsnCommand *cmd; MsnTransaction *trans; - MsnTransCb ack_cb; + MsnCb ack_cb; void *ack_data; }; @@ -97,7 +111,7 @@ * * @return A new message. */ -MsnMessage *msn_message_new(void); +MsnMessage *msn_message_new(MsnMsgType type); /** * Creates a new, empty MSNSLP message. @@ -299,5 +313,6 @@ char *msn_message_gen_slp_body(MsnMessage *msg, size_t *ret_size); +char *msn_message_to_string(MsnMessage *msg); #endif /* _MSN_MSG_H_ */ diff -r ef7f9e69f03e -r ecf3ce2e2ab1 src/protocols/msn/msn.c --- a/src/protocols/msn/msn.c Sun Nov 21 06:16:23 2004 +0000 +++ b/src/protocols/msn/msn.c Sun Nov 21 17:48:09 2004 +0000 @@ -192,7 +192,7 @@ payload = msn_page_gen_payload(page, &payload_len); - trans = msn_transaction_new("PGD", "%s 1 %d", who, payload_len); + trans = msn_transaction_new(cmdproc, "PGD", "%s 1 %d", who, payload_len); msn_transaction_set_payload(trans, payload, payload_len); @@ -798,7 +798,7 @@ if (!swboard->user_joined) return 0; - msg = msn_message_new(); + msg = msn_message_new(MSN_MSG_TYPING); msn_message_set_content_type(msg, "text/x-msmsgscontrol"); msn_message_set_flag(msg, 'U'); msn_message_set_attr(msg, "TypingUser", diff -r ef7f9e69f03e -r ecf3ce2e2ab1 src/protocols/msn/notification.c --- a/src/protocols/msn/notification.c Sun Nov 21 06:16:23 2004 +0000 +++ b/src/protocols/msn/notification.c Sun Nov 21 17:48:09 2004 +0000 @@ -286,7 +286,7 @@ for (i = 0; i < 16; i++) g_snprintf(buf + (i*2), 3, "%02x", di[i]); - trans = msn_transaction_new("QRY", "%s 32", "PROD0038W!61ZTF9"); + trans = msn_transaction_new(cmdproc, "QRY", "%s 32", "PROD0038W!61ZTF9"); msn_transaction_set_payload(trans, buf, 32); @@ -981,7 +981,7 @@ if (session->passport_info.file == NULL) { MsnTransaction *trans; - trans = msn_transaction_new("URL", "%s", "INBOX"); + trans = msn_transaction_new(cmdproc, "URL", "%s", "INBOX"); msn_transaction_queue_cmd(trans, msg->cmd); msn_cmdproc_send_trans(cmdproc, trans); @@ -1034,7 +1034,7 @@ if (session->passport_info.file == NULL) { MsnTransaction *trans; - trans = msn_transaction_new("URL", "%s", "INBOX"); + trans = msn_transaction_new(cmdproc, "URL", "%s", "INBOX"); msn_transaction_queue_cmd(trans, msg->cmd); msn_cmdproc_send_trans(cmdproc, trans); diff -r ef7f9e69f03e -r ecf3ce2e2ab1 src/protocols/msn/servconn.c --- a/src/protocols/msn/servconn.c Sun Nov 21 06:16:23 2004 +0000 +++ b/src/protocols/msn/servconn.c Sun Nov 21 17:48:09 2004 +0000 @@ -65,6 +65,10 @@ } else { + MsnSwitchBoard *swboard; + swboard = servconn->data; + swboard->error = MSN_SB_ERROR_CONNECTION; + /* GaimAccount *account; char *primary; @@ -75,6 +79,7 @@ gaim_notify_error(gc, NULL, primary, tmp); g_free(primary); + */ } g_free(tmp); diff -r ef7f9e69f03e -r ecf3ce2e2ab1 src/protocols/msn/servconn.h --- a/src/protocols/msn/servconn.h Sun Nov 21 06:16:23 2004 +0000 +++ b/src/protocols/msn/servconn.h Sun Nov 21 17:48:09 2004 +0000 @@ -70,7 +70,6 @@ size_t payload_len; void (*connect_cb)(MsnServConn *); -/* void (*failed_io_cb)(MsnServConn *); */ void (*disconnect_cb)(MsnServConn *); void (*data_free_cb)(void *data); void *data; @@ -86,8 +85,6 @@ void (*connect_cb)(MsnServConn *)); void msn_servconn_set_disconnect_cb(MsnServConn *servconn, void (*disconnect_cb)(MsnServConn *)); -void msn_servconn_set_failed_io_cb(MsnServConn *servconn, - void (*failed_io_cb)(MsnServConn *)); size_t msn_servconn_write(MsnServConn *servconn, const char *buf, size_t size); #endif /* _MSN_SERVCONN_H_ */ diff -r ef7f9e69f03e -r ecf3ce2e2ab1 src/protocols/msn/session.c --- a/src/protocols/msn/session.c Sun Nov 21 06:16:23 2004 +0000 +++ b/src/protocols/msn/session.c Sun Nov 21 17:48:09 2004 +0000 @@ -131,7 +131,6 @@ } /* TODO: This must go away when conversation is redesigned */ - MsnSwitchBoard * msn_session_find_swboard(MsnSession *session, const char *username) { @@ -185,9 +184,9 @@ if (swboard == NULL) { swboard = msn_switchboard_new(session); + swboard->im_user = g_strdup(username); msn_switchboard_request(swboard); msn_switchboard_request_add_user(swboard, username); - swboard->im_user = g_strdup(username); } return swboard; diff -r ef7f9e69f03e -r ecf3ce2e2ab1 src/protocols/msn/slp.c --- a/src/protocols/msn/slp.c Sun Nov 21 06:16:23 2004 +0000 +++ b/src/protocols/msn/slp.c Sun Nov 21 17:48:09 2004 +0000 @@ -144,9 +144,11 @@ void msn_xfer_end_cb(MsnSlpCall *slpcall) { - if (gaim_xfer_get_status(slpcall->xfer) != GAIM_XFER_STATUS_DONE) + if ((gaim_xfer_get_status(slpcall->xfer) != GAIM_XFER_STATUS_DONE) && + (gaim_xfer_get_status(slpcall->xfer) != GAIM_XFER_STATUS_CANCEL_REMOTE) && + (gaim_xfer_get_status(slpcall->xfer) != GAIM_XFER_STATUS_CANCEL_LOCAL)) { - gaim_xfer_cancel_remote(slpcall->xfer); + /* gaim_xfer_cancel_remote(slpcall->xfer); */ } } @@ -334,13 +336,13 @@ gaim_base64_decode(context, &bin, &bin_len); file_size = GUINT32_FROM_LE(*((gsize *)bin + 2)); - + uni_name = (gunichar2 *)(bin + 20); while(*uni_name != 0 && ((char *)uni_name - (bin + 20)) < MAX_FILE_NAME_LEN) { *uni_name = GUINT16_FROM_LE(*uni_name); uni_name++; } - + file_name = g_utf16_to_utf8((const gunichar2 *)(bin + 20), -1, NULL, NULL, NULL); @@ -669,7 +671,7 @@ size_t offset = c - status; if (offset >= sizeof(temp)) offset = sizeof(temp) - 1; - + strncpy(temp, status, offset); temp[offset] = '\0'; } @@ -760,7 +762,7 @@ slplink = msn_session_get_slplink(session, who); - msn_slplink_request_object(slplink, smile, got_emoticon, obj); + msn_slplink_request_object(slplink, smile, got_emoticon, NULL, obj); g_strfreev(tokens); } @@ -802,6 +804,10 @@ { MsnUser *user; + g_return_if_fail(userlist != NULL); + + gaim_debug_info("msn", "Releasing buddy icon request\n"); + while (userlist->buddy_icon_window > 0) { GQueue *queue; @@ -820,6 +826,9 @@ msn_request_user_display(user); userlist->buddy_icon_window--; + + gaim_debug_info("msn", "buddy_icon_window=%d\n", + userlist->buddy_icon_window); } } @@ -830,6 +839,8 @@ MsnObject *obj; GQueue *queue; + g_return_if_fail(user != NULL); + account = user->userlist->session->account; obj = msn_user_get_object(user); @@ -860,8 +871,14 @@ userlist = user->userlist; queue = userlist->buddy_icon_requests; + gaim_debug_info("msn", "Queueing buddy icon request: %s\n", + user->passport); + g_queue_push_tail(queue, user); + gaim_debug_info("msn", "buddy_icon_window=%d\n", + userlist->buddy_icon_window); + if (userlist->buddy_icon_window > 0) msn_release_buddy_icon_request(userlist); } @@ -871,13 +888,17 @@ got_user_display(MsnSlpCall *slpcall, const char *data, long long size) { + MsnUserList *userlist; const char *info; GaimAccount *account; GSList *sl; + g_return_if_fail(slpcall != NULL); + info = slpcall->data_info; gaim_debug_info("msn", "Got User Display: %s\n", info); + userlist = slpcall->slplink->session->userlist; account = slpcall->slplink->session->account; /* TODO: I think we need better buddy icon core functions. */ @@ -892,8 +913,35 @@ gaim_blist_node_set_string((GaimBlistNode*)buddy, "icon_checksum", info); } - slpcall->slplink->session->userlist->buddy_icon_window++; - msn_release_buddy_icon_request(slpcall->slplink->session->userlist); +#if 0 + /* Free one window slot */ + userlist->buddy_icon_window++; + + gaim_debug_info("msn", "buddy_icon_window=%d\n", + userlist->buddy_icon_window); + + msn_release_buddy_icon_request(userlist); +#endif +} + +void +end_user_display(MsnSlpCall *slpcall) +{ + MsnUserList *userlist; + + g_return_if_fail(slpcall != NULL); + + gaim_debug_info("msn", "End User Display\n"); + + userlist = slpcall->slplink->session->userlist; + + /* Free one window slot */ + userlist->buddy_icon_window++; + + gaim_debug_info("msn", "buddy_icon_window=%d\n", + userlist->buddy_icon_window); + + msn_release_buddy_icon_request(userlist); } void @@ -917,7 +965,8 @@ if (g_ascii_strcasecmp(user->passport, gaim_account_get_username(account))) { - msn_slplink_request_object(slplink, info, got_user_display, obj); + msn_slplink_request_object(slplink, info, got_user_display, + end_user_display, obj); } else { @@ -943,7 +992,7 @@ /* TODO: I think we need better buddy icon core functions. */ gaim_buddy_icons_set_for_user(account, user->passport, (void *)data, len); - + sl = gaim_find_buddies(account, user->passport); for (; sl != NULL; sl = sl->next) @@ -952,7 +1001,12 @@ gaim_blist_node_set_string((GaimBlistNode*)buddy, "icon_checksum", info); } + /* Free one window slot */ session->userlist->buddy_icon_window++; + + gaim_debug_info("msn", "buddy_icon_window=%d\n", + session->userlist->buddy_icon_window); + msn_release_buddy_icon_request(session->userlist); } } diff -r ef7f9e69f03e -r ecf3ce2e2ab1 src/protocols/msn/slpcall.c --- a/src/protocols/msn/slpcall.c Sun Nov 21 06:16:23 2004 +0000 +++ b/src/protocols/msn/slpcall.c Sun Nov 21 17:48:09 2004 +0000 @@ -62,6 +62,8 @@ slplink->slp_calls = g_list_append(slplink->slp_calls, slpcall); + slpcall->timer = gaim_timeout_add(MSN_SLPCALL_TIMEOUT, msn_slp_call_timeout, slpcall); + return slpcall; } @@ -93,6 +95,9 @@ g_return_if_fail(slpcall != NULL); + if (slpcall->timer) + gaim_timeout_remove(slpcall->timer); + if (slpcall->id != NULL) g_free(slpcall->id); @@ -181,6 +186,16 @@ msn_slp_call_destroy(slpcall); } +gboolean +msn_slp_call_timeout(gpointer data) +{ + gaim_debug_info("msn", "slpcall timeout\n"); + + msn_slp_call_destroy(data); + + return FALSE; +} + MsnSlpCall * msn_slp_process_msg(MsnSlpLink *slplink, MsnSlpMessage *slpmsg) { @@ -201,7 +216,20 @@ slpcall = msn_slplink_find_slp_call_with_session_id(slplink, slpmsg->session_id); if (slpcall != NULL) + { + if (slpcall->timer) + gaim_timeout_remove(slpcall->timer); + slpcall->cb(slpcall, body, body_len); + + /* TODO: Shall we send a BYE? I don't think so*/ +#if 0 + send_bye(slpcall, "application/x-msnmsgr-sessionclosebody"); + msn_slplink_unleash(slpcall->slplink); +#endif + + slpcall->wasted = TRUE; + } } #if 0 else if (slpmsg->flags == 0x100) @@ -213,5 +241,14 @@ } #endif + if (slpcall != NULL) + { + if (slpcall->timer) + gaim_timeout_remove(slpcall->timer); + + slpcall->timer = gaim_timeout_add(MSN_SLPCALL_TIMEOUT, + msn_slp_call_timeout, slpcall); + } + return slpcall; } diff -r ef7f9e69f03e -r ecf3ce2e2ab1 src/protocols/msn/slpcall.h --- a/src/protocols/msn/slpcall.h Sun Nov 21 06:16:23 2004 +0000 +++ b/src/protocols/msn/slpcall.h Sun Nov 21 17:48:09 2004 +0000 @@ -28,10 +28,14 @@ typedef void (*MsnSlpCb)(MsnSlpCall *slpcall, const char *data, long long size); +typedef void (*MsnSlpEndCb)(MsnSlpCall *slpcall); #include "slplink.h" #include "slpsession.h" +/* The official client seems to timeout slp calls after 5 minutes */ +#define MSN_SLPCALL_TIMEOUT 300000 + typedef enum { MSN_SLPCALL_ANY, @@ -66,6 +70,8 @@ void (*end_cb)(MsnSlpCall *slpcall); gboolean wasted; gboolean started; + + int timer; }; MsnSlpCall *msn_slp_call_new(MsnSlpLink *slplink); @@ -75,5 +81,6 @@ void msn_slp_call_invite(MsnSlpCall *slpcall, const char *euf_guid, int app_id, const char *context); void msn_slp_call_close(MsnSlpCall *slpcall); +gboolean msn_slp_call_timeout(gpointer data); #endif /* _MSN_SLPCALL_H_ */ diff -r ef7f9e69f03e -r ecf3ce2e2ab1 src/protocols/msn/slplink.c --- a/src/protocols/msn/slplink.c Sun Nov 21 06:16:23 2004 +0000 +++ b/src/protocols/msn/slplink.c Sun Nov 21 17:48:09 2004 +0000 @@ -100,11 +100,12 @@ MsnSlpLink * msn_session_find_slplink(MsnSession *session, const char *who) { - MsnSlpLink *slplink; GList *l; for (l = session->slplinks; l != NULL; l = l->next) { + MsnSlpLink *slplink; + slplink = l->data; if (!strcmp(slplink->remote_user, who)) @@ -192,7 +193,8 @@ { MsnSwitchBoard *swboard; - swboard = msn_session_get_swboard(slplink->session, slplink->remote_user); + swboard = msn_session_get_swboard(slplink->session, + slplink->remote_user); if (swboard == NULL) return; @@ -209,13 +211,14 @@ } } +/* We have received the message receive ack */ static void -t_ack(MsnCmdProc *cmdproc, MsnCommand *cmd) +msg_ack(void *data) { MsnSlpMessage *slpmsg; long long real_size; - slpmsg = cmd->trans->data; + slpmsg = data; real_size = (slpmsg->flags == 0x2) ? 0 : slpmsg->size; @@ -283,10 +286,16 @@ msn_slplink_send_msg(slplink, msg); - if (slpmsg->flags == 0x20 || slpmsg->flags == 0x1000030) + if ((slpmsg->flags == 0x20 || slpmsg->flags == 0x1000030) && (slpmsg->slpcall != NULL)) { - if ((slpmsg->slpcall != NULL) && - (slpmsg->slpcall->progress_cb != NULL)) + if (slpmsg->slpcall->timer) + { + gaim_timeout_remove(slpmsg->slpcall->timer); + slpmsg->slpcall->timer = gaim_timeout_add(MSN_SLPCALL_TIMEOUT, + msn_slp_call_timeout, slpmsg->slpcall); + } + + if (slpmsg->slpcall->progress_cb != NULL) { slpmsg->slpcall->progress_cb(slpmsg->slpcall, slpmsg->size, len, slpmsg->offset); @@ -338,7 +347,7 @@ msn_message_set_attr(msg, "P2P-Dest", slplink->remote_user); - msg->ack_cb = t_ack; + msg->ack_cb = msg_ack; msg->ack_data = slpmsg; msn_slplink_send_msgpart(slplink, slpmsg); @@ -473,7 +482,7 @@ } } } - if (!slpmsg->fp) + if (!slpmsg->fp && slpmsg->size) { slpmsg->buffer = g_try_malloc(slpmsg->size); if (slpmsg->buffer == NULL) @@ -495,7 +504,7 @@ /* fseek(slpmsg->fp, offset, SEEK_SET); */ len = fwrite(data, 1, len, slpmsg->fp); } - else + else if (slpmsg->size) { if ((offset + len) > slpmsg->size) { @@ -512,10 +521,16 @@ g_return_if_reached(); } - if (slpmsg->flags == 0x20 || slpmsg->flags == 0x1000030) + if ((slpmsg->flags == 0x20 || slpmsg->flags == 0x1000030) && (slpmsg->slpcall != NULL)) { - if ((slpmsg->slpcall != NULL) && - (slpmsg->slpcall->progress_cb != NULL)) + if (slpmsg->slpcall->timer) + { + gaim_timeout_remove(slpmsg->slpcall->timer); + slpmsg->slpcall->timer = gaim_timeout_add(MSN_SLPCALL_TIMEOUT, + msn_slp_call_timeout, slpmsg->slpcall); + } + + if (slpmsg->slpcall->progress_cb != NULL) { slpmsg->slpcall->progress_cb(slpmsg->slpcall, slpmsg->size, len, offset); @@ -623,7 +638,7 @@ header.file_size = GUINT32_TO_LE(size); header.unk2 = GUINT32_TO_LE(0); header.unk3 = GUINT32_TO_LE(0); - + base = g_malloc(len + 1); n = base; @@ -638,7 +653,7 @@ memset(n, 0xFF, 4); n += 4; - + g_free(uni); return gaim_base64_encode(base, len); } @@ -682,6 +697,7 @@ msn_slplink_request_object(MsnSlpLink *slplink, const char *info, MsnSlpCb cb, + MsnSlpEndCb end_cb, const MsnObject *obj) { MsnSlpCall *slpcall; @@ -700,6 +716,7 @@ slpcall->data_info = g_strdup(info); slpcall->cb = cb; + slpcall->end_cb = end_cb; msn_slp_call_invite(slpcall, "A4268EEC-FEC5-49E5-95C3-F126696BDBF6", 1, msnobj_base64); diff -r ef7f9e69f03e -r ecf3ce2e2ab1 src/protocols/msn/slplink.h --- a/src/protocols/msn/slplink.h Sun Nov 21 06:16:23 2004 +0000 +++ b/src/protocols/msn/slplink.h Sun Nov 21 17:48:09 2004 +0000 @@ -79,6 +79,7 @@ void msn_slplink_request_object(MsnSlpLink *slplink, const char *info, MsnSlpCb cb, + MsnSlpEndCb end_cb, const MsnObject *obj); MsnSlpCall *msn_slp_process_msg(MsnSlpLink *slplink, MsnSlpMessage *slpmsg); diff -r ef7f9e69f03e -r ecf3ce2e2ab1 src/protocols/msn/slpmsg.c --- a/src/protocols/msn/slpmsg.c Sun Nov 21 06:16:23 2004 +0000 +++ b/src/protocols/msn/slpmsg.c Sun Nov 21 17:48:09 2004 +0000 @@ -122,6 +122,7 @@ case 0x2: info = "SLP ACK"; break; case 0x20: + case 0x1000030: info = "SLP DATA"; break; default: info = "SLP UNKNOWN"; break; diff -r ef7f9e69f03e -r ecf3ce2e2ab1 src/protocols/msn/switchboard.c --- a/src/protocols/msn/switchboard.c Sun Nov 21 06:16:23 2004 +0000 +++ b/src/protocols/msn/switchboard.c Sun Nov 21 17:48:09 2004 +0000 @@ -31,6 +31,8 @@ static MsnTable *cbs_table; +static void cal_error(MsnCmdProc *cmdproc, MsnTransaction *trans, int error); + /************************************************************************** * Utility functions **************************************************************************/ @@ -39,7 +41,7 @@ { MsnMessage *msg; - msg = msn_message_new(); + msg = msn_message_new(MSN_MSG_CAPS); msn_message_set_content_type(msg, "text/x-clientcaps"); msn_message_set_flag(msg, 'U'); msn_message_set_bin_data(msg, MSN_CLIENTINFO, strlen(MSN_CLIENTINFO)); @@ -135,14 +137,41 @@ swboard->ready = TRUE; } +GaimConversation * +msn_switchboard_get_conv(MsnSwitchBoard *swboard) +{ + GaimAccount *account; + + g_return_val_if_fail(swboard != NULL, NULL); + + if (swboard->conv != NULL) + return swboard->conv; + + account = swboard->session->account; + + return gaim_find_conversation_with_account(swboard->im_user, account); +} + +void +msn_switchboard_report_user(MsnSwitchBoard *swboard, GaimMessageFlags flags, const char *msg) +{ + GaimConversation *conv; + + g_return_if_fail(swboard != NULL); + g_return_if_fail(msg != NULL); + + if ((conv = msn_switchboard_get_conv(swboard)) != NULL) + { + gaim_conversation_write(conv, NULL, msg, flags, time(NULL)); + } +} + static void bye_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) { - GaimAccount *account; MsnSwitchBoard *swboard; const char *user; - account = cmdproc->session->account; swboard = cmdproc->servconn->data; user = cmd->params[0]; @@ -155,16 +184,8 @@ } else { - char *username; - GaimConversation *conv; - GaimBuddy *b; char *str = NULL; - if ((b = gaim_find_buddy(account, user)) != NULL) - username = gaim_escape_html(gaim_buddy_get_alias(b)); - else - username = gaim_escape_html(user); - if (cmd->param_count == 2 && atoi(cmd->params[1]) == 1) { if (gaim_prefs_get_bool("/plugins/prpl/msn/conv_timeout_notice")) @@ -177,22 +198,28 @@ { if (gaim_prefs_get_bool("/plugins/prpl/msn/conv_close_notice")) { + char *username; + GaimAccount *account; + GaimBuddy *b; + + account = cmdproc->session->account; + + if ((b = gaim_find_buddy(account, user)) != NULL) + username = gaim_escape_html(gaim_buddy_get_alias(b)); + else + username = gaim_escape_html(user); + str = g_strdup_printf(_("%s has closed the conversation " "window."), username); + + g_free(username); } } - if (str != NULL && - (conv = gaim_find_conversation_with_account(user, account)) != NULL) - { - gaim_conversation_write(conv, NULL, str, GAIM_MESSAGE_SYSTEM, - time(NULL)); - - g_free(str); - } + if (str != NULL) + msn_switchboard_report_user(swboard, GAIM_MESSAGE_SYSTEM, str); msn_switchboard_disconnect(swboard); - g_free(username); } } @@ -433,6 +460,71 @@ #endif } +static void +msg_error_helper(MsnCmdProc *cmdproc, MsnMessage *msg) +{ + if (msg->type == MSN_MSG_TEXT) + { + MsnSwitchBoard *swboard; + char *body; + char *report; + char *str_reason; + + swboard = cmdproc->servconn->data; + + switch (swboard->error) + { + case MSN_SB_ERROR_OFFLINE: + str_reason = _("Message could not be sent, not allowed while invisible"); + break; + case MSN_SB_ERROR_USER_OFFLINE: + str_reason = _("Message could not be sent because the user is offline"); + break; + case MSN_SB_ERROR_CONNECTION: + str_reason = _("Message could not be sent because a connection error occured"); + break; + default: + str_reason = _("Message could not be sent for an unkwnown reason"); + break; + } + + body = msn_message_to_string(msg); + report = g_strdup_printf(_("%s:\n%s"), str_reason, body); + gaim_debug_info("msn", "%s\n", report); + msn_switchboard_report_user(cmdproc->servconn->data, GAIM_MESSAGE_ERROR, report); + g_free(report); + g_free(body); + } +} + +static void +msg_timeout(MsnCmdProc *cmdproc, MsnTransaction *trans) +{ + MsnMessage *msg; + + msg = trans->data; + g_return_if_fail(msg != NULL); + + gaim_debug_info("msn", "msg_timeout\n"); + msg_error_helper(cmdproc, msg); +} + +static void +msg_error(MsnCmdProc *cmdproc, MsnTransaction *trans, int error) +{ + msg_error_helper(cmdproc, trans->data); +} + +static void +msg_ack (MsnCmdProc *cmdproc, MsnCommand *cmd) +{ + MsnMessage *msg; + + msg = cmd->trans->data; + + msg->ack_cb (msg->ack_data); +} + void msn_switchboard_send_msg(MsnSwitchBoard *swboard, MsnMessage *msg) { @@ -450,11 +542,19 @@ /* msn_message_show_readable(msg, "SB SEND", FALSE); */ - trans = msn_transaction_new("MSG", "%c %d", msn_message_get_flag(msg), - payload_len); + trans = msn_transaction_new(cmdproc, "MSG", "%c %d", + msn_message_get_flag(msg), payload_len); + + /* Data for callbacks */ + msn_transaction_set_data(trans, msg); if (msg->ack_cb != NULL) - msn_transaction_add_cb(trans, "ACK", msg->ack_cb, msg->ack_data); + { + msn_transaction_add_cb(trans, "ACK", msg_ack); + msn_transaction_set_timeout_cb(trans, msg_timeout); + } + else if (msg->type == MSN_MSG_TEXT) + msn_transaction_set_timeout_cb(trans, msg_timeout); trans->payload = payload; trans->payload_len = payload_len; @@ -563,7 +663,8 @@ msn_table_add_cmd(cbs_table, NULL, "ACK", NULL); #endif - msn_table_add_error(cbs_table, "MSG", NULL); + msn_table_add_error(cbs_table, "MSG", msg_error); + msn_table_add_error(cbs_table, "CAL", cal_error); /* Register the message type callbacks. */ msn_table_add_msg_type(cbs_table, "text/plain", @@ -637,6 +738,19 @@ swboard->destroying = TRUE; + /* Destroy the message queue */ + while ((msg = g_queue_pop_head(swboard->im_queue)) != NULL) + { + if (swboard->error > 0) + { + /* The messages could not be sent due to an error */ + msg_error_helper(swboard->servconn->cmdproc, msg); + } + msn_message_destroy(msg); + } + + g_queue_free(swboard->im_queue); + if (swboard->im_user != NULL) g_free(swboard->im_user); @@ -655,36 +769,10 @@ if (swboard->servconn != NULL) msn_servconn_destroy(swboard->servconn); - while ((msg = g_queue_pop_head(swboard->im_queue)) != NULL) - msn_message_destroy(msg); - - g_queue_free(swboard->im_queue); - g_free(swboard); } #if 0 -void -msn_switchboard_set_user(MsnSwitchBoard *swboard, const char *user) -{ - g_return_if_fail(swboard != NULL); - - if (swboard->user != NULL) - g_free(swboard->user); - - swboard->user = g_strdup(user); -} - -const char * -msn_switchboard_get_user(MsnSwitchBoard *swboard) -{ - g_return_val_if_fail(swboard != NULL, NULL); - - return swboard->user; -} -#endif - -#if 0 static void got_cal(MsnCmdProc *cmdproc, MsnCommand *cmd) { @@ -699,6 +787,53 @@ } #endif +static void +swboard_error_helper(MsnSwitchBoard *swboard, int reason, const char *passport) +{ + gaim_debug_info("msg", "Error: Unable to call the user %s\n", passport); + + if (swboard->total_users == 0) + { + swboard->error = reason; + msn_switchboard_destroy(swboard); + } +} + +static void +cal_error_helper(MsnTransaction *trans, int reason) +{ + MsnSwitchBoard *swboard; + const char *passport; + char **params; + + params = g_strsplit(trans->params, " ", 0); + + passport = params[0]; + + swboard = trans->data; + + swboard_error_helper(swboard, reason, passport); + + g_strfreev(params); +} + +static void +cal_timeout(MsnCmdProc *cmdproc, MsnTransaction *trans) +{ + cal_error_helper(trans, MSN_SB_ERROR_UNKNOWN); +} + +static void +cal_error(MsnCmdProc *cmdproc, MsnTransaction *trans, int error) +{ + int reason = MSN_SB_ERROR_UNKNOWN; + + if (error == 217) + reason = MSN_SB_ERROR_USER_OFFLINE; + + cal_error_helper(trans, reason); +} + void msn_switchboard_request_add_user(MsnSwitchBoard *swboard, const char *user) { @@ -709,8 +844,11 @@ cmdproc = swboard->servconn->cmdproc; - trans = msn_transaction_new("CAL", "%s", user); - /* msn_transaction_add_cb(trans, "CAL", got_cal, NULL); */ + trans = msn_transaction_new(cmdproc, "CAL", "%s", user); + /* msn_transaction_add_cb(trans, "CAL", got_cal); */ + + msn_transaction_set_data(trans, swboard); + msn_transaction_set_timeout_cb(trans, cal_timeout); if (swboard->ready) msn_cmdproc_send_trans(cmdproc, trans); @@ -839,6 +977,20 @@ g_free(host); } +static void +xfr_error(MsnCmdProc *cmdproc, MsnTransaction *trans, int error) +{ + MsnSwitchBoard *swboard; + int reason = MSN_SB_ERROR_UNKNOWN; + + if (error == 913) + reason = MSN_SB_ERROR_OFFLINE; + + swboard = trans->data; + + swboard_error_helper(swboard, reason, swboard->im_user); +} + void msn_switchboard_request(MsnSwitchBoard *swboard) { @@ -849,8 +1001,10 @@ cmdproc = swboard->session->notification->cmdproc; - trans = msn_transaction_new("XFR", "%s", "SB"); - msn_transaction_add_cb(trans, "XFR", got_swboard, swboard); + trans = msn_transaction_new(cmdproc, "XFR", "%s", "SB"); + msn_transaction_add_cb(trans, "XFR", got_swboard); + msn_transaction_set_data(trans, swboard); + msn_transaction_set_error_cb(trans, xfr_error); msn_cmdproc_send_trans(cmdproc, trans); } diff -r ef7f9e69f03e -r ecf3ce2e2ab1 src/protocols/msn/switchboard.h --- a/src/protocols/msn/switchboard.h Sun Nov 21 06:16:23 2004 +0000 +++ b/src/protocols/msn/switchboard.h Sun Nov 21 17:48:09 2004 +0000 @@ -33,6 +33,17 @@ #include "servconn.h" +typedef enum +{ + MSN_SB_ERROR_NONE, + MSN_SB_ERROR_CAL, /* The user could not join (answer the call) */ + MSN_SB_ERROR_OFFLINE, /* The account is offline */ + MSN_SB_ERROR_USER_OFFLINE, /* The user to call is offline */ + MSN_SB_ERROR_CONNECTION, /* There was a connection error */ + MSN_SB_ERROR_UNKNOWN + +} MsnSBErrorType; + struct _MsnSwitchBoard { MsnSession *session; @@ -60,6 +71,8 @@ gboolean user_joined; GQueue *im_queue; + + int error; }; /** diff -r ef7f9e69f03e -r ecf3ce2e2ab1 src/protocols/msn/table.h --- a/src/protocols/msn/table.h Sun Nov 21 06:16:23 2004 +0000 +++ b/src/protocols/msn/table.h Sun Nov 21 17:48:09 2004 +0000 @@ -30,8 +30,6 @@ #include "transaction.h" #include "msg.h" -typedef void (*MsnErrorCb)(MsnCmdProc *cmdproc, MsnTransaction *trans, - int error); typedef void (*MsnMsgCb)(MsnCmdProc *cmdproc, MsnMessage *msg); struct _MsnTable diff -r ef7f9e69f03e -r ecf3ce2e2ab1 src/protocols/msn/transaction.c --- a/src/protocols/msn/transaction.c Sun Nov 21 06:16:23 2004 +0000 +++ b/src/protocols/msn/transaction.c Sun Nov 21 17:48:09 2004 +0000 @@ -25,7 +25,8 @@ #include "transaction.h" MsnTransaction * -msn_transaction_new(const char *command, const char *format, ...) +msn_transaction_new(MsnCmdProc *cmdproc, const char *command, + const char *format, ...) { MsnTransaction *trans; va_list arg; @@ -34,6 +35,7 @@ trans = g_new0(MsnTransaction, 1); + trans->cmdproc = cmdproc; trans->command = g_strdup(command); if (format != NULL) @@ -73,6 +75,9 @@ } #endif + if (trans->timer) + gaim_timeout_remove(trans->timer); + g_free(trans); } @@ -156,7 +161,7 @@ void msn_transaction_add_cb(MsnTransaction *trans, char *answer, - MsnTransCb cb, void *data) + MsnTransCb cb) { g_return_if_fail(trans != NULL); g_return_if_fail(answer != NULL); @@ -165,6 +170,38 @@ trans->callbacks = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL); g_hash_table_insert(trans->callbacks, answer, cb); +} - trans->data = data; +static gboolean +transaction_timeout(gpointer data) +{ + MsnTransaction *trans; + + trans = data; + g_return_val_if_fail(trans != NULL, FALSE); + + gaim_debug_info("msn", "%s %d %s\n", trans->command, trans->trId, trans->params); + + if (trans->timeout_cb != NULL) + trans->timeout_cb(trans->cmdproc, trans); + + return FALSE; } + +void +msn_transaction_set_timeout_cb(MsnTransaction *trans, MsnTimeoutCb cb) +{ + if (trans->timer) + { + gaim_debug_error("msn", "This shouldn't be happening\n"); + gaim_timeout_remove(trans->timer); + } + trans->timeout_cb = cb; + trans->timer = gaim_timeout_add(60000, transaction_timeout, trans); +} + +void +msn_transaction_set_error_cb(MsnTransaction *trans, MsnErrorCb cb) +{ + trans->error_cb = cb; +} diff -r ef7f9e69f03e -r ecf3ce2e2ab1 src/protocols/msn/transaction.h --- a/src/protocols/msn/transaction.h Sun Nov 21 06:16:23 2004 +0000 +++ b/src/protocols/msn/transaction.h Sun Nov 21 17:48:09 2004 +0000 @@ -30,28 +30,38 @@ #include "cmdproc.h" typedef void (*MsnTransCb)(MsnCmdProc *cmdproc, MsnCommand *cmd); +typedef void (*MsnTimeoutCb)(MsnCmdProc *cmdproc, MsnTransaction *trans); +typedef void (*MsnErrorCb)(MsnCmdProc *cmdproc, MsnTransaction *trans, + int error); /** - * A transaction. A command that will initiate the transaction. + * A transaction. A sending command that will initiate the transaction. */ struct _MsnTransaction { + MsnCmdProc *cmdproc; unsigned int trId; char *command; char *params; + int timer; + + void *data; /* The data to be used on the different callbacks */ GHashTable *callbacks; - void *data; + MsnErrorCb error_cb; + MsnTimeoutCb timeout_cb; char *payload; size_t payload_len; GQueue *queue; - MsnCommand *pendent_cmd; + MsnCommand *pendent_cmd; /* The command that is waiting for the result of + this transaction. */ }; -MsnTransaction *msn_transaction_new(const char *command, +MsnTransaction *msn_transaction_new(MsnCmdProc *cmdproc, + const char *command, const char *format, ...); void msn_transaction_destroy(MsnTransaction *trans); @@ -62,6 +72,8 @@ const char *payload, int payload_len); void msn_transaction_set_data(MsnTransaction *trans, void *data); void msn_transaction_add_cb(MsnTransaction *trans, char *answer, - MsnTransCb cb, void *data); + MsnTransCb cb); +void msn_transaction_set_error_cb(MsnTransaction *trans, MsnErrorCb cb); +void msn_transaction_set_timeout_cb(MsnTransaction *trans, MsnTimeoutCb cb); #endif /* _MSN_TRANSACTION_H */ diff -r ef7f9e69f03e -r ecf3ce2e2ab1 src/protocols/msn/userlist.c --- a/src/protocols/msn/userlist.c Sun Nov 21 06:16:23 2004 +0000 +++ b/src/protocols/msn/userlist.c Sun Nov 21 17:48:09 2004 +0000 @@ -73,7 +73,7 @@ got_new_entry(GaimConnection *gc, const char *passport, const char *friendly) { MsnPermitAdd *pa; - char *msg; + char *msg, *escaped; pa = g_new0(MsnPermitAdd, 1); pa->who = g_strdup(passport); @@ -81,11 +81,13 @@ if (friendly != NULL) { + escaped = g_markup_escape_text(friendly, -1); msg = g_strdup_printf( _("The user %s (%s) wants to add %s to his or her " "buddy list."), - passport, friendly, + passport, escaped, gaim_account_get_username(gc->account)); + g_free(escaped); } else { @@ -173,7 +175,7 @@ if (old_group_name) data->old_group_name = g_strdup(old_group_name); - trans = msn_transaction_new("ADG", "%s %d", + trans = msn_transaction_new(cmdproc, "ADG", "%s %d", gaim_url_encode(new_group_name), 0); diff -r ef7f9e69f03e -r ecf3ce2e2ab1 src/protocols/silc/silc.c --- a/src/protocols/silc/silc.c Sun Nov 21 06:16:23 2004 +0000 +++ b/src/protocols/silc/silc.c Sun Nov 21 17:48:09 2004 +0000 @@ -65,12 +65,16 @@ silcgaim_set_status(GaimAccount *account, GaimStatus *status) { GaimConnection *gc = gaim_account_get_connection(account); - SilcGaim sg = gc->proto_data; + SilcGaim sg; SilcUInt32 mode; SilcBuffer idp; unsigned char mb[4]; const char *state; + g_return_if_fail(gc != NULL); + + sg = gc->proto_data; + if ((status == NULL) || (sg->conn == NULL)) return;