# HG changeset patch # User Mark Doliner # Date 1150791469 0 # Node ID a9ff4499d9ce325da0830c90febf08d70b08f5bd # Parent f3d4a9902eadd039bac8bf4c22d037e7984208a5 [gaim-migrate @ 16295] Hopefully improve the typing notification code so it's a lot easier to understand. This also creates a distinction between the signals emitted when receiving GAIM_TYPED and GAIM_NOT_TYPING messages (by adding a gaim-typed signal). And the gaim-not-typing signal should work in all cases. Most of this is stuff I changed last week during work, thanks to Meebo committer: Tailor Script diff -r f3d4a9902ead -r a9ff4499d9ce plugins/perl/common/Conversation.xs --- a/plugins/perl/common/Conversation.xs Tue Jun 20 04:05:56 2006 +0000 +++ b/plugins/perl/common/Conversation.xs Tue Jun 20 08:17:49 2006 +0000 @@ -179,15 +179,15 @@ Gaim::Conversation::IM im void -gaim_conv_im_start_type_again_timeout(im) +gaim_conv_im_start_send_typed_timeout(im) Gaim::Conversation::IM im void -gaim_conv_im_stop_type_again_timeout(im) +gaim_conv_im_stop_send_typed_timeout(im) Gaim::Conversation::IM im guint -gaim_conv_im_get_type_again_timeout(im) +gaim_conv_im_get_send_typed_timeout(im) Gaim::Conversation::IM im void diff -r f3d4a9902ead -r a9ff4499d9ce plugins/perl/common/Server.xs --- a/plugins/perl/common/Server.xs Tue Jun 20 04:05:56 2006 +0000 +++ b/plugins/perl/common/Server.xs Tue Jun 20 08:17:49 2006 +0000 @@ -200,10 +200,10 @@ Gaim::MessageFlags flags int -serv_send_typing(con, a, b) +serv_send_typing(con, a, state) Gaim::Connection con const char * a - int b + Gaim::TypingState state void serv_set_buddyicon(gc, filename) diff -r f3d4a9902ead -r a9ff4499d9ce src/conversation.c --- a/src/conversation.c Tue Jun 20 04:05:56 2006 +0000 +++ b/src/conversation.c Tue Jun 20 08:17:49 2006 +0000 @@ -46,39 +46,44 @@ } static gboolean -reset_typing(gpointer data) +reset_typing_cb(gpointer data) { GaimConversation *c = (GaimConversation *)data; GaimConvIm *im; - if (!g_list_find(conversations, c)) - return FALSE; - im = GAIM_CONV_IM(c); gaim_conv_im_set_typing_state(im, GAIM_NOT_TYPING); gaim_conv_im_update_typing(im); gaim_conv_im_stop_typing_timeout(im); + gaim_signal_emit(gaim_conversations_get_handle(), + "buddy-typing-stopped", c); + return FALSE; } static gboolean -send_typed(gpointer data) +send_typed_cb(gpointer data) { GaimConversation *conv = (GaimConversation *)data; GaimConnection *gc; const char *name; g_return_val_if_fail(conv != NULL, FALSE); - + gc = gaim_conversation_get_gc(conv); name = gaim_conversation_get_name(conv); if (gc != NULL && name != NULL) { - gaim_conv_im_set_type_again(GAIM_CONV_IM(conv), TRUE); + /* We set this to 1 so that GAIM_TYPING will be sent + * if the Gaim user types anything else. + */ + gaim_conv_im_set_type_again(GAIM_CONV_IM(conv), 1); serv_send_typing(gc, name, GAIM_TYPED); + gaim_signal_emit(gaim_conversations_get_handle(), + "buddy-typed", conv); gaim_debug(GAIM_DEBUG_MISC, "conversation", "typed...\n"); } @@ -420,7 +425,7 @@ if (conv->type == GAIM_CONV_TYPE_IM) { gaim_conv_im_stop_typing_timeout(conv->u.im); - gaim_conv_im_stop_type_again_timeout(conv->u.im); + gaim_conv_im_stop_send_typed_timeout(conv->u.im); if (conv->u.im->icon != NULL) gaim_buddy_icon_unref(conv->u.im->icon); @@ -986,7 +991,12 @@ gaim_signal_emit(gaim_conversations_get_handle(), "buddy-typing", im->conv->account, im->conv->name); } - else + else if (state == GAIM_TYPED) + { + gaim_signal_emit(gaim_conversations_get_handle(), + "buddy-typed", im->conv->account, im->conv->name); + } + else if (state == GAIM_NOT_TYPING) { gaim_signal_emit(gaim_conversations_get_handle(), "buddy-typing-stopped", im->conv->account, im->conv->name); @@ -1016,7 +1026,7 @@ conv = gaim_conv_im_get_conversation(im); name = gaim_conversation_get_name(conv); - im->typing_timeout = gaim_timeout_add(timeout * 1000, reset_typing, conv); + im->typing_timeout = gaim_timeout_add(timeout * 1000, reset_typing_cb, conv); } void @@ -1040,11 +1050,14 @@ } void -gaim_conv_im_set_type_again(GaimConvIm *im, time_t val) +gaim_conv_im_set_type_again(GaimConvIm *im, unsigned int val) { g_return_if_fail(im != NULL); - im->type_again = val; + if (val == 0) + im->type_again = 0; + else + im->type_again = time(NULL) + val; } time_t @@ -1056,32 +1069,32 @@ } void -gaim_conv_im_start_type_again_timeout(GaimConvIm *im) +gaim_conv_im_start_send_typed_timeout(GaimConvIm *im) { g_return_if_fail(im != NULL); - im->type_again_timeout = gaim_timeout_add(SEND_TYPED_TIMEOUT, send_typed, + im->send_typed_timeout = gaim_timeout_add(SEND_TYPED_TIMEOUT, send_typed_cb, gaim_conv_im_get_conversation(im)); } void -gaim_conv_im_stop_type_again_timeout(GaimConvIm *im) +gaim_conv_im_stop_send_typed_timeout(GaimConvIm *im) { g_return_if_fail(im != NULL); - if (im->type_again_timeout == 0) + if (im->send_typed_timeout == 0) return; - gaim_timeout_remove(im->type_again_timeout); - im->type_again_timeout = 0; + gaim_timeout_remove(im->send_typed_timeout); + im->send_typed_timeout = 0; } guint -gaim_conv_im_get_type_again_timeout(const GaimConvIm *im) +gaim_conv_im_get_send_typed_timeout(const GaimConvIm *im) { g_return_val_if_fail(im != NULL, 0); - return im->type_again_timeout; + return im->send_typed_timeout; } void @@ -2090,6 +2103,12 @@ GAIM_SUBTYPE_ACCOUNT), gaim_value_new(GAIM_TYPE_STRING)); + gaim_signal_register(handle, "buddy-typed", + gaim_marshal_VOID__POINTER_POINTER, NULL, 2, + gaim_value_new(GAIM_TYPE_SUBTYPE, + GAIM_SUBTYPE_ACCOUNT), + gaim_value_new(GAIM_TYPE_STRING)); + gaim_signal_register(handle, "buddy-typing-stopped", gaim_marshal_VOID__POINTER_POINTER, NULL, 2, gaim_value_new(GAIM_TYPE_SUBTYPE, diff -r f3d4a9902ead -r a9ff4499d9ce src/conversation.h --- a/src/conversation.h Tue Jun 20 04:05:56 2006 +0000 +++ b/src/conversation.h Tue Jun 20 08:17:49 2006 +0000 @@ -186,7 +186,7 @@ GaimTypingState typing_state; /**< The current typing state. */ guint typing_timeout; /**< The typing timer handle. */ time_t type_again; /**< The type again time. */ - guint type_again_timeout; /**< The type again timer handle. */ + guint send_typed_timeout; /**< The type again timer handle. */ GaimBuddyIcon *icon; /**< The buddy icon. */ }; @@ -666,19 +666,25 @@ guint gaim_conv_im_get_typing_timeout(const GaimConvIm *im); /** - * Sets the IM's time until it should send another typing notification. + * Sets the quiet-time when no GAIM_TYPING messages will be sent. + * Few protocols need this (maybe only MSN). If the user is still + * typing after this quiet-period, then another GAIM_TYPING message + * will be sent. * * @param im The IM. - * @param val The time. + * @param val The number of seconds to wait before allowing another + * GAIM_TYPING message to be sent to the user. Or 0 to + * not send another GAIM_TYPING message. */ -void gaim_conv_im_set_type_again(GaimConvIm *im, time_t val); +void gaim_conv_im_set_type_again(GaimConvIm *im, unsigned int val); /** - * Returns the IM's time until it should send another typing notification. + * Returns the time after which another GAIM_TYPING message should be sent. * * @param im The IM. * - * @return The time. + * @return The time in seconds since the epoch. Or 0 if no additional + * GAIM_TYPING message should be sent. */ time_t gaim_conv_im_get_type_again(const GaimConvIm *im); @@ -687,14 +693,14 @@ * * @param im The IM. */ -void gaim_conv_im_start_type_again_timeout(GaimConvIm *im); +void gaim_conv_im_start_send_typed_timeout(GaimConvIm *im); /** * Stops the IM's type again timeout. * * @param im The IM. */ -void gaim_conv_im_stop_type_again_timeout(GaimConvIm *im); +void gaim_conv_im_stop_send_typed_timeout(GaimConvIm *im); /** * Returns the IM's type again timeout interval. @@ -703,7 +709,7 @@ * * @return The type again timeout interval. */ -guint gaim_conv_im_get_type_again_timeout(const GaimConvIm *im); +guint gaim_conv_im_get_send_typed_timeout(const GaimConvIm *im); /** * Updates the visual typing notification for an IM conversation. diff -r f3d4a9902ead -r a9ff4499d9ce src/gtkconv.c --- a/src/gtkconv.c Tue Jun 20 04:05:56 2006 +0000 +++ b/src/gtkconv.c Tue Jun 20 08:17:49 2006 +0000 @@ -2168,8 +2168,7 @@ if (gtk_text_iter_is_start(start_pos) && gtk_text_iter_is_end(end_pos)) { /* We deleted all the text, so turn off typing. */ - if (gaim_conv_im_get_type_again_timeout(im)) - gaim_conv_im_stop_type_again_timeout(im); + gaim_conv_im_stop_send_typed_timeout(im); serv_send_typing(gaim_conversation_get_gc(conv), gaim_conversation_get_name(conv), @@ -2913,22 +2912,18 @@ im = GAIM_CONV_IM(conv); - if (gaim_conv_im_get_type_again_timeout(im)) - gaim_conv_im_stop_type_again_timeout(im); - - gaim_conv_im_start_type_again_timeout(im); - + gaim_conv_im_stop_send_typed_timeout(im); + gaim_conv_im_start_send_typed_timeout(im); + + /* Check if we need to send another GAIM_TYPING message */ if (first || (gaim_conv_im_get_type_again(im) != 0 && - time(NULL) > gaim_conv_im_get_type_again(im))) { - - int timeout = serv_send_typing(gaim_conversation_get_gc(conv), - (char *)gaim_conversation_get_name(conv), - GAIM_TYPING); - - if (timeout) - gaim_conv_im_set_type_again(im, time(NULL) + timeout); - else - gaim_conv_im_set_type_again(im, 0); + time(NULL) > gaim_conv_im_get_type_again(im))) + { + unsigned int timeout; + timeout = serv_send_typing(gaim_conversation_get_gc(conv), + gaim_conversation_get_name(conv), + GAIM_TYPING); + gaim_conv_im_set_type_again(im, timeout); } } diff -r f3d4a9902ead -r a9ff4499d9ce src/gtkpounce.c --- a/src/gtkpounce.c Tue Jun 20 04:05:56 2006 +0000 +++ b/src/gtkpounce.c Tue Jun 20 08:17:49 2006 +0000 @@ -81,6 +81,7 @@ GtkWidget *idle; GtkWidget *idle_return; GtkWidget *typing; + GtkWidget *typed; GtkWidget *stop_typing; GtkWidget *message_recv; @@ -278,6 +279,9 @@ if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->typing))) events |= GAIM_POUNCE_TYPING; + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->typed))) + events |= GAIM_POUNCE_TYPED; + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->stop_typing))) events |= GAIM_POUNCE_TYPING_STOPPED; @@ -564,7 +568,7 @@ /* Create the "Pounce When Buddy..." frame. */ frame = gaim_gtk_make_frame(vbox2, _("Pounce When Buddy...")); - table = gtk_table_new(2, 4, FALSE); + table = gtk_table_new(5, 2, FALSE); gtk_container_add(GTK_CONTAINER(frame), table); gtk_table_set_col_spacings(GTK_TABLE(table), GAIM_HIG_BORDER); gtk_widget_show(table); @@ -583,28 +587,32 @@ gtk_check_button_new_with_mnemonic(_("Is no longer i_dle")); dialog->typing = gtk_check_button_new_with_mnemonic(_("Starts _typing")); + dialog->typed = + gtk_check_button_new_with_mnemonic(_("P_auses while typing")); dialog->stop_typing = gtk_check_button_new_with_mnemonic(_("Stops t_yping")); dialog->message_recv = gtk_check_button_new_with_mnemonic(_("Sends a _message")); - gtk_table_attach(GTK_TABLE(table), dialog->signon, 0, 1, 0, 1, + gtk_table_attach(GTK_TABLE(table), dialog->message_recv, 0, 1, 0, 1, GTK_FILL, 0, 0, 0); - gtk_table_attach(GTK_TABLE(table), dialog->signoff, 1, 2, 0, 1, + gtk_table_attach(GTK_TABLE(table), dialog->signon, 0, 1, 1, 2, GTK_FILL, 0, 0, 0); - gtk_table_attach(GTK_TABLE(table), dialog->away, 0, 1, 1, 2, + gtk_table_attach(GTK_TABLE(table), dialog->signoff, 0, 1, 2, 3, GTK_FILL, 0, 0, 0); - gtk_table_attach(GTK_TABLE(table), dialog->away_return, 1, 2, 1, 2, + gtk_table_attach(GTK_TABLE(table), dialog->away, 0, 1, 3, 4, + GTK_FILL, 0, 0, 0); + gtk_table_attach(GTK_TABLE(table), dialog->away_return, 0, 1, 4, 5, GTK_FILL, 0, 0, 0); - gtk_table_attach(GTK_TABLE(table), dialog->idle, 0, 1, 2, 3, + gtk_table_attach(GTK_TABLE(table), dialog->idle, 1, 2, 0, 1, GTK_FILL, 0, 0, 0); - gtk_table_attach(GTK_TABLE(table), dialog->idle_return, 1, 2, 2, 3, + gtk_table_attach(GTK_TABLE(table), dialog->idle_return, 1, 2, 1, 2, GTK_FILL, 0, 0, 0); - gtk_table_attach(GTK_TABLE(table), dialog->typing, 0, 1, 3, 4, + gtk_table_attach(GTK_TABLE(table), dialog->typing, 1, 2, 2, 3, GTK_FILL, 0, 0, 0); - gtk_table_attach(GTK_TABLE(table), dialog->stop_typing, 1, 2, 3, 4, + gtk_table_attach(GTK_TABLE(table), dialog->typed, 1, 2, 3, 4, GTK_FILL, 0, 0, 0); - gtk_table_attach(GTK_TABLE(table), dialog->message_recv, 0, 1, 4, 5, + gtk_table_attach(GTK_TABLE(table), dialog->stop_typing, 1, 2, 4, 5, GTK_FILL, 0, 0, 0); gtk_widget_show(dialog->signon); @@ -614,6 +622,7 @@ gtk_widget_show(dialog->idle); gtk_widget_show(dialog->idle_return); gtk_widget_show(dialog->typing); + gtk_widget_show(dialog->typed); gtk_widget_show(dialog->stop_typing); gtk_widget_show(dialog->message_recv); @@ -845,6 +854,8 @@ (events & GAIM_POUNCE_IDLE_RETURN)); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->typing), (events & GAIM_POUNCE_TYPING)); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->typed), + (events & GAIM_POUNCE_TYPED)); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->stop_typing), (events & GAIM_POUNCE_TYPING_STOPPED)); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->message_recv), @@ -1429,6 +1440,8 @@ tmp = g_strdup_printf( (events & GAIM_POUNCE_TYPING) ? _("%s has started typing to you (%s)") : + (events & GAIM_POUNCE_TYPED) ? + _("%s has paused while typing to you (%s)") : (events & GAIM_POUNCE_SIGNON) ? _("%s has signed on (%s)") : (events & GAIM_POUNCE_IDLE_RETURN) ? diff -r f3d4a9902ead -r a9ff4499d9ce src/pounce.c --- a/src/pounce.c Tue Jun 20 04:05:56 2006 +0000 +++ b/src/pounce.c Tue Jun 20 08:17:49 2006 +0000 @@ -206,6 +206,8 @@ add_event_to_xmlnode(child, "return-from-idle"); if (events & GAIM_POUNCE_TYPING) add_event_to_xmlnode(child, "start-typing"); + if (events & GAIM_POUNCE_TYPED) + add_event_to_xmlnode(child, "typed"); if (events & GAIM_POUNCE_TYPING_STOPPED) add_event_to_xmlnode(child, "stop-typing"); if (events & GAIM_POUNCE_MESSAGE_RECEIVED) @@ -411,7 +413,7 @@ else if (!strcmp(element_name, "option")) { if (!strcmp(data->option_type, "on-away")) data->options |= GAIM_POUNCE_OPTION_AWAY; - + g_free(data->option_type); data->option_type = NULL; } @@ -430,6 +432,8 @@ data->events |= GAIM_POUNCE_IDLE_RETURN; else if (!strcmp(data->event_type, "start-typing")) data->events |= GAIM_POUNCE_TYPING; + else if (!strcmp(data->event_type, "typed")) + data->events |= GAIM_POUNCE_TYPED; else if (!strcmp(data->event_type, "stop-typing")) data->events |= GAIM_POUNCE_TYPING_STOPPED; else if (!strcmp(data->event_type, "message-received")) @@ -1059,10 +1063,16 @@ conv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM, name, account); if (conv != NULL) { + GaimTypingState state; GaimPounceEvent event; - event = (gaim_conv_im_get_typing_state(GAIM_CONV_IM(conv)) == GAIM_TYPING - ? GAIM_POUNCE_TYPING : GAIM_POUNCE_TYPING_STOPPED); + state = gaim_conv_im_get_typing_state(GAIM_CONV_IM(conv)); + if (state == GAIM_TYPED) + event = GAIM_POUNCE_TYPED; + else if (state == GAIM_NOT_TYPING) + event = GAIM_POUNCE_TYPING_STOPPED; + else + event = GAIM_POUNCE_TYPING; gaim_pounce_execute(account, name, event); } @@ -1105,6 +1115,8 @@ gaim_signal_connect(conv_handle, "buddy-typing", handle, GAIM_CALLBACK(buddy_typing_cb), NULL); + gaim_signal_connect(conv_handle, "buddy-typed", + handle, GAIM_CALLBACK(buddy_typing_cb), NULL); gaim_signal_connect(conv_handle, "buddy-typing-stopped", handle, GAIM_CALLBACK(buddy_typing_cb), NULL); diff -r f3d4a9902ead -r a9ff4499d9ce src/pounce.h --- a/src/pounce.h Tue Jun 20 04:05:56 2006 +0000 +++ b/src/pounce.h Tue Jun 20 08:17:49 2006 +0000 @@ -35,16 +35,17 @@ */ typedef enum { - GAIM_POUNCE_NONE = 0x00, /**< No events. */ - GAIM_POUNCE_SIGNON = 0x01, /**< The buddy signed on. */ - GAIM_POUNCE_SIGNOFF = 0x02, /**< The buddy signed off. */ - GAIM_POUNCE_AWAY = 0x04, /**< The buddy went away. */ - GAIM_POUNCE_AWAY_RETURN = 0x08, /**< The buddy returned from away. */ - GAIM_POUNCE_IDLE = 0x10, /**< The buddy became idle. */ - GAIM_POUNCE_IDLE_RETURN = 0x20, /**< The buddy is no longer idle. */ - GAIM_POUNCE_TYPING = 0x40, /**< The buddy started typing. */ - GAIM_POUNCE_TYPING_STOPPED = 0x80, /**< The buddy stopped typing. */ - GAIM_POUNCE_MESSAGE_RECEIVED = 0x100 /**< The buddy sent a message */ + GAIM_POUNCE_NONE = 0x000, /**< No events. */ + GAIM_POUNCE_SIGNON = 0x001, /**< The buddy signed on. */ + GAIM_POUNCE_SIGNOFF = 0x002, /**< The buddy signed off. */ + GAIM_POUNCE_AWAY = 0x004, /**< The buddy went away. */ + GAIM_POUNCE_AWAY_RETURN = 0x008, /**< The buddy returned from away. */ + GAIM_POUNCE_IDLE = 0x010, /**< The buddy became idle. */ + GAIM_POUNCE_IDLE_RETURN = 0x020, /**< The buddy is no longer idle. */ + GAIM_POUNCE_TYPING = 0x040, /**< The buddy started typing. */ + GAIM_POUNCE_TYPED = 0x080, /**< The buddy has entered text. */ + GAIM_POUNCE_TYPING_STOPPED = 0x100, /**< The buddy stopped typing. */ + GAIM_POUNCE_MESSAGE_RECEIVED = 0x200 /**< The buddy sent a message */ } GaimPounceEvent; diff -r f3d4a9902ead -r a9ff4499d9ce src/protocols/jabber/message.c --- a/src/protocols/jabber/message.c Tue Jun 20 04:05:56 2006 +0000 +++ b/src/protocols/jabber/message.c Tue Jun 20 08:17:49 2006 +0000 @@ -589,7 +589,7 @@ return 1; } -int jabber_send_typing(GaimConnection *gc, const char *who, int typing) +unsigned int jabber_send_typing(GaimConnection *gc, const char *who, GaimTypingState state) { JabberMessage *jm; JabberBuddy *jb; @@ -611,9 +611,9 @@ jm->to = g_strdup(who); jm->id = jabber_get_next_id(jm->js); - if(GAIM_TYPING == typing) + if(GAIM_TYPING == state) jm->chat_state = JM_STATE_COMPOSING; - else if(GAIM_TYPED == typing) + else if(GAIM_TYPED == state) jm->chat_state = JM_STATE_PAUSED; else jm->chat_state = JM_STATE_ACTIVE; diff -r f3d4a9902ead -r a9ff4499d9ce src/protocols/jabber/message.h --- a/src/protocols/jabber/message.h Tue Jun 20 04:05:56 2006 +0000 +++ b/src/protocols/jabber/message.h Tue Jun 20 08:17:49 2006 +0000 @@ -71,7 +71,7 @@ GaimMessageFlags flags); int jabber_message_send_chat(GaimConnection *gc, int id, const char *message, GaimMessageFlags flags); -int jabber_send_typing(GaimConnection *gc, const char *who, int typing); +unsigned int jabber_send_typing(GaimConnection *gc, const char *who, GaimTypingState state); #endif /* _GAIM_JABBER_MESSAGE_H_ */ diff -r f3d4a9902ead -r a9ff4499d9ce src/protocols/msn/msn.c --- a/src/protocols/msn/msn.c Tue Jun 20 04:05:56 2006 +0000 +++ b/src/protocols/msn/msn.c Tue Jun 20 08:17:49 2006 +0000 @@ -836,8 +836,8 @@ return 1; } -static int -msn_send_typing(GaimConnection *gc, const char *who, int typing) +static unsigned int +msn_send_typing(GaimConnection *gc, const char *who, GaimTypingState state) { GaimAccount *account; MsnSession *session; @@ -847,7 +847,12 @@ account = gaim_connection_get_account(gc); session = gc->proto_data; - if (!typing) + /* + * TODO: I feel like this should be "if (state != GAIM_TYPING)" + * but this is how it was before, and I don't want to break + * anything. --KingAnt + */ + if (state == GAIM_NOT_TYPING) return 0; if (!g_ascii_strcasecmp(who, gaim_account_get_username(account))) diff -r f3d4a9902ead -r a9ff4499d9ce src/protocols/novell/novell.c --- a/src/protocols/novell/novell.c Tue Jun 20 04:05:56 2006 +0000 +++ b/src/protocols/novell/novell.c Tue Jun 20 08:17:49 2006 +0000 @@ -2303,8 +2303,8 @@ return 1; } -static int -novell_send_typing(GaimConnection * gc, const char *name, int typing) +static unsigned int +novell_send_typing(GaimConnection * gc, const char *name, GaimTypingState state) { NMConference *conf = NULL; NMUser *user; @@ -2312,11 +2312,11 @@ NMERR_T rc = NM_OK; if (gc == NULL || name == NULL) - return -1; + return 0; user = gc->proto_data; if (user == NULL) - return -1; + return 0; /* Need to get the DN for the buddy so we can look up the convo */ dn = nm_lookup_dn(user, name); @@ -2327,7 +2327,7 @@ if (conf) { rc = nm_send_typing(user, conf, - ((typing == GAIM_TYPING) ? TRUE : FALSE), NULL); + ((state == GAIM_TYPING) ? TRUE : FALSE), NULL); _check_for_disconnect(user, rc); } diff -r f3d4a9902ead -r a9ff4499d9ce src/protocols/oscar/oscar.c --- a/src/protocols/oscar/oscar.c Tue Jun 20 04:05:56 2006 +0000 +++ b/src/protocols/oscar/oscar.c Tue Jun 20 08:17:49 2006 +0000 @@ -3945,8 +3945,8 @@ flap_connection_send_keepalive(od, conn); } -static int -oscar_send_typing(GaimConnection *gc, const char *name, int typing) +static unsigned int +oscar_send_typing(GaimConnection *gc, const char *name, GaimTypingState state) { OscarData *od; PeerConnection *conn; @@ -3956,7 +3956,7 @@ if ((conn != NULL) && (conn->ready)) { - peer_odc_send_typing(conn, typing); + peer_odc_send_typing(conn, state); } else { /* Don't send if this turkey is in our deny list */ @@ -3965,9 +3965,9 @@ if (!list) { struct buddyinfo *bi = g_hash_table_lookup(od->buddyinfo, gaim_normalize(gc->account, name)); if (bi && bi->typingnot) { - if (typing == GAIM_TYPING) + if (state == GAIM_TYPING) aim_im_sendmtn(od, 0x0001, name, 0x0002); - else if (typing == GAIM_TYPED) + else if (state == GAIM_TYPED) aim_im_sendmtn(od, 0x0001, name, 0x0001); else aim_im_sendmtn(od, 0x0001, name, 0x0000); diff -r f3d4a9902ead -r a9ff4499d9ce src/protocols/sametime/sametime.c --- a/src/protocols/sametime/sametime.c Tue Jun 20 04:05:56 2006 +0000 +++ b/src/protocols/sametime/sametime.c Tue Jun 20 08:17:49 2006 +0000 @@ -3965,14 +3965,14 @@ } -static int mw_prpl_send_typing(GaimConnection *gc, const char *name, - int typing) { +static unsigned int mw_prpl_send_typing(GaimConnection *gc, const char *name, + GaimTypingState state) { struct mwGaimPluginData *pd; struct mwIdBlock who = { (char *) name, NULL }; struct mwConversation *conv; - gpointer t = GINT_TO_POINTER(!! typing); + gpointer t = GINT_TO_POINTER(!! state); g_return_val_if_fail(gc != NULL, 0); pd = gc->proto_data; @@ -3984,7 +3984,7 @@ if(mwConversation_isOpen(conv)) return ! mwConversation_send(conv, mwImSend_TYPING, t); - if(typing) { + if ((state == GAIM_TYPING) || (state == GAIM_TYPED)) { /* let's only open a channel for typing, not for not-typing. Otherwise two users in psychic mode will continually open conversations to each other, never able to get rid of them, as @@ -3996,6 +3996,11 @@ mwConversation_open(conv); } + /* + * TODO: This should probably be "0." When it's set to 1, the Gaim + * core will call serv_send_typing(gc, who, GAIM_TYPING) once + * every second until the Gaim user stops typing. --KingAnt + */ return 1; } diff -r f3d4a9902ead -r a9ff4499d9ce src/protocols/simple/simple.c --- a/src/protocols/simple/simple.c Tue Jun 20 04:05:56 2006 +0000 +++ b/src/protocols/simple/simple.c Tue Jun 20 08:17:49 2006 +0000 @@ -1053,7 +1053,7 @@ send_sip_response(sip->gc, msg, 200, "OK", NULL); } -static int simple_typing(GaimConnection *gc, const char *name, int typing) { +static unsigned int simple_typing(GaimConnection *gc, const char *name, GaimTypingState state) { struct simple_account_data *sip = gc->proto_data; gchar *xml = "\n" @@ -1065,16 +1065,22 @@ "60\n" ""; gchar *recv = g_strdup(name); - if(typing == GAIM_TYPING) { + if(state == GAIM_TYPING) { gchar *msg = g_strdup_printf(xml, "active"); simple_send_message(sip, recv, msg, "application/im-iscomposing+xml"); g_free(msg); - } else { + } else /* TODO: Only if (state == GAIM_TYPED) ? */ { gchar *msg = g_strdup_printf(xml, "idle"); simple_send_message(sip, recv, msg, "application/im-iscomposing+xml"); g_free(msg); } g_free(recv); + /* + * TODO: Is this right? It will cause the core to call + * serv_send_typing(gc, who, GAIM_TYPING) once every second + * until the user stops typing. If that's not desired, + * then return 0 instead. + */ return 1; } diff -r f3d4a9902ead -r a9ff4499d9ce src/protocols/yahoo/yahoo.c --- a/src/protocols/yahoo/yahoo.c Tue Jun 20 04:05:56 2006 +0000 +++ b/src/protocols/yahoo/yahoo.c Tue Jun 20 08:17:49 2006 +0000 @@ -3131,12 +3131,12 @@ return ret; } -static int yahoo_send_typing(GaimConnection *gc, const char *who, int typ) +static unsigned int yahoo_send_typing(GaimConnection *gc, const char *who, GaimTypingState state) { struct yahoo_data *yd = gc->proto_data; struct yahoo_packet *pkt = yahoo_packet_new(YAHOO_SERVICE_NOTIFY, YAHOO_STATUS_TYPING, 0); yahoo_packet_hash(pkt, "ssssss", 49, "TYPING", 1, gaim_connection_get_display_name(gc), - 14, " ", 13, typ == GAIM_TYPING ? "1" : "0", + 14, " ", 13, state == GAIM_TYPING ? "1" : "0", 5, who, 1002, "1"); yahoo_packet_send_and_free(pkt, yd); diff -r f3d4a9902ead -r a9ff4499d9ce src/protocols/zephyr/zephyr.c --- a/src/protocols/zephyr/zephyr.c Tue Jun 20 04:05:56 2006 +0000 +++ b/src/protocols/zephyr/zephyr.c Tue Jun 20 08:17:49 2006 +0000 @@ -2450,14 +2450,15 @@ return "zephyr"; } -static int zephyr_send_typing(GaimConnection *gc, const char *who, int typing) { +static unsigned int zephyr_send_typing(GaimConnection *gc, const char *who, GaimTypingState state) { gchar *recipient; zephyr_account *zephyr = gc->proto_data; if (use_tzc(zephyr)) return 0; - if (!typing) + if (state == GAIM_NOT_TYPING) return 0; + /* XXX We probably should care if this fails. Or maybe we don't want to */ if (!who) { gaim_debug_info("zephyr", "who is null\n"); @@ -2476,6 +2477,12 @@ gaim_debug_info("zephyr","about to send typing notification to %s\n",recipient); zephyr_send_message(zephyr,"MESSAGE","PERSONAL",recipient,"","","PING"); gaim_debug_info("zephyr","sent typing notification\n"); + + /* + * TODO: Is this correct? It means we will call + * serv_send_typing(gc, who, GAIM_TYPING) once every 15 seconds + * until the Gaim user stops typing. + */ return ZEPHYR_TYPING_SEND_TIMEOUT; } diff -r f3d4a9902ead -r a9ff4499d9ce src/prpl.h --- a/src/prpl.h Tue Jun 20 04:05:56 2006 +0000 +++ b/src/prpl.h Tue Jun 20 08:17:49 2006 +0000 @@ -224,7 +224,7 @@ GaimMessageFlags flags); void (*set_info)(GaimConnection *, const char *info); - int (*send_typing)(GaimConnection *, const char *name, int typing); + unsigned int (*send_typing)(GaimConnection *, const char *name, GaimTypingState state); void (*get_info)(GaimConnection *, const char *who); void (*set_status)(GaimAccount *account, GaimStatus *status); diff -r f3d4a9902ead -r a9ff4499d9ce src/server.c --- a/src/server.c Tue Jun 20 04:05:56 2006 +0000 +++ b/src/server.c Tue Jun 20 08:17:49 2006 +0000 @@ -38,18 +38,16 @@ #define SECS_BEFORE_RESENDING_AUTORESPONSE 600 #define SEX_BEFORE_RESENDING_AUTORESPONSE "Only after you're married" -/* This should return the elapsed time in seconds in which Gaim will not send - * typing notifications. - * if it returns zero, it will not send any more typing notifications - * typing is a flag - TRUE for typing, FALSE for stopped typing */ -int serv_send_typing(GaimConnection *g, const char *name, int typing) { +unsigned int +serv_send_typing(GaimConnection *gc, const char *name, GaimTypingState state) +{ GaimPluginProtocolInfo *prpl_info = NULL; - if (g != NULL && g->prpl != NULL) - prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(g->prpl); + if (gc != NULL && gc->prpl != NULL) + prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl); - if (g && prpl_info && prpl_info->send_typing) - return prpl_info->send_typing(g, name, typing); + if (prpl_info && prpl_info->send_typing) + return prpl_info->send_typing(gc, name, state); return 0; } @@ -150,8 +148,8 @@ lar->sent = time(NULL); } - if (conv && gaim_conv_im_get_type_again_timeout(GAIM_CONV_IM(conv))) - gaim_conv_im_stop_type_again_timeout(GAIM_CONV_IM(conv)); + if (conv && gaim_conv_im_get_send_typed_timeout(GAIM_CONV_IM(conv))) + gaim_conv_im_stop_send_typed_timeout(GAIM_CONV_IM(conv)); return val; } @@ -593,7 +591,7 @@ else { gaim_signal_emit(gaim_conversations_get_handle(), - "buddy-typing-stopped", gc->account, name); + "buddy-typed", gc->account, name); } } @@ -618,6 +616,11 @@ gaim_conv_im_set_typing_state(im, GAIM_NOT_TYPING); gaim_conv_im_update_typing(im); } + else + { + gaim_signal_emit(gaim_conversations_get_handle(), + "buddy-typing-stopped", gc->account, name); + } gaim_signal_emit(gaim_conversations_get_handle(), "buddy-typing-stopped", gc->account, name); diff -r f3d4a9902ead -r a9ff4499d9ce src/server.h --- a/src/server.h Tue Jun 20 04:05:56 2006 +0000 +++ b/src/server.h Tue Jun 20 08:17:49 2006 +0000 @@ -33,11 +33,27 @@ extern "C" { #endif +/** + * Send a typing message to a given user over a given connection. + * + * TODO: Could probably move this into the conversation API. + * + * @param typing One of GAIM_TYPING, GAIM_TYPED, or GAIM_NOT_TYPING. + * @return A quiet-period, specified in seconds, where Gaim will not + * send any additional typing notification messages. Most + * protocols should return 0, which means that no additional + * GAIM_TYPING messages need to be sent. If this is 5, for + * example, then Gaim will wait five seconds, and if the Gaim + * user is still typing then Gaim will send another GAIM_TYPING + * message. + */ +unsigned int serv_send_typing(GaimConnection *gc, const char *name, GaimTypingState state); + +void serv_move_buddy(GaimBuddy *, GaimGroup *, GaimGroup *); int serv_send_im(GaimConnection *, const char *, const char *, GaimMessageFlags flags); void serv_get_info(GaimConnection *, const char *); void serv_set_info(GaimConnection *, const char *); -int serv_send_typing(GaimConnection *, const char *, int); -void serv_move_buddy(GaimBuddy *, GaimGroup *, GaimGroup *); + void serv_add_permit(GaimConnection *, const char *); void serv_add_deny(GaimConnection *, const char *); void serv_rem_permit(GaimConnection *, const char *); @@ -51,12 +67,31 @@ int serv_chat_send(GaimConnection *, int, const char *, GaimMessageFlags flags); void serv_alias_buddy(GaimBuddy *); void serv_got_alias(GaimConnection *gc, const char *who, const char *alias); + +/** + * Receive a typing message from a remote user. Either GAIM_TYPING + * or GAIM_TYPED. If the user has stopped typing then use + * serv_got_typing_stopped instead. + * + * TODO: Could probably move this into the conversation API. + * + * @param timeout If this is a number greater than 0, then + * Gaim will wait this number of seconds and then + * set this buddy to the GAIM_NOT_TYPING state. This + * is used by protocols that send repeated typing messages + * while the user is composing the message. + */ void serv_got_typing(GaimConnection *gc, const char *name, int timeout, GaimTypingState state); -void serv_set_buddyicon(GaimConnection *gc, const char *filename); + +/** + * TODO: Could probably move this into the conversation API. + */ void serv_got_typing_stopped(GaimConnection *gc, const char *name); + void serv_got_im(GaimConnection *gc, const char *who, const char *msg, GaimMessageFlags flags, time_t mtime); +void serv_set_buddyicon(GaimConnection *gc, const char *filename); void serv_got_chat_invite(GaimConnection *gc, const char *name, const char *who, const char *message, GHashTable *data);