# HG changeset patch # User Elliott Sales de Andrade # Date 1330235509 0 # Node ID 3c420b12a03480d63ffaa066a45fcd039366b5a9 # Parent c1daad7121f89a2b70a70df09ad12402f459f99b# Parent 194f66d5089a56bbf669a8d160d934bfc3593998 propagate from branch 'im.pidgin.pidgin' (head 78f2facd08a9b906e2ab5491bb828763c80ea46a) to branch 'im.pidgin.cpw.qulogic.gtk3' (head ec42ed4101a842f3dc81c13f1942996951d08422) diff -r 194f66d5089a -r 3c420b12a034 ChangeLog --- a/ChangeLog Thu Feb 23 09:00:17 2012 +0000 +++ b/ChangeLog Sun Feb 26 05:51:49 2012 +0000 @@ -24,8 +24,6 @@ MSN: * Fix file transfer with older Mac MSN clients. * Support file transfers up to ~9 EiB. - * Support new protocol version MSNP18. (#14753) - * Fix messages to offline contacts. (#14302) MXit: * Remove all reference to Hidden Number. @@ -70,6 +68,8 @@ MSN: * Fix possible crashes caused by not validating incoming messages as UTF-8. (Thijs Alkemade) (#14884) + * Support new protocol version MSNP18. (#14753) + * Fix messages to offline contacts. (#14302) Windows-Specific Changes: * Fix compilation of the Bonjour protocol plugin. (#14802) diff -r 194f66d5089a -r 3c420b12a034 ChangeLog.API --- a/ChangeLog.API Thu Feb 23 09:00:17 2012 +0000 +++ b/ChangeLog.API Sun Feb 26 05:51:49 2012 +0000 @@ -8,6 +8,8 @@ * purple_account_get_ui_data * purple_account_set_ui_data * purple_account_register_completed + * purple_certificate_get_der_data + * purple_certificate_get_display_string * purple_conv_chat_cb_get_alias * purple_conv_chat_cb_get_flags * purple_conv_chat_cb_is_buddy @@ -32,6 +34,9 @@ * purple_menu_action_set_data * purple_menu_action_set_callback * purple_menu_action_set_children + * purple_request_certificate + * purple_request_field_certificate_new + * purple_request_field_certificate_get_value * purple_request_field_get_tooltip * purple_request_field_group_get_fields_list * purple_request_field_set_tooltip @@ -159,6 +164,8 @@ * purple_buddy_icons_set_custom_icon * purple_certificate_check_signature_chain_with_failing. Use purple_certificate_check_signature_chain, instead + * purple_certificate_display_x509. Use purple_request_certificate, + instead * purple_connection_error_reason * purple_connection_new * purple_connection_new_unregister diff -r 194f66d5089a -r 3c420b12a034 configure.ac diff -r 194f66d5089a -r 3c420b12a034 finch/gntrequest.c --- a/finch/gntrequest.c Thu Feb 23 09:00:17 2012 +0000 +++ b/finch/gntrequest.c Sun Feb 26 05:51:49 2012 +0000 @@ -571,6 +571,22 @@ return combo; } +static GntWidget* +create_certificate_field(PurpleRequestField *field) +{ + GntWidget *w; + PurpleCertificate *cert; + char *str; + + cert = purple_request_field_certificate_get_value(field); + str = purple_certificate_get_display_string(cert); + w = gnt_label_new(str); + + g_free(str); + + return w; +} + static void * finch_request_fields(const char *title, const char *primary, const char *secondary, PurpleRequestFields *allfields, @@ -650,6 +666,10 @@ accountlist = create_account_field(field); purple_request_field_set_ui_data(field, accountlist); } + else if (type == PURPLE_REQUEST_FIELD_CERTIFICATE) + { + purple_request_field_set_ui_data(field, create_certificate_field(field)); + } else { purple_request_field_set_ui_data(field, gnt_label_new_with_format(_("Not implemented yet."), diff -r 194f66d5089a -r 3c420b12a034 libpurple/certificate.c --- a/libpurple/certificate.c Thu Feb 23 09:00:17 2012 +0000 +++ b/libpurple/certificate.c Sun Feb 26 05:51:49 2012 +0000 @@ -518,6 +518,24 @@ } gchar * +purple_certificate_get_display_string(PurpleCertificate *crt) +{ + PurpleCertificateScheme *scheme; + gchar *str; + + g_return_val_if_fail(crt, NULL); + g_return_val_if_fail(crt->scheme, NULL); + + scheme = crt->scheme; + + g_return_val_if_fail(scheme->get_display_string, NULL); + + str = (scheme->get_display_string)(crt); + + return str; +} + +gchar * purple_certificate_pool_mkpath(PurpleCertificatePool *pool, const gchar *id) { gchar *path; @@ -662,77 +680,62 @@ /****************************************************************************/ static void -x509_singleuse_verify_cb (PurpleCertificateVerificationRequest *vrq, gint id) +x509_singleuse_verify_accept_cb(PurpleCertificateVerificationRequest *vrq) { g_return_if_fail(vrq); purple_debug_info("certificate/x509_singleuse", - "VRQ on cert from %s gave %d\n", - vrq->subject_name, id); + "VRQ on cert from %s accepted\n", + vrq->subject_name); + + purple_certificate_verify_complete(vrq, PURPLE_CERTIFICATE_VALID); +} - /* Signal what happened back to the caller */ - if (1 == id) { - /* Accepted! */ - purple_certificate_verify_complete(vrq, - PURPLE_CERTIFICATE_VALID); - } else { - /* Not accepted */ - purple_certificate_verify_complete(vrq, - PURPLE_CERTIFICATE_INVALID); +static void +x509_singleuse_verify_reject_cb(PurpleCertificateVerificationRequest *vrq) +{ + g_return_if_fail(vrq); - } + purple_debug_info("certificate/x509_singleuse", + "VRQ on cert from %s rejected\n", + vrq->subject_name); + + purple_certificate_verify_complete(vrq, PURPLE_CERTIFICATE_INVALID); } static void x509_singleuse_start_verify (PurpleCertificateVerificationRequest *vrq) { - gchar *sha_asc; - GByteArray *sha_bin; gchar *cn; const gchar *cn_match; gchar *primary, *secondary; - PurpleCertificate *crt = (PurpleCertificate *) vrq->cert_chain->data; + PurpleCertificate *crt = (PurpleCertificate *)vrq->cert_chain->data; - /* Pull out the SHA1 checksum */ - sha_bin = purple_certificate_get_fingerprint_sha1(crt); - /* Now decode it for display */ - sha_asc = purple_base16_encode_chunked(sha_bin->data, - sha_bin->len); - - /* Get the cert Common Name */ cn = purple_certificate_get_subject_name(crt); - /* Determine whether the name matches */ if (purple_certificate_check_subject_name(crt, vrq->subject_name)) { - cn_match = ""; + cn_match = _("(MATCH)"); } else { cn_match = _("(DOES NOT MATCH)"); } - /* Make messages */ primary = g_strdup_printf(_("%s has presented the following certificate for just-this-once use:"), vrq->subject_name); - secondary = g_strdup_printf(_("Common name: %s %s\nFingerprint (SHA1): %s"), cn, cn_match, sha_asc); + secondary = g_strdup_printf(_("Common name: %s %s"), cn, cn_match); /* Make a semi-pretty display */ - purple_request_accept_cancel( + purple_request_certificate( vrq->cb_data, /* TODO: Find what the handle ought to be */ _("Single-use Certificate Verification"), primary, secondary, - 0, /* Accept by default */ - NULL, /* No account */ - NULL, /* No other user */ - NULL, /* No associated conversation */ - vrq, - x509_singleuse_verify_cb, - x509_singleuse_verify_cb ); + crt, + _("Accept"), G_CALLBACK(x509_singleuse_verify_accept_cb), + _("Reject"), G_CALLBACK(x509_singleuse_verify_reject_cb), + vrq); - /* Cleanup */ g_free(cn); g_free(primary); g_free(secondary); - g_free(sha_asc); - g_byte_array_free(sha_bin, TRUE); } static void @@ -1289,102 +1292,34 @@ static PurpleCertificateVerifier x509_tls_cached; -/* The following is several hacks piled together and needs to be fixed. - * It exists because show_cert (see its comments) needs the original reason - * given to user_auth in order to rebuild the dialog. - */ -/* TODO: This will cause a ua_ctx to become memleaked if the request(s) get - closed by handle or otherwise abnormally. */ -typedef struct { - PurpleCertificateVerificationRequest *vrq; - gchar *reason; -} x509_tls_cached_ua_ctx; - -static x509_tls_cached_ua_ctx * -x509_tls_cached_ua_ctx_new(PurpleCertificateVerificationRequest *vrq, - const gchar *reason) +static void +x509_tls_cached_user_auth_accept_cb(PurpleCertificateVerificationRequest *vrq) { - x509_tls_cached_ua_ctx *c; + PurpleCertificatePool *tls_peers; + gchar *cache_id; - c = g_new0(x509_tls_cached_ua_ctx, 1); - c->vrq = vrq; - c->reason = g_strdup(reason); + g_return_if_fail(vrq); + + tls_peers = purple_certificate_find_pool("x509", "tls_peers"); - return c; -} - + cache_id = vrq->subject_name; + purple_debug_info("certificate/x509/tls_cached", + "User ACCEPTED cert\nCaching first in chain for future use as %s...\n", + cache_id); -static void -x509_tls_cached_ua_ctx_free(x509_tls_cached_ua_ctx *c) -{ - g_return_if_fail(c); - g_free(c->reason); - g_free(c); + purple_certificate_pool_store(tls_peers, cache_id, vrq->cert_chain->data); + + purple_certificate_verify_complete(vrq, PURPLE_CERTIFICATE_VALID); } static void -x509_tls_cached_user_auth(PurpleCertificateVerificationRequest *vrq, - const gchar *reason); - -static void -x509_tls_cached_show_cert(x509_tls_cached_ua_ctx *c, gint id) +x509_tls_cached_user_auth_reject_cb(PurpleCertificateVerificationRequest *vrq) { - PurpleCertificate *disp_crt = c->vrq->cert_chain->data; - - /* Since clicking a button closes the request, show it again */ - x509_tls_cached_user_auth(c->vrq, c->reason); - - /* Show the certificate AFTER re-opening the dialog so that this - appears above the other */ - purple_certificate_display_x509(disp_crt); - - x509_tls_cached_ua_ctx_free(c); -} - -static void -x509_tls_cached_user_auth_cb (x509_tls_cached_ua_ctx *c, gint id) -{ - PurpleCertificateVerificationRequest *vrq; - PurpleCertificatePool *tls_peers; - - g_return_if_fail(c); - g_return_if_fail(c->vrq); - - vrq = c->vrq; - - x509_tls_cached_ua_ctx_free(c); + g_return_if_fail(vrq); - tls_peers = purple_certificate_find_pool("x509","tls_peers"); - - if (2 == id) { - gchar *cache_id = vrq->subject_name; - purple_debug_info("certificate/x509/tls_cached", - "User ACCEPTED cert\nCaching first in chain for future use as %s...\n", - cache_id); - - purple_certificate_pool_store(tls_peers, cache_id, - vrq->cert_chain->data); + purple_debug_warning("certificate/x509/tls_cached", "User REJECTED cert\n"); - purple_certificate_verify_complete(vrq, - PURPLE_CERTIFICATE_VALID); - } else { - purple_debug_warning("certificate/x509/tls_cached", - "User REJECTED cert\n"); - purple_certificate_verify_complete(vrq, - PURPLE_CERTIFICATE_INVALID); - } -} - -static void -x509_tls_cached_user_auth_accept_cb(x509_tls_cached_ua_ctx *c, gint ignore) -{ - x509_tls_cached_user_auth_cb(c, 2); -} - -static void -x509_tls_cached_user_auth_reject_cb(x509_tls_cached_ua_ctx *c, gint ignore) -{ - x509_tls_cached_user_auth_cb(c, 1); + purple_certificate_verify_complete(vrq, PURPLE_CERTIFICATE_INVALID); } /** Validates a certificate by asking the user @@ -1398,27 +1333,19 @@ { gchar *primary; - /* Make messages */ primary = g_strdup_printf(_("Accept certificate for %s?"), vrq->subject_name); - /* Make a semi-pretty display */ - purple_request_action( + purple_request_certificate( vrq->cb_data, /* TODO: Find what the handle ought to be */ _("SSL Certificate Verification"), primary, reason, - 0, /* Accept by default */ - NULL, /* No account */ - NULL, /* No other user */ - NULL, /* No associated conversation */ - x509_tls_cached_ua_ctx_new(vrq, reason), - 3, /* Number of actions */ - _("Accept"), x509_tls_cached_user_auth_accept_cb, - _("Reject"), x509_tls_cached_user_auth_reject_cb, - _("_View Certificate..."), x509_tls_cached_show_cert); + vrq->cert_chain->data, + _("Accept"), G_CALLBACK(x509_tls_cached_user_auth_accept_cb), + _("Reject"), G_CALLBACK(x509_tls_cached_user_auth_reject_cb), + vrq); - /* Cleanup */ g_free(primary); } @@ -2165,63 +2092,6 @@ /* Scheme-specific functions */ /****************************************************************************/ -void -purple_certificate_display_x509(PurpleCertificate *crt) -{ - gchar *sha_asc; - GByteArray *sha_bin; - gchar *cn; - time_t activation, expiration; - gchar *activ_str, *expir_str; - gchar *secondary; - - /* Pull out the SHA1 checksum */ - sha_bin = purple_certificate_get_fingerprint_sha1(crt); - /* Now decode it for display */ - sha_asc = purple_base16_encode_chunked(sha_bin->data, - sha_bin->len); - - /* Get the cert Common Name */ - /* TODO: Will break on CA certs */ - cn = purple_certificate_get_subject_name(crt); - - /* Get the certificate times */ - /* TODO: Check the times against localtime */ - /* TODO: errorcheck? */ - 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)); - - /* Make messages */ - secondary = g_strdup_printf(_("Common name: %s\n\n" - "Fingerprint (SHA1): %s\n\n" - "Activation date: %s\n" - "Expiration date: %s\n"), - cn ? cn : "(null)", - sha_asc ? sha_asc : "(null)", - activ_str ? activ_str : "(null)", - expir_str ? expir_str : "(null)"); - - /* Make a semi-pretty display */ - purple_notify_info( - NULL, /* TODO: Find what the handle ought to be */ - _("Certificate Information"), - "", - secondary); - - /* Cleanup */ - g_free(cn); - g_free(secondary); - g_free(sha_asc); - g_free(activ_str); - g_free(expir_str); - g_byte_array_free(sha_bin, TRUE); -} - void purple_certificate_add_ca_search_path(const char *path) { if (g_list_find_custom(x509_ca_paths, path, (GCompareFunc)strcmp)) diff -r 194f66d5089a -r 3c420b12a034 libpurple/certificate.h --- a/libpurple/certificate.h Thu Feb 23 09:00:17 2012 +0000 +++ b/libpurple/certificate.h Sun Feb 26 05:51:49 2012 +0000 @@ -261,8 +261,16 @@ */ GByteArray * (* get_der_data)(PurpleCertificate *crt); + /** + * Retrieves a string representation of the certificate suitable for display + * + * @param crt Certificate instance + * @return User-displayable string representation of certificate - must be + * freed using g_free(). + */ + gchar * (* get_display_string)(PurpleCertificate *crt); + void (*_purple_reserved1)(void); - void (*_purple_reserved2)(void); }; /** A set of operations used to provide logic for verifying a Certificate's @@ -577,6 +585,17 @@ GByteArray * purple_certificate_get_der_data(PurpleCertificate *crt); +/** + * Retrieves a string suitable for displaying a certificate to the user. + * + * @param crt Certificate instance + * + * @return String representing the certificate that may be displayed to the user + * - must be freed using g_free(). + */ +char * +purple_certificate_get_display_string(PurpleCertificate *crt); + /*@}*/ /*****************************************************************************/ @@ -815,15 +834,6 @@ /** - * Displays a window showing X.509 certificate information - * - * @param crt Certificate under an "x509" Scheme - * @todo Will break on CA certs, as they have no Common Name - */ -void -purple_certificate_display_x509(PurpleCertificate *crt); - -/** * Add a search path for certificates. * * @param path Path to search for certificates. diff -r 194f66d5089a -r 3c420b12a034 libpurple/network.c diff -r 194f66d5089a -r 3c420b12a034 libpurple/plugins/ssl/ssl-gnutls.c --- a/libpurple/plugins/ssl/ssl-gnutls.c Thu Feb 23 09:00:17 2012 +0000 +++ b/libpurple/plugins/ssl/ssl-gnutls.c Sun Feb 26 05:51:49 2012 +0000 @@ -1173,6 +1173,55 @@ return data; } +static gchar * +x509_display_string(PurpleCertificate *crt) +{ + gchar *sha_asc; + GByteArray *sha_bin; + gchar *cn; + time_t activation, expiration; + gchar *activ_str, *expir_str; + gchar *text; + + /* Pull out the SHA1 checksum */ + sha_bin = x509_sha1sum(crt); + sha_asc = purple_base16_encode_chunked(sha_bin->data, sha_bin->len); + + /* Get the cert Common Name */ + /* TODO: Will break on CA certs */ + cn = x509_common_name(crt); + + /* Get the certificate times */ + /* TODO: Check the times against localtime */ + /* TODO: errorcheck? */ + if (!x509_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)); + + /* Make messages */ + text = g_strdup_printf(_("Common name: %s\n\n" + "Fingerprint (SHA1): %s\n\n" + "Activation date: %s\n" + "Expiration date: %s\n"), + cn ? cn : "(null)", + sha_asc ? sha_asc : "(null)", + activ_str ? activ_str : "(null)", + expir_str ? expir_str : "(null)"); + + /* Cleanup */ + g_free(cn); + g_free(sha_asc); + g_free(activ_str); + g_free(expir_str); + g_byte_array_free(sha_bin, TRUE); + + return text; +} + /* X.509 certificate operations provided by this plugin */ static PurpleCertificateScheme x509_gnutls = { "x509", /* Scheme name */ @@ -1190,8 +1239,8 @@ x509_times, /* Activation/Expiration time */ x509_importcerts_from_file, /* Multiple certificates import function */ x509_get_der_data, /* Binary DER data */ + x509_display_string, /* Display representation */ - NULL, NULL }; diff -r 194f66d5089a -r 3c420b12a034 libpurple/plugins/ssl/ssl-nss.c --- a/libpurple/plugins/ssl/ssl-nss.c Thu Feb 23 09:00:17 2012 +0000 +++ b/libpurple/plugins/ssl/ssl-nss.c Sun Feb 26 05:51:49 2012 +0000 @@ -953,6 +953,55 @@ return data; } +static gchar * +x509_display_string(PurpleCertificate *crt) +{ + gchar *sha_asc; + GByteArray *sha_bin; + gchar *cn; + time_t activation, expiration; + gchar *activ_str, *expir_str; + gchar *text; + + /* Pull out the SHA1 checksum */ + sha_bin = x509_sha1sum(crt); + sha_asc = purple_base16_encode_chunked(sha_bin->data, sha_bin->len); + + /* Get the cert Common Name */ + /* TODO: Will break on CA certs */ + cn = x509_common_name(crt); + + /* Get the certificate times */ + /* TODO: Check the times against localtime */ + /* TODO: errorcheck? */ + if (!x509_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)); + + /* Make messages */ + text = g_strdup_printf(_("Common name: %s\n\n" + "Fingerprint (SHA1): %s\n\n" + "Activation date: %s\n" + "Expiration date: %s\n"), + cn ? cn : "(null)", + sha_asc ? sha_asc : "(null)", + activ_str ? activ_str : "(null)", + expir_str ? expir_str : "(null)"); + + /* Cleanup */ + g_free(cn); + g_free(sha_asc); + g_free(activ_str); + g_free(expir_str); + g_byte_array_free(sha_bin, TRUE); + + return text; +} + static PurpleCertificateScheme x509_nss = { "x509", /* Scheme name */ N_("X.509 Certificates"), /* User-visible scheme name */ @@ -969,8 +1018,8 @@ x509_times, /* Activation/Expiration time */ x509_importcerts_from_file, /* Multiple certificate import function */ x509_get_der_data, /* Binary DER data */ + x509_display_string, /* Display representation */ - NULL, NULL }; diff -r 194f66d5089a -r 3c420b12a034 libpurple/protocols/msn/contact.c diff -r 194f66d5089a -r 3c420b12a034 libpurple/protocols/msn/msn.c diff -r 194f66d5089a -r 3c420b12a034 libpurple/protocols/msn/nexus.c diff -r 194f66d5089a -r 3c420b12a034 libpurple/protocols/msn/notification.c diff -r 194f66d5089a -r 3c420b12a034 libpurple/protocols/msn/session.c diff -r 194f66d5089a -r 3c420b12a034 libpurple/protocols/msn/switchboard.c diff -r 194f66d5089a -r 3c420b12a034 libpurple/protocols/msn/user.c diff -r 194f66d5089a -r 3c420b12a034 libpurple/protocols/mxit/formcmds.c diff -r 194f66d5089a -r 3c420b12a034 libpurple/proxy.c diff -r 194f66d5089a -r 3c420b12a034 libpurple/request.c --- a/libpurple/request.c Thu Feb 23 09:00:17 2012 +0000 +++ b/libpurple/request.c Sun Feb 26 05:51:49 2012 +0000 @@ -119,6 +119,11 @@ gsize size; } image; + struct + { + PurpleCertificate *cert; + } certificate; + } u; void *ui_data; @@ -1329,6 +1334,31 @@ return field->u.account.filter_func; } +PurpleRequestField * +purple_request_field_certificate_new(const char *id, const char *text, PurpleCertificate *cert) +{ + PurpleRequestField *field; + + g_return_val_if_fail(id != NULL, NULL); + g_return_val_if_fail(text != NULL, NULL); + g_return_val_if_fail(cert != NULL, NULL); + + field = purple_request_field_new(id, text, PURPLE_REQUEST_FIELD_CERTIFICATE); + + field->u.certificate.cert = cert; + + return field; +} + +PurpleCertificate * +purple_request_field_certificate_get_value(const PurpleRequestField *field) +{ + g_return_val_if_fail(field != NULL, NULL); + g_return_val_if_fail(field->type == PURPLE_REQUEST_FIELD_CERTIFICATE, NULL); + + return field->u.certificate.cert; +} + /* -- */ void * @@ -1636,6 +1666,29 @@ return NULL; } +void * +purple_request_certificate(void *handle, const char *title, + const char *primary, const char *secondary, + PurpleCertificate *cert, + const char *ok_text, GCallback ok_cb, + const char *cancel_text, GCallback cancel_cb, + void *user_data) +{ + PurpleRequestFields *fields; + PurpleRequestFieldGroup *group; + PurpleRequestField *field; + + fields = purple_request_fields_new(); + group = purple_request_field_group_new(NULL); + purple_request_fields_add_group(fields, group); + field = purple_request_field_certificate_new("certificate", "Certificate", cert); + purple_request_field_group_add_field(group, field); + + return purple_request_fields(handle, title, primary, secondary, fields, + ok_text, ok_cb, cancel_text, cancel_cb, + NULL, NULL, NULL, user_data); +} + static void purple_request_close_info(PurpleRequestInfo *info) { diff -r 194f66d5089a -r 3c420b12a034 libpurple/request.h --- a/libpurple/request.h Thu Feb 23 09:00:17 2012 +0000 +++ b/libpurple/request.h Sun Feb 26 05:51:49 2012 +0000 @@ -76,7 +76,8 @@ PURPLE_REQUEST_FIELD_LIST, PURPLE_REQUEST_FIELD_LABEL, PURPLE_REQUEST_FIELD_IMAGE, - PURPLE_REQUEST_FIELD_ACCOUNT + PURPLE_REQUEST_FIELD_ACCOUNT, + PURPLE_REQUEST_FIELD_CERTIFICATE } PurpleRequestFieldType; @@ -1170,6 +1171,36 @@ /*@}*/ /**************************************************************************/ +/** @name Certificate Field API */ +/**************************************************************************/ +/*@{*/ + +/** + * Creates a certificate field. + * + * @param id The field ID. + * @param text The label of the field. + * @param cert The certificate of the field. + * + * @return The new field. + */ +PurpleRequestField *purple_request_field_certificate_new(const char *id, + const char *text, + PurpleCertificate *cert); + +/** + * Returns the certificate in a certificate field. + * + * @param field The field. + * + * @return The certificate. + */ +PurpleCertificate *purple_request_field_certificate_get_value( + const PurpleRequestField *field); + +/*@}*/ + +/**************************************************************************/ /** @name Request API */ /**************************************************************************/ /*@{*/ @@ -1500,6 +1531,37 @@ PurpleAccount *account, const char *who, PurpleConversation *conv, void *user_data); +/** + * Prompts the user for action over a certificate. + * + * This is often represented as a dialog with a button for each action. + * + * @param handle The plugin or connection handle. For some things this + * is extremely important. See the comments on + * purple_request_input(). + * @param title The title of the message, or @c NULL if it should have + * no title. + * @param primary The main point of the message, or @c NULL if you're + * feeling enigmatic. + * @param secondary Secondary information, or @c NULL if there is none. + * @param cert The #PurpleCertificate associated with this request. + * @param ok_text The text for the @c OK button, which may not be @c NULL. + * @param ok_cb The callback for the @c OK button, which may not be + * @c NULL. + * @param cancel_text The text for the @c Cancel button, which may not be + * @c NULL. + * @param cancel_cb The callback for the @c Cancel button, which may be + * @c NULL. + * @param user_data The data to pass to the callback. + * + * @return A UI-specific handle. + */ +void *purple_request_certificate(void *handle, const char *title, + const char *primary, const char *secondary, PurpleCertificate *cert, + const char *ok_text, GCallback ok_cb, + const char *cancel_text, GCallback cancel_cb, + void *user_data); + /*@}*/ /**************************************************************************/ diff -r 194f66d5089a -r 3c420b12a034 pidgin/gtkcertmgr.c --- a/pidgin/gtkcertmgr.c Thu Feb 23 09:00:17 2012 +0000 +++ b/pidgin/gtkcertmgr.c Sun Feb 26 05:51:49 2012 +0000 @@ -40,12 +40,6 @@ #include "gtkcertmgr.h" -#ifdef ENABLE_GCR -#define GCR_API_SUBJECT_TO_CHANGE -#include -#include -#endif - /***************************************************************************** * X.509 tls_peers management interface * *****************************************************************************/ @@ -316,13 +310,7 @@ GtkTreeModel *model; gchar *id; PurpleCertificate *crt; -#ifdef ENABLE_GCR - GByteArray *der; - GcrCertificate *gcrt; char *title; - GtkWidget *dialog; - GcrCertificateBasicsWidget *cert_widget; -#endif /* See if things are selected */ if (!gtk_tree_selection_get_selected(select, &model, &iter)) { @@ -338,38 +326,15 @@ crt = purple_certificate_pool_retrieve(tpm_dat->tls_peers, id); g_return_if_fail(crt); -#ifdef ENABLE_GCR - der = purple_certificate_get_der_data(crt); - g_return_if_fail(der); - - gcrt = gcr_simple_certificate_new(der->data, der->len); - g_return_if_fail(gcrt); - /* Fire the notification */ title = g_strdup_printf(_("Certificate Information for %s"), id); - dialog = gtk_dialog_new_with_buttons(title, - NULL, - 0, - GTK_STOCK_OK, - GTK_RESPONSE_ACCEPT, - NULL); - cert_widget = gcr_certificate_basics_widget_new(gcrt); - gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), - GTK_WIDGET(cert_widget), TRUE, TRUE, 0); - g_signal_connect_swapped(dialog, "response", - G_CALLBACK(gtk_widget_destroy), - dialog); - gtk_widget_show_all(dialog); - - g_byte_array_free(der, TRUE); - g_object_unref(G_OBJECT(gcrt)); -#else - /* Fire the notification */ - purple_certificate_display_x509(crt); + purple_request_certificate(tpm_dat, title, NULL, NULL, crt, + _("OK"), G_CALLBACK(purple_certificate_destroy), + _("Cancel"), G_CALLBACK(purple_certificate_destroy), + crt); g_free(id); - purple_certificate_destroy(crt); -#endif + g_free(title); } static void diff -r 194f66d5089a -r 3c420b12a034 pidgin/gtkrequest.c --- a/pidgin/gtkrequest.c Thu Feb 23 09:00:17 2012 +0000 +++ b/pidgin/gtkrequest.c Sun Feb 26 05:51:49 2012 +0000 @@ -39,6 +39,12 @@ #include +#ifdef ENABLE_GCR +#define GCR_API_SUBJECT_TO_CHANGE +#include +#include +#endif + #if !GTK_CHECK_VERSION(2,18,0) #define gtk_widget_set_can_default(x,y) do {\ if (y) \ @@ -1222,6 +1228,51 @@ return pidgin_make_scrollable(treeview, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC, GTK_SHADOW_IN, -1, -1); } +static GtkWidget * +create_certificate_field(PurpleRequestField *field) +{ + PurpleCertificate *cert; +#ifdef ENABLE_GCR + GcrCertificateBasicsWidget *cert_widget; + GByteArray *der; + GcrCertificate *gcrt; +#else + GtkWidget *cert_label; + char *str; + char *escaped; +#endif + + cert = purple_request_field_certificate_get_value(field); + +#ifdef ENABLE_GCR + der = purple_certificate_get_der_data(cert); + g_return_val_if_fail(der, NULL); + + gcrt = gcr_simple_certificate_new(der->data, der->len); + g_return_val_if_fail(gcrt, NULL); + + cert_widget = gcr_certificate_basics_widget_new(gcrt); + + g_byte_array_free(der, TRUE); + g_object_unref(G_OBJECT(gcrt)); + + return GTK_WIDGET(cert_widget); +#else + str = purple_certificate_get_display_string(cert); + escaped = g_markup_escape_text(str, -1); + + cert_label = gtk_label_new(NULL); + gtk_label_set_markup(GTK_LABEL(cert_label), escaped); + gtk_label_set_line_wrap(GTK_LABEL(cert_label), TRUE); + gtk_misc_set_alignment(GTK_MISC(cert_label), 0, 0); + + g_free(str); + g_free(escaped); + + return cert_label; +#endif +} + static void * pidgin_request_fields(const char *title, const char *primary, const char *secondary, PurpleRequestFields *fields, @@ -1509,6 +1560,8 @@ widget = create_image_field(field); else if (type == PURPLE_REQUEST_FIELD_ACCOUNT) widget = create_account_field(field); + else if (type == PURPLE_REQUEST_FIELD_CERTIFICATE) + widget = create_certificate_field(field); else continue; }