# HG changeset patch # User Ethan Blanton # Date 1188614211 0 # Node ID 0a055f917c85358689c54c4f7c0a83bd02fb66c3 # Parent f1740f23c8968286edbb75c2ef7b4cfc35bc7f89# Parent 11849a5c3951cfa9e457e2468d2ab550390436bb merge of '1247a733923713e275ecb722adf9abc726896c3f' and '26743756292ed5c798a0e97c6983736a95f5b0d2' diff -r f1740f23c896 -r 0a055f917c85 ChangeLog.API --- a/ChangeLog.API Sat Sep 01 01:49:38 2007 +0000 +++ b/ChangeLog.API Sat Sep 01 02:36:51 2007 +0000 @@ -17,6 +17,9 @@ Added: * pidgin_set_accessible_relations, sets up label-for and labelled-by ATK relations (broken out from pidgin_set_accessible_label) + * pidgin_conv_attach_to_conversation, to reattach the Pidgin UI to a + conversation + * conversation-hiding and conversation-displayed signals. Finch: Added: diff -r f1740f23c896 -r 0a055f917c85 doc/gtkconv-signals.dox --- a/doc/gtkconv-signals.dox Sat Sep 01 01:49:38 2007 +0000 +++ b/doc/gtkconv-signals.dox Sat Sep 01 02:36:51 2007 +0000 @@ -8,6 +8,8 @@ @signal displaying-chat-msg @signal displayed-chat-msg @signal conversation-switched + @signal conversation-hiding + @signal conversation-displayed @endsignals
@@ -116,5 +118,23 @@ @param new_conv The now active conversation. @endsignaldef + @signaldef conversation-hiding + @signalproto +void (*conversation_hiding)(PidginConversation *gtkconv); + @endsignalproto + @signaldesc + Emitted immediately before an existing conversation is hidden. + @param gtkconv The PidginConversation + @endsignaldef + + @signaldef conversation-displayed + @signalproto +void (*conversation_displayed)(PidginConversation *gtkconv); + @endsignalproto + @signaldesc + Emitted right after the Pidgin UI is reattached to a conversation. + @param gtkconv The PidginConversation + @endsignaldef + */ // vim: syntax=c tw=75 et diff -r f1740f23c896 -r 0a055f917c85 libpurple/certificate.c --- a/libpurple/certificate.c Sat Sep 01 01:49:38 2007 +0000 +++ b/libpurple/certificate.c Sat Sep 01 02:36:51 2007 +0000 @@ -1205,7 +1205,14 @@ /* Load up the cached certificate */ cached_crt = purple_certificate_pool_retrieve( tls_peers, vrq->subject_name); - g_assert(cached_crt); + if ( !cached_crt ) { + purple_debug_error("certificate/x509/tls_cached", + "Lookup failed on cached certificate!\n" + "It was here just a second ago. Forwarding " + "to cert_changed.\n"); + /* vrq now becomes the problem of cert_changed */ + x509_tls_cached_peer_cert_changed(vrq); + } /* Now get SHA1 sums for both and compare them */ /* TODO: This is not an elegant way to compare certs */ @@ -1338,7 +1345,14 @@ ca_crt = purple_certificate_pool_retrieve(ca, ca_id); g_free(ca_id); - g_assert(ca_crt); + if (!ca_crt) { + purple_debug_error("certificate/x509/tls_cached", + "Certificate authority disappeared out " + "underneath me!\n"); + purple_certificate_verify_complete(vrq, + PURPLE_CERTIFICATE_INVALID); + return; + } /* Check the signature */ if ( !purple_certificate_signed_by(end_crt, ca_crt) ) { @@ -1375,9 +1389,11 @@ "tls_peers"); if (tls_peers) { - g_assert(purple_certificate_pool_store(tls_peers, - vrq->subject_name, - peer_crt) ); + if (!purple_certificate_pool_store(tls_peers,vrq->subject_name, + peer_crt) ) { + purple_debug_error("certificate/x509/tls_cached", + "FAILED to cache peer certificate\n"); + } } else { purple_debug_error("certificate/x509/tls_cached", "Unable to locate tls_peers certificate " @@ -1790,7 +1806,6 @@ GByteArray *sha_bin; gchar *cn; time_t activation, expiration; - /* Length of these buffers is dictated by 'man ctime_r' */ gchar *activ_str, *expir_str; gchar *secondary; @@ -1807,7 +1822,11 @@ /* Get the certificate times */ /* TODO: Check the times against localtime */ /* TODO: errorcheck? */ - g_assert(purple_certificate_get_times(crt, &activation, &expiration)); + if (!purple_certificate_get_times(crt, &activation, &expiration)) { + purple_debug_error("certificate", + "Failed to get certificate times!\n"); + activation = expiration = 0; + } activ_str = g_strdup(ctime(&activation)); expir_str = g_strdup(ctime(&expiration)); diff -r f1740f23c896 -r 0a055f917c85 libpurple/example/nullclient.c --- a/libpurple/example/nullclient.c Sat Sep 01 01:49:38 2007 +0000 +++ b/libpurple/example/nullclient.c Sat Sep 01 02:36:51 2007 +0000 @@ -197,7 +197,7 @@ purple_util_set_user_dir(CUSTOM_USER_DIRECTORY); /* We do not want any debugging for now to keep the noise to a minimum. */ - purple_debug_set_enabled(TRUE); + purple_debug_set_enabled(FALSE); /* Set the core-uiops, which is used to * - initialize the ui specific preferences. @@ -257,24 +257,6 @@ PURPLE_CALLBACK(signed_on), NULL); } - - - -void signedOn( PurpleConnection *gc, gpointer dummy ) { - - - if( gc ) { - - PurpleAccount* a = purple_connection_get_account( gc ); - - if( a ) { - - purple_presence_set_idle( purple_account_get_presence( a ), TRUE, time( NULL ) ); - } - } -} - - int main() { GList *iter; @@ -300,26 +282,30 @@ names = g_list_append(names, info->id); } } + printf("Select the protocol [0-%d]: ", i-1); + fgets(name, sizeof(name), stdin); + sscanf(name, "%d", &num); + prpl = g_list_nth_data(names, num); + + printf("Username: "); + fgets(name, sizeof(name), stdin); + name[strlen(name) - 1] = 0; /* strip the \n at the end */ /* Create the account */ - account = purple_account_new("msimprpl@xyzzy.cjb.net", "prpl-myspace" ); - purple_account_set_password(account, "4224jc" ); + account = purple_account_new(name, prpl); + + /* Get the password for the account */ + password = getpass("Password: "); + purple_account_set_password(account, password); /* It's necessary to enable the account first. */ purple_account_set_enabled(account, UI_ID, TRUE); -#if 0 - static int handle; - purple_signal_connect( purple_connections_get_handle(), - "signed-on", &handle, - PURPLE_CALLBACK( signedOn ), - NULL ); - /* Now, to connect the account(s), create a status and activate it. */ - purple_savedstatus_activate( purple_savedstatus_get_default() ); + status = purple_savedstatus_new(NULL, PURPLE_STATUS_AVAILABLE); + purple_savedstatus_activate(status); connect_to_signals_for_demonstration_purposes_only(); -#endif g_main_loop_run(loop); diff -r f1740f23c896 -r 0a055f917c85 libpurple/plugins/ssl/ssl-gnutls.c --- a/libpurple/plugins/ssl/ssl-gnutls.c Sat Sep 01 01:49:38 2007 +0000 +++ b/libpurple/plugins/ssl/ssl-gnutls.c Sat Sep 01 02:36:51 2007 +0000 @@ -60,7 +60,7 @@ (gnutls_realloc_function) g_realloc, /* realloc */ (gnutls_free_function) g_free /* free */ ); - + gnutls_global_init(); gnutls_certificate_allocate_credentials(&xcred); @@ -73,7 +73,7 @@ static gboolean ssl_gnutls_init(void) { - return TRUE; + return TRUE; } static void @@ -130,17 +130,18 @@ purple_ssl_close(gsc); } else { - purple_debug_info("gnutls", "Handshake complete\n"); - - /* TODO: Remove all this debugging babble */ /* Now we are cooking with gas! */ PurpleSslOps *ops = purple_ssl_get_ops(); GList * peers = ops->get_peer_certificates(gsc); - + PurpleCertificateScheme *x509 = purple_certificate_find_scheme("x509"); GList * l; + + /* TODO: Remove all this debugging babble */ + purple_debug_info("gnutls", "Handshake complete\n"); + for (l=peers; l; l = l->next) { PurpleCertificate *crt = l->data; GByteArray *z = @@ -155,72 +156,71 @@ /* Kill the cert! */ x509->destroy_certificate(crt); - + g_free(fpr); g_byte_array_free(z, TRUE); } g_list_free(peers); - + { - const gnutls_datum_t *cert_list; - unsigned int cert_list_size = 0; - gnutls_session_t session=gnutls_data->session; - - cert_list = - gnutls_certificate_get_peers(session, &cert_list_size); - - purple_debug_info("gnutls", - "Peer provided %d certs\n", - cert_list_size); - int i; - for (i=0; isession; + int i; + + cert_list = + gnutls_certificate_get_peers(session, &cert_list_size); + + purple_debug_info("gnutls", + "Peer provided %d certs\n", + cert_list_size); + for (i=0; isession) == GNUTLS_CRT_X509, NULL); @@ -426,12 +426,14 @@ static void x509_crtdata_delref(x509_crtdata_t *cd) { - g_assert(cd->refcount > 0); - (cd->refcount)--; + if (cd->refcount < 0) + g_critical("Refcount of x509_crtdata_t is %d, which is less " + "than zero!\n", cd->refcount); + /* If the refcount reaches zero, kill the structure */ - if (cd->refcount == 0) { + if (cd->refcount <= 0) { purple_debug_info("gnutls/x509", "Freeing unused cert data at %p\n", cd); @@ -466,11 +468,11 @@ certdat = g_new0(x509_crtdata_t, 1); gnutls_x509_crt_init(&(certdat->crt)); certdat->refcount = 0; - + /* Perform the actual certificate parse */ /* Yes, certdat->crt should be passed as-is */ gnutls_x509_crt_import(certdat->crt, &dt, mode); - + /* Allocate the certificate and load it with data */ crt = g_new0(PurpleCertificate, 1); crt->scheme = &x509_gnutls; @@ -495,7 +497,7 @@ purple_debug_info("gnutls", "Attempting to load X.509 certificate from %s\n", filename); - + /* Next, we'll simply yank the entire contents of the file into memory */ /* TODO: Should I worry about very large files here? */ @@ -506,7 +508,7 @@ NULL /* No error checking for now */ ), NULL); - + /* Load the datum struct */ dt.data = (unsigned char *) buf; dt.size = buf_sz; @@ -514,7 +516,7 @@ /* Perform the conversion */ crt = x509_import_from_datum(dt, GNUTLS_X509_FMT_PEM); // files should be in PEM format - + /* Cleanup */ g_free(buf); @@ -571,7 +573,6 @@ success = purple_util_write_data_to_file_absolute(filename, out_buf, out_size); - g_free(out_buf); g_return_val_if_fail(success, FALSE); return success; @@ -596,10 +597,10 @@ } /** Frees a Certificate * - * Destroys a Certificate's internal data structures and frees the pointer - * given. - * @param crt Certificate instance to be destroyed. It WILL NOT be destroyed - * if it is not of the correct CertificateScheme. Can be NULL + * Destroys a Certificate's internal data structures and frees the pointer + * given. + * @param crt Certificate instance to be destroyed. It WILL NOT be destroyed + * if it is not of the correct CertificateScheme. Can be NULL * */ static void @@ -622,7 +623,7 @@ /* Use the reference counting system to free (or not) the underlying data */ x509_crtdata_delref((x509_crtdata_t *)crt->data); - + /* Kill the structure itself */ g_free(crt); } @@ -643,7 +644,7 @@ gnutls_x509_crt_t issuer_dat; unsigned int verify; /* used to store result from GnuTLS verifier */ int ret; - + g_return_val_if_fail(crt, FALSE); g_return_val_if_fail(issuer, FALSE); @@ -685,7 +686,7 @@ /* The issuer is not correct, or there were errors */ return FALSE; } - + /* Now, check the signature */ /* The second argument is a ptr to an array of "trusted" issuer certs, but we're only using one trusted one */ @@ -696,7 +697,7 @@ current standard) */ GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT, &verify); - + if (ret != 0) { purple_debug_error("gnutls/x509", "Attempted certificate verification caused a GnuTLS error code %d. I will just say the signature is bad, but you should look into this.\n", ret); @@ -713,7 +714,7 @@ issuer_id, crt_id); g_free(crt_id); g_free(issuer_id); - + return FALSE; } /* if (ret, etc.) */ @@ -742,7 +743,7 @@ /* This shouldn't happen */ g_return_val_if_fail(tmpsz == hashlen, NULL); - + /* Okay, now create and fill hash array */ hash = g_byte_array_new(); g_byte_array_append(hash, hashbuf, hashlen); @@ -776,7 +777,7 @@ g_free(dn); return NULL; } - + return dn; } @@ -807,7 +808,7 @@ g_free(dn); return NULL; } - + return dn; } @@ -848,7 +849,6 @@ return NULL; } - return cn; } @@ -893,7 +893,7 @@ if (*activation == errval || *expiration == errval) { return FALSE; } - + return TRUE; } diff -r f1740f23c896 -r 0a055f917c85 libpurple/protocols/yahoo/yahoo.c --- a/libpurple/protocols/yahoo/yahoo.c Sat Sep 01 01:49:38 2007 +0000 +++ b/libpurple/protocols/yahoo/yahoo.c Sat Sep 01 02:36:51 2007 +0000 @@ -3030,6 +3030,11 @@ if (yd->ycht) ycht_connection_close(yd->ycht); + g_free(yd->pending_chat_room); + g_free(yd->pending_chat_id); + g_free(yd->pending_chat_topic); + g_free(yd->pending_chat_goto); + g_free(yd); gc->proto_data = NULL; } diff -r f1740f23c896 -r 0a055f917c85 libpurple/protocols/yahoo/yahoo.h --- a/libpurple/protocols/yahoo/yahoo.h Sat Sep 01 01:49:38 2007 +0000 +++ b/libpurple/protocols/yahoo/yahoo.h Sat Sep 01 02:36:51 2007 +0000 @@ -130,6 +130,10 @@ gboolean chat_online; gboolean in_chat; char *chat_name; + char *pending_chat_room; + char *pending_chat_id; + char *pending_chat_topic; + char *pending_chat_goto; char *auth; gsize auth_written; char *cookie_y; diff -r f1740f23c896 -r 0a055f917c85 libpurple/protocols/yahoo/yahoochat.c --- a/libpurple/protocols/yahoo/yahoochat.c Sat Sep 01 01:49:38 2007 +0000 +++ b/libpurple/protocols/yahoo/yahoochat.c Sat Sep 01 02:36:51 2007 +0000 @@ -55,16 +55,24 @@ { struct yahoo_data *yd = gc->proto_data; struct yahoo_packet *pkt; + const char *rll; if (yd->wm) { ycht_connection_open(gc); return; } + rll = purple_account_get_string(purple_connection_get_account(gc), + "room_list_locale", YAHOO_ROOMLIST_LOCALE); + pkt = yahoo_packet_new(YAHOO_SERVICE_CHATONLINE, YAHOO_STATUS_AVAILABLE,0); - yahoo_packet_hash(pkt, "ssss", 1, purple_connection_get_display_name(gc), - 109, purple_connection_get_display_name(gc), 6, "abcde", - 135, "ym8.1.0.415"); + yahoo_packet_hash(pkt, "sssss", + 109, purple_connection_get_display_name(gc), + 1, purple_connection_get_display_name(gc), + 6, "abcde", + /* I'm not sure this is the correct way to set this. */ + 98, rll, + 135, "ym8.1.0.415"); yahoo_packet_send_and_free(pkt, yd); } @@ -125,6 +133,7 @@ case 1: /* us, but we already know who we are */ break; case 57: + g_free(room); room = yahoo_string_decode(gc, pair->value, FALSE); break; case 50: /* inviter */ @@ -136,6 +145,7 @@ g_string_append_printf(members, "%s\n", pair->value); break; case 58: + g_free(msg); msg = yahoo_string_decode(gc, pair->value, FALSE); break; case 13: /* ? */ @@ -145,6 +155,17 @@ if (!room) { g_string_free(members, TRUE); + g_free(msg); + return; + } + + if (!yahoo_privacy_check(gc, who) || + (purple_account_get_bool(purple_connection_get_account(gc), "ignore_invites", FALSE))) { + purple_debug_info("yahoo", + "Invite to conference %s from %s has been dropped.\n", room, who); + g_free(room); + g_free(msg); + g_string_free(members, TRUE); return; } @@ -153,19 +174,9 @@ if (msg) g_hash_table_replace(components, g_strdup("topic"), msg); g_hash_table_replace(components, g_strdup("type"), g_strdup("Conference")); - if (members) { - g_hash_table_replace(components, g_strdup("members"), g_strdup(members->str)); - } - if (!yahoo_privacy_check(gc, who) || - (purple_account_get_bool(purple_connection_get_account(gc), "ignore_invites", FALSE))) { - purple_debug_info("yahoo", - "Invite to conference %s from %s has been dropped.\n", room, who); - g_string_free(members, TRUE); - return; - } + g_hash_table_replace(components, g_strdup("members"), g_string_free(members, FALSE)); serv_got_chat_invite(gc, room, who, msg, components); - g_string_free(members, TRUE); } void yahoo_process_conference_decline(PurpleConnection *gc, struct yahoo_packet *pkt) @@ -180,20 +191,21 @@ switch (pair->key) { case 57: + g_free(room); room = yahoo_string_decode(gc, pair->value, FALSE); break; case 54: who = pair->value; break; case 14: + g_free(msg); msg = yahoo_string_decode(gc, pair->value, FALSE); break; } } if (!yahoo_privacy_check(gc, who)) { g_free(room); - if (msg != NULL) - g_free(msg); + g_free(msg); return; } @@ -209,8 +221,7 @@ } g_free(room); - if (msg) - g_free(msg); + g_free(msg); } } @@ -226,6 +237,7 @@ switch (pair->key) { case 57: + g_free(room); room = yahoo_string_decode(gc, pair->value, FALSE); break; case 53: @@ -254,6 +266,7 @@ switch (pair->key) { case 57: + g_free(room); room = yahoo_string_decode(gc, pair->value, FALSE); break; case 56: @@ -276,7 +289,6 @@ char *room = NULL; char *who = NULL; char *msg = NULL; - char *msg2; int utf8 = 0; PurpleConversation *c; @@ -285,6 +297,7 @@ switch (pair->key) { case 57: + g_free(room); room = yahoo_string_decode(gc, pair->value, FALSE); break; case 3: @@ -299,28 +312,82 @@ } } - if (room && who && msg) { - msg2 = yahoo_string_decode(gc, msg, utf8); - c = yahoo_find_conference(gc, room); - if (!c) - return; - msg = yahoo_codes_to_html(msg2); - serv_got_chat_in(gc, purple_conv_chat_get_id(PURPLE_CONV_CHAT(c)), who, 0, msg, time(NULL)); - g_free(msg); - g_free(msg2); + if (room && who && msg) { + char *msg2; + + c = yahoo_find_conference(gc, room); + if (!c) { + g_free(room); + return; } - if (room) - g_free(room); + + msg2 = yahoo_string_decode(gc, msg, utf8); + msg = yahoo_codes_to_html(msg2); + serv_got_chat_in(gc, purple_conv_chat_get_id(PURPLE_CONV_CHAT(c)), who, 0, msg, time(NULL)); + g_free(msg); + g_free(msg2); + } + + g_free(room); } +static void yahoo_chat_join(PurpleConnection *gc, const char *dn, const char *room, const char *topic, const char *id) +{ + struct yahoo_data *yd = gc->proto_data; + struct yahoo_packet *pkt; + char *room2; + gboolean utf8 = TRUE; + + if (yd->wm) { + g_return_if_fail(yd->ycht != NULL); + ycht_chat_join(yd->ycht, room); + return; + } + + /* apparently room names are always utf8, or else always not utf8, + * so we don't have to actually pass the flag in the packet. Or something. */ + room2 = yahoo_string_encode(gc, room, &utf8); + + pkt = yahoo_packet_new(YAHOO_SERVICE_CHATJOIN, YAHOO_STATUS_AVAILABLE, 0); + yahoo_packet_hash(pkt, "ssss", + 1, purple_connection_get_display_name(gc), + 104, room2, + 62, "2", + 129, id ? id : "0"); + yahoo_packet_send_and_free(pkt, yd); + g_free(room2); +} /* this is a confirmation of yahoo_chat_online(); */ void yahoo_process_chat_online(PurpleConnection *gc, struct yahoo_packet *pkt) { struct yahoo_data *yd = (struct yahoo_data *) gc->proto_data; - if (pkt->status == 1) + if (pkt->status == 1) { yd->chat_online = 1; + + /* We need to goto a user in chat */ + if (yd->pending_chat_goto) { + struct yahoo_packet *pkt = yahoo_packet_new(YAHOO_SERVICE_CHATGOTO, YAHOO_STATUS_AVAILABLE, 0); + yahoo_packet_hash(pkt, "sss", + 109, yd->pending_chat_goto, + 1, purple_connection_get_display_name(gc), + 62, "2"); + yahoo_packet_send_and_free(pkt, yd); + } else if (yd->pending_chat_room) { + yahoo_chat_join(gc, purple_connection_get_display_name(gc), yd->pending_chat_room, + yd->pending_chat_topic, yd->pending_chat_id); + } + + g_free(yd->pending_chat_room); + yd->pending_chat_room = NULL; + g_free(yd->pending_chat_id); + yd->pending_chat_id = NULL; + g_free(yd->pending_chat_topic); + yd->pending_chat_topic = NULL; + g_free(yd->pending_chat_goto); + yd->pending_chat_goto = NULL; + } } /* this is basicly the opposite of chat_online */ @@ -340,6 +407,14 @@ if (pkt->status == 1) { yd->chat_online = 0; + g_free(yd->pending_chat_room); + yd->pending_chat_room = NULL; + g_free(yd->pending_chat_id); + yd->pending_chat_id = NULL; + g_free(yd->pending_chat_topic); + yd->pending_chat_topic = NULL; + g_free(yd->pending_chat_goto); + yd->pending_chat_goto = NULL; if (yd->in_chat) yahoo_c_leave(gc, YAHOO_CHAT_ID); } @@ -384,9 +459,11 @@ switch (pair->key) { case 104: + g_free(room); room = yahoo_string_decode(gc, pair->value, TRUE); break; case 105: + g_free(topic); topic = yahoo_string_decode(gc, pair->value, TRUE); break; case 128: @@ -445,8 +522,11 @@ purple_conversation_set_name(c, room); c = serv_got_joined_chat(gc, YAHOO_CHAT_ID, room); - if (topic) + if (topic) { purple_conv_chat_set_topic(PURPLE_CONV_CHAT(c), NULL, topic); + /* Also print the topic to the backlog so that the captcha link is clickable */ + purple_conv_chat_write(PURPLE_CONV_CHAT(c), "", topic, PURPLE_MESSAGE_SYSTEM, time(NULL)); + } yd->in_chat = 1; yd->chat_name = g_strdup(room); purple_conv_chat_add_users(PURPLE_CONV_CHAT(c), members, NULL, flags, FALSE); @@ -456,14 +536,22 @@ g_free(tmpmsg); } else { c = serv_got_joined_chat(gc, YAHOO_CHAT_ID, room); - if (topic) + if (topic) { purple_conv_chat_set_topic(PURPLE_CONV_CHAT(c), NULL, topic); + /* Also print the topic to the backlog so that the captcha link is clickable */ + purple_conv_chat_write(PURPLE_CONV_CHAT(c), "", topic, PURPLE_MESSAGE_SYSTEM, time(NULL)); + } yd->in_chat = 1; yd->chat_name = g_strdup(room); purple_conv_chat_add_users(PURPLE_CONV_CHAT(c), members, NULL, flags, FALSE); } g_list_free(flags); } else if (c) { + if (topic) { + const char *cur_topic = purple_conv_chat_get_topic(PURPLE_CONV_CHAT(c)); + if (cur_topic == NULL || strcmp(cur_topic, topic) != 0) + purple_conv_chat_set_topic(PURPLE_CONV_CHAT(c), NULL, topic); + } yahoo_chat_add_users(PURPLE_CONV_CHAT(c), members); } @@ -497,8 +585,10 @@ for (l = pkt->hash; l; l = l->next) { struct yahoo_pair *pair = l->data; - if (pair->key == 104) + if (pair->key == 104) { + g_free(room); room = yahoo_string_decode(gc, pair->value, TRUE); + } if (pair->key == 109) who = pair->value; } @@ -529,6 +619,7 @@ utf8 = strtol(pair->value, NULL, 10); break; case 104: + g_free(room); room = yahoo_string_decode(gc, pair->value, TRUE); break; case 109: @@ -583,6 +674,7 @@ switch (pair->key) { case 104: + g_free(room); room = yahoo_string_decode(gc, pair->value, TRUE); break; case 129: /* room id? */ @@ -590,6 +682,7 @@ case 126: /* ??? */ break; case 117: + g_free(msg); msg = yahoo_string_decode(gc, pair->value, FALSE); break; case 119: @@ -603,24 +696,21 @@ if (room && who) { GHashTable *components; + if (!yahoo_privacy_check(gc, who) || + (purple_account_get_bool(purple_connection_get_account(gc), "ignore_invites", FALSE))) { + purple_debug_info("yahoo", "Invite to room %s from %s has been dropped.\n", room, who); + g_free(room); + g_free(msg); + return; + } + components = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); g_hash_table_replace(components, g_strdup("room"), g_strdup(room)); - if (!yahoo_privacy_check(gc, who) || - (purple_account_get_bool(purple_connection_get_account(gc), "ignore_invites", FALSE))) { - purple_debug_info("yahoo", - "Invite to room %s from %s has been dropped.\n", room, who); - if (room != NULL) - g_free(room); - if (msg != NULL) - g_free(msg); - return; - } serv_got_chat_invite(gc, room, who, msg, components); } - if (room) - g_free(room); - if (msg) - g_free(msg); + + g_free(room); + g_free(msg); } void yahoo_process_chat_goto(PurpleConnection *gc, struct yahoo_packet *pkt) @@ -783,6 +873,14 @@ yahoo_packet_send_and_free(pkt, yd); yd->chat_online = 0; + g_free(yd->pending_chat_room); + yd->pending_chat_room = NULL; + g_free(yd->pending_chat_id); + yd->pending_chat_id = NULL; + g_free(yd->pending_chat_topic); + yd->pending_chat_topic = NULL; + g_free(yd->pending_chat_goto); + yd->pending_chat_goto = NULL; g_free(eroom); } @@ -829,29 +927,6 @@ return 0; } -static void yahoo_chat_join(PurpleConnection *gc, const char *dn, const char *room, const char *topic) -{ - struct yahoo_data *yd = gc->proto_data; - struct yahoo_packet *pkt; - char *room2; - gboolean utf8 = TRUE; - - if (yd->wm) { - g_return_if_fail(yd->ycht != NULL); - ycht_chat_join(yd->ycht, room); - return; - } - - /* apparently room names are always utf8, or else always not utf8, - * so we don't have to actually pass the flag in the packet. Or something. */ - room2 = yahoo_string_encode(gc, room, &utf8); - - pkt = yahoo_packet_new(YAHOO_SERVICE_CHATJOIN, YAHOO_STATUS_AVAILABLE, 0); - yahoo_packet_hash(pkt, "ssss", 1, purple_connection_get_display_name(gc), - 62, "2", 104, room2, 129, "0"); - yahoo_packet_send_and_free(pkt, yd); - g_free(room2); -} static void yahoo_chat_invite(PurpleConnection *gc, const char *dn, const char *buddy, const char *room, const char *msg) @@ -892,8 +967,18 @@ return; } - if (!yd->chat_online) + if (!yd->chat_online) { yahoo_chat_online(gc); + g_free(yd->pending_chat_room); + yd->pending_chat_room = NULL; + g_free(yd->pending_chat_id); + yd->pending_chat_id = NULL; + g_free(yd->pending_chat_topic); + yd->pending_chat_topic = NULL; + g_free(yd->pending_chat_goto); + yd->pending_chat_goto = g_strdup(name); + return; + } pkt = yahoo_packet_new(YAHOO_SERVICE_CHATGOTO, YAHOO_STATUS_AVAILABLE, 0); yahoo_packet_hash(pkt, "sss", 109, name, 1, purple_connection_get_display_name(gc), 62, "2"); @@ -988,8 +1073,7 @@ void yahoo_c_join(PurpleConnection *gc, GHashTable *data) { struct yahoo_data *yd; - char *room, *topic, *members, *type; - int id; + char *room, *topic, *type; PurpleConversation *c; yd = (struct yahoo_data *) gc->proto_data; @@ -1004,9 +1088,9 @@ if (!topic) topic = ""; - members = g_hash_table_lookup(data, "members"); - if ((type = g_hash_table_lookup(data, "type")) && !strcmp(type, "Conference")) { + int id; + const char *members = g_hash_table_lookup(data, "members"); id = yd->conf_id++; c = serv_got_joined_chat(gc, id, room); yd->confs = g_slist_prepend(yd->confs, c); @@ -1014,13 +1098,27 @@ yahoo_conf_join(yd, c, purple_connection_get_display_name(gc), room, topic, members); return; } else { - if (yd->in_chat) + const char *id; + /*if (yd->in_chat) yahoo_chat_leave(gc, room, purple_connection_get_display_name(gc), - FALSE); - if (!yd->chat_online) + FALSE);*/ + + id = g_hash_table_lookup(data, "id"); + + if (!yd->chat_online) { yahoo_chat_online(gc); - yahoo_chat_join(gc, purple_connection_get_display_name(gc), room, topic); + g_free(yd->pending_chat_room); + yd->pending_chat_room = g_strdup(room); + g_free(yd->pending_chat_id); + yd->pending_chat_id = g_strdup(id); + g_free(yd->pending_chat_topic); + yd->pending_chat_topic = g_strdup(topic); + g_free(yd->pending_chat_goto); + yd->pending_chat_goto = NULL; + } else { + yahoo_chat_join(gc, purple_connection_get_display_name(gc), room, topic, id); + } return; } } @@ -1148,16 +1246,13 @@ for (i = 0; anames[i]; i++) { if (!strcmp(anames[i], "id")) { - if (s->room.id) - g_free(s->room.id); + g_free(s->room.id); s->room.id = g_strdup(avalues[i]); } else if (!strcmp(anames[i], "name")) { - if (s->room.name) - g_free(s->room.name); + g_free(s->room.name); s->room.name = g_strdup(avalues[i]); } else if (!strcmp(anames[i], "topic")) { - if (s->room.topic) - g_free(s->room.topic); + g_free(s->room.topic); s->room.topic = g_strdup(avalues[i]); } else if (!strcmp(anames[i], "type")) { if (!strcmp("yahoo", avalues[i])) diff -r f1740f23c896 -r 0a055f917c85 pidgin/gtkblist.c --- a/pidgin/gtkblist.c Sat Sep 01 01:49:38 2007 +0000 +++ b/pidgin/gtkblist.c Sat Sep 01 02:36:51 2007 +0000 @@ -3209,6 +3209,7 @@ { GdkPixbuf *ret; const char *protoname = NULL; + const char *icon = NULL; struct _pidgin_blist_node *gtknode = node->ui_data; struct _pidgin_blist_node *gtkbuddynode = NULL; PurpleBuddy *buddy = NULL; @@ -3257,62 +3258,54 @@ purple_buddy_get_name(buddy), purple_buddy_get_account(buddy)); PurplePresence *p; + gboolean trans; + if(conv != NULL) { PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv); - if(gtkconv != NULL && pidgin_conv_is_hidden(gtkconv) && size == PIDGIN_STATUS_ICON_SMALL) { + if((gtkconv == NULL || pidgin_conv_is_hidden(gtkconv)) && size == PIDGIN_STATUS_ICON_SMALL) { return gtk_widget_render_icon (GTK_WIDGET(gtkblist->treeview), PIDGIN_STOCK_STATUS_MESSAGE, icon_size, "GtkTreeView"); } } + p = purple_buddy_get_presence(buddy); + trans = (purple_presence_is_idle(p) && size == PIDGIN_STATUS_ICON_SMALL); if (PURPLE_BUDDY_IS_ONLINE(buddy) && gtkbuddynode && gtkbuddynode->recent_signonoff) - ret = gtk_widget_render_icon (GTK_WIDGET(gtkblist->treeview), PIDGIN_STOCK_STATUS_LOGIN, - icon_size, "GtkTreeView"); + icon = PIDGIN_STOCK_STATUS_LOGIN; else if (gtkbuddynode && gtkbuddynode->recent_signonoff) - ret = gtk_widget_render_icon (GTK_WIDGET(gtkblist->treeview), PIDGIN_STOCK_STATUS_LOGOUT, - icon_size, "GtkTreeView"); + icon = PIDGIN_STOCK_STATUS_LOGOUT; else if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_UNAVAILABLE)) - if (purple_presence_is_idle(p) && size == PIDGIN_STATUS_ICON_SMALL) - ret = gtk_widget_render_icon (GTK_WIDGET(gtkblist->treeview), PIDGIN_STOCK_STATUS_BUSY_I, - icon_size, "GtkTreeView"); + if (trans) + icon = PIDGIN_STOCK_STATUS_BUSY_I; else - ret = gtk_widget_render_icon (GTK_WIDGET(gtkblist->treeview), PIDGIN_STOCK_STATUS_BUSY, - icon_size, "GtkTreeView"); + icon = PIDGIN_STOCK_STATUS_BUSY; else if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_AWAY)) - if (purple_presence_is_idle(p) && size == PIDGIN_STATUS_ICON_SMALL) - ret = gtk_widget_render_icon (GTK_WIDGET(gtkblist->treeview), PIDGIN_STOCK_STATUS_AWAY_I, - icon_size, "GtkTreeView"); + if (trans) + icon = PIDGIN_STOCK_STATUS_AWAY_I; else - ret = gtk_widget_render_icon (GTK_WIDGET(gtkblist->treeview), PIDGIN_STOCK_STATUS_AWAY, - icon_size, "GtkTreeView"); + icon = PIDGIN_STOCK_STATUS_AWAY; else if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_EXTENDED_AWAY)) - if (purple_presence_is_idle(p) && size == PIDGIN_STATUS_ICON_SMALL) - ret = gtk_widget_render_icon (GTK_WIDGET(gtkblist->treeview), PIDGIN_STOCK_STATUS_XA_I, - icon_size, "GtkTreeView"); + if (trans) + icon = PIDGIN_STOCK_STATUS_XA_I; else - ret = gtk_widget_render_icon (GTK_WIDGET(gtkblist->treeview), PIDGIN_STOCK_STATUS_XA, - icon_size, "GtkTreeView"); + icon = PIDGIN_STOCK_STATUS_XA; else if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_OFFLINE)) - ret = gtk_widget_render_icon (GTK_WIDGET(gtkblist->treeview), PIDGIN_STOCK_STATUS_OFFLINE, - icon_size, "GtkTreeView"); - else if (purple_presence_is_idle(p) && size == PIDGIN_STATUS_ICON_SMALL) - ret = gtk_widget_render_icon (GTK_WIDGET(gtkblist->treeview), PIDGIN_STOCK_STATUS_AVAILABLE_I, - icon_size, "GtkTreeView"); + icon = PIDGIN_STOCK_STATUS_OFFLINE; + else if (trans) + icon = PIDGIN_STOCK_STATUS_AVAILABLE_I; else if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_INVISIBLE)) - ret = gtk_widget_render_icon(GTK_WIDGET(gtkblist->treeview), PIDGIN_STOCK_STATUS_INVISIBLE, - icon_size, "GtkTreeView"); + icon = PIDGIN_STOCK_STATUS_INVISIBLE; else - ret = gtk_widget_render_icon(GTK_WIDGET(gtkblist->treeview), PIDGIN_STOCK_STATUS_AVAILABLE, - icon_size, "GtkTreeView"); + icon = PIDGIN_STOCK_STATUS_AVAILABLE; } else if (chat) { - ret = gtk_widget_render_icon (GTK_WIDGET(gtkblist->treeview), PIDGIN_STOCK_STATUS_CHAT, - icon_size, "GtkTreeView"); + icon = PIDGIN_STOCK_STATUS_CHAT; } else { - ret = gtk_widget_render_icon (GTK_WIDGET(gtkblist->treeview), PIDGIN_STOCK_STATUS_PERSON, - icon_size, "GtkTreeView"); - } - + icon = PIDGIN_STOCK_STATUS_PERSON; + } + + ret = gtk_widget_render_icon (GTK_WIDGET(gtkblist->treeview), icon, + icon_size, "GtkTreeView"); return ret; } @@ -3335,7 +3328,7 @@ if(conv != NULL) { gtkconv = PIDGIN_CONVERSATION(conv); - if(gtkconv != NULL && pidgin_conv_is_hidden(gtkconv)) { + if(gtkconv == NULL || pidgin_conv_is_hidden(gtkconv)) { hidden_conv = TRUE; } } @@ -5213,6 +5206,10 @@ GdkPixbuf *emblem; char *mark; gboolean showicons = purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/show_buddy_icons"); + const char *name = purple_chat_get_name(chat); + PurpleConversation *conv = + purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, name, chat->account); + gboolean hidden = (conv && !PIDGIN_CONVERSATION(conv)); if(!insert_node(list, node, &iter)) return; @@ -5228,15 +5225,20 @@ avatar = NULL; mark = g_markup_escape_text(purple_chat_get_name(chat), -1); + if (hidden) { + char *bold = g_strdup_printf("%s", mark); + g_free(mark); + mark = bold; + } gtk_tree_store_set(gtkblist->treemodel, &iter, STATUS_ICON_COLUMN, status, STATUS_ICON_VISIBLE_COLUMN, TRUE, BUDDY_ICON_COLUMN, avatar ? avatar : gtkblist->empty_avatar, BUDDY_ICON_VISIBLE_COLUMN, purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/show_buddy_icons"), - EMBLEM_COLUMN, emblem, + EMBLEM_COLUMN, emblem, EMBLEM_VISIBLE_COLUMN, emblem != NULL, - PROTOCOL_ICON_COLUMN, pidgin_create_prpl_icon(chat->account, PIDGIN_PRPL_ICON_SMALL), + PROTOCOL_ICON_COLUMN, pidgin_create_prpl_icon(chat->account, PIDGIN_PRPL_ICON_SMALL), PROTOCOL_ICON_VISIBLE_COLUMN, purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/show_protocol_icons"), NAME_COLUMN, mark, GROUP_EXPANDER_VISIBLE_COLUMN, FALSE, diff -r f1740f23c896 -r 0a055f917c85 pidgin/gtkconv.c --- a/pidgin/gtkconv.c Sat Sep 01 01:49:38 2007 +0000 +++ b/pidgin/gtkconv.c Sat Sep 01 02:36:51 2007 +0000 @@ -1303,7 +1303,10 @@ menu_hide_conv_cb(gpointer data, guint action, GtkWidget *widget) { PidginWindow *win = data; + PidginConversation *gtkconv = pidgin_conv_window_get_active_gtkconv(win); PurpleConversation *conv = pidgin_conv_window_get_active_conversation(win); + purple_signal_emit(pidgin_conversations_get_handle(), + "conversation-hiding", gtkconv); purple_conversation_set_ui_ops(conv, NULL); } @@ -5622,6 +5625,7 @@ account, name, displaying, conv, flags); g_free(displaying); } + static void pidgin_conv_chat_add_users(PurpleConversation *conv, GList *cbuddies, gboolean new_arrivals) { @@ -7206,6 +7210,8 @@ if (gtkconv->attach.current) return TRUE; + purple_signal_emit(pidgin_conversations_get_handle(), + "conversation-displayed", gtkconv); g_source_remove(gtkconv->attach.timer); gtkconv->attach.timer = 0; return FALSE; @@ -7228,12 +7234,15 @@ list = g_list_last(list); gtkconv->attach.current = list; gtkconv->attach.timer = g_idle_add(add_message_history_to_gtkconv, gtkconv); - } - - /* XXX: If this is a chat: - * - populate the userlist - * - set the topic - */ + } else { + purple_signal_emit(pidgin_conversations_get_handle(), + "conversation-displayed", gtkconv); + } + + if (conv->type == PURPLE_CONV_TYPE_CHAT) { + pidgin_conv_update_fields(conv, PIDGIN_CONV_TOPIC); + pidgin_conv_chat_add_users(conv, PURPLE_CONV_CHAT(conv)->in_room, TRUE); + } return TRUE; } @@ -7415,6 +7424,16 @@ purple_value_new(PURPLE_TYPE_SUBTYPE, PURPLE_SUBTYPE_CONVERSATION)); + purple_signal_register(handle, "conversation-hiding", + purple_marshal_VOID__POINTER_POINTER, NULL, 1, + purple_value_new(PURPLE_TYPE_BOXED, + "PidginConversation *")); + + purple_signal_register(handle, "conversation-displayed", + purple_marshal_VOID__POINTER_POINTER, NULL, 1, + purple_value_new(PURPLE_TYPE_BOXED, + "PidginConversation *")); + /********************************************************************** * Register commands **********************************************************************/ diff -r f1740f23c896 -r 0a055f917c85 pidgin/gtkconv.h --- a/pidgin/gtkconv.h Sat Sep 01 01:49:38 2007 +0000 +++ b/pidgin/gtkconv.h Sat Sep 01 02:36:51 2007 +0000 @@ -245,6 +245,13 @@ */ void pidgin_conv_present_conversation(PurpleConversation *conv); +/** + * Reattach Pidgin UI to a conversation. + * + * @param conv The conversation. + * + * @return Wheter Pidgin UI was successfully attached. + */ gboolean pidgin_conv_attach_to_conversation(PurpleConversation *conv); PidginWindow *pidgin_conv_get_window(PidginConversation *gtkconv); diff -r f1740f23c896 -r 0a055f917c85 pidgin/gtkimhtmltoolbar.c --- a/pidgin/gtkimhtmltoolbar.c Sat Sep 01 01:49:38 2007 +0000 +++ b/pidgin/gtkimhtmltoolbar.c Sat Sep 01 02:36:51 2007 +0000 @@ -786,6 +786,7 @@ gtk_widget_set_sensitive(GTK_WIDGET(toolbar->bold), buttons & GTK_IMHTML_BOLD); gtk_widget_set_sensitive(GTK_WIDGET(toolbar->italic), buttons & GTK_IMHTML_ITALIC); gtk_widget_set_sensitive(GTK_WIDGET(toolbar->underline), buttons & GTK_IMHTML_UNDERLINE); + gtk_widget_set_sensitive(GTK_WIDGET(toolbar->strikethrough), buttons & GTK_IMHTML_STRIKE); gtk_widget_set_sensitive(GTK_WIDGET(toolbar->larger_size), buttons & GTK_IMHTML_GROW); gtk_widget_set_sensitive(GTK_WIDGET(toolbar->smaller_size), buttons & GTK_IMHTML_SHRINK); @@ -798,6 +799,7 @@ (buttons & GTK_IMHTML_BOLD || buttons & GTK_IMHTML_ITALIC || buttons & GTK_IMHTML_UNDERLINE || + buttons & GTK_IMHTML_STRIKE || buttons & GTK_IMHTML_GROW || buttons & GTK_IMHTML_SHRINK || buttons & GTK_IMHTML_FACE || @@ -831,7 +833,7 @@ static void update_buttons(GtkIMHtmlToolbar *toolbar) { - gboolean bold, italic, underline; + gboolean bold, italic, underline, strike; char *tmp; char *tmp2; GtkLabel *label = g_object_get_data(G_OBJECT(toolbar), "font_label"); @@ -840,6 +842,7 @@ gtk_imhtml_get_current_format(GTK_IMHTML(toolbar->imhtml), &bold, &italic, &underline); + strike = GTK_IMHTML(toolbar->imhtml)->edit.strike; if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(toolbar->bold)) != bold) toggle_button_set_active_block(GTK_TOGGLE_BUTTON(toolbar->bold), bold, @@ -847,10 +850,12 @@ if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(toolbar->italic)) != italic) toggle_button_set_active_block(GTK_TOGGLE_BUTTON(toolbar->italic), italic, toolbar); - if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(toolbar->underline)) != underline) toggle_button_set_active_block(GTK_TOGGLE_BUTTON(toolbar->underline), underline, toolbar); + if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(toolbar->strikethrough)) != strike) + toggle_button_set_active_block(GTK_TOGGLE_BUTTON(toolbar->strikethrough), + strike, toolbar); /* These buttons aren't ever "active". */ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toolbar->smaller_size), FALSE); @@ -874,6 +879,12 @@ gtk_label_set_markup_with_mnemonic(label, markup); g_free(markup); } + if (strike) { + gchar *markup = g_strdup_printf("%s", + gtk_label_get_label(label)); + gtk_label_set_markup_with_mnemonic(label, markup); + g_free(markup); + } tmp = gtk_imhtml_get_current_fontface(GTK_IMHTML(toolbar->imhtml)); toggle_button_set_active_block(GTK_TOGGLE_BUTTON(toolbar->font), diff -r f1740f23c896 -r 0a055f917c85 pidgin/gtksourceundomanager.c --- a/pidgin/gtksourceundomanager.c Sat Sep 01 01:49:38 2007 +0000 +++ b/pidgin/gtksourceundomanager.c Sat Sep 01 02:36:51 2007 +0000 @@ -677,8 +677,6 @@ if (um->priv->running_not_undoable_actions > 0) return; - g_return_if_fail (strlen (text) >= (guint)length); - undo_action.action_type = GTK_SOURCE_UNDO_ACTION_INSERT; undo_action.action.insert.pos = gtk_text_iter_get_offset (pos); @@ -774,7 +772,7 @@ *action = *undo_action; if (action->action_type == GTK_SOURCE_UNDO_ACTION_INSERT) - action->action.insert.text = g_strdup (undo_action->action.insert.text); + action->action.insert.text = g_strndup (undo_action->action.insert.text, undo_action->action.insert.length); else if (action->action_type == GTK_SOURCE_UNDO_ACTION_DELETE) action->action.delete.text = g_strdup (undo_action->action.delete.text); else diff -r f1740f23c896 -r 0a055f917c85 pidgin/plugins/notify.c --- a/pidgin/plugins/notify.c Sat Sep 01 01:49:38 2007 +0000 +++ b/pidgin/plugins/notify.c Sat Sep 01 02:36:51 2007 +0000 @@ -167,7 +167,7 @@ gboolean has_focus; PidginWindow *purplewin = NULL; - if (conv == NULL) + if (conv == NULL || PIDGIN_CONVERSATION(conv) == NULL) return 0; /* We want to remove the notifications, but not reset the counter */ @@ -224,6 +224,8 @@ PidginWindow *purplewin = NULL; g_return_if_fail(conv != NULL); + if (PIDGIN_CONVERSATION(conv) == NULL) + return; purplewin = PIDGIN_CONVERSATION(conv)->win; active_conv = pidgin_conv_window_get_active_conversation(purplewin); @@ -417,10 +419,14 @@ deleting_conv(PurpleConversation *conv) { PidginWindow *purplewin = NULL; + PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv); + + if (gtkconv == NULL) + return; detach_signals(conv); - purplewin = PIDGIN_CONVERSATION(conv)->win; + purplewin = gtkconv->win; handle_urgent(purplewin, FALSE); purple_conversation_set_data(conv, "notify-message-count", GINT_TO_POINTER(0));