Fri, 30 Nov 2018 02:50:38 +0000
Merged in facebook-group-chat--sort-list (pull request #428)
Sort the facebook contacts by name/alias in group chat.
Approved-by: Elliott Sales de Andrade
Approved-by: Gary Kramlich
Approved-by: Eion Robb
--- a/doc/reference/finch/finch-docs.xml Thu Nov 22 11:25:59 2018 +0200 +++ b/doc/reference/finch/finch-docs.xml Fri Nov 30 02:50:38 2018 +0000 @@ -26,7 +26,6 @@ <xi:include href="xml/gntaccount.xml" /> <xi:include href="xml/gntblist.xml" /> <xi:include href="xml/gntpounce.xml" /> - <xi:include href="xml/gntcertmgr.xml" /> <xi:include href="xml/gntconn.xml" /> <xi:include href="xml/gntconv.xml" /> <xi:include href="xml/gntdebug.xml" />
--- a/doc/reference/libpurple/libpurple-docs.xml Thu Nov 22 11:25:59 2018 +0200 +++ b/doc/reference/libpurple/libpurple-docs.xml Fri Nov 30 02:50:38 2018 +0000 @@ -83,8 +83,6 @@ <xi:include href="xml/theme.xml" /> <xi:include href="xml/theme-loader.xml" /> <xi:include href="xml/theme-manager.xml" /> - <xi:include href="xml/tls-certificate-info.xml" /> - <xi:include href="xml/tls-certificate.xml" /> <xi:include href="xml/trie.xml" /> <xi:include href="xml/sound-theme.xml" /> <xi:include href="xml/sound-theme-loader.xml" />
--- a/doc/reference/pidgin/pidgin-docs.xml Thu Nov 22 11:25:59 2018 +0200 +++ b/doc/reference/pidgin/pidgin-docs.xml Fri Nov 30 02:50:38 2018 +0000 @@ -25,7 +25,6 @@ <xi:include href="xml/gtkblist-theme-loader.xml" /> <xi:include href="xml/gtkpounce.xml" /> <xi:include href="xml/gtkcellrendererexpander.xml" /> - <xi:include href="xml/gtkcertmgr.xml" /> <xi:include href="xml/gtkconn.xml" /> <xi:include href="xml/gtkconv.xml" /> <xi:include href="xml/gtkconvwin.xml" />
--- a/finch/gntcertmgr.c Thu Nov 22 11:25:59 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,351 +0,0 @@ -/* finch - * - * Finch is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - * - */ - -#include <internal.h> -#include "finch.h" - -#include "debug.h" -#include "notify.h" -#include "request.h" -#include "tls-certificate.h" -#include "tls-certificate-info.h" - -#include "gntcertmgr.h" - -#include "gntbutton.h" -#include "gntlabel.h" -#include "gnttree.h" -#include "gntutils.h" -#include "gntwindow.h" - -struct { - GntWidget *window; - GntWidget *tree; -} certmgr; - -/* Pretty much Xerox of gtkcertmgr */ - -/* Add certificate */ -static void -tls_peers_mgmt_import_ok2_cb(gpointer data, const char *result) -{ - GTlsCertificate *crt = data; - const char *id = result; - GError *error = NULL; - - /* TODO: Perhaps prompt if you're overwriting a cert? */ - - if (purple_tls_certificate_trust(id, crt, &error)) { - gnt_tree_add_row_last(GNT_TREE(certmgr.tree), g_strdup(id), - gnt_tree_create_row(GNT_TREE(certmgr.tree), id), - NULL); - } else { - purple_debug_error("gntcertmgr/tls_peers_mgmt", - "Failure trusting peer certificate '%s': %s", - id, error->message); - g_clear_error(&error); - } - - g_object_unref(crt); -} - -static void -tls_peers_mgmt_import_ok_cb(gpointer data, const char *filename) -{ - GTlsCertificate *crt; - GError *error = NULL; - - crt = g_tls_certificate_new_from_file(filename, &error); - - if (crt != NULL) { - gchar *default_hostname; - PurpleTlsCertificateInfo *info; - - info = purple_tls_certificate_get_info(crt); - default_hostname = purple_tls_certificate_info_get_subject_name(info); - purple_tls_certificate_info_free(info); - - purple_request_input(NULL, - _("Certificate Import"), - _("Specify a hostname"), - _("Type the host name this certificate is for."), - default_hostname, FALSE, FALSE, NULL, - _("OK"), G_CALLBACK(tls_peers_mgmt_import_ok2_cb), - _("Cancel"), G_CALLBACK(g_object_unref), - NULL, crt); - g_free(default_hostname); - } else { - gchar * secondary; - - purple_debug_error("gntcertmgr/tls_peers_mgmt", - "Failed to import certificate '%s': %s", - filename, error->message); - g_clear_error(&error); - - secondary = g_strdup_printf(_("File %s could not be imported.\nMake sure that the file is readable and in PEM format.\n"), filename); - purple_notify_error(NULL, - _("Certificate Import Error"), - _("X.509 certificate import failed"), - secondary, NULL); - g_free(secondary); - } -} - -static void -add_cert_cb(GntWidget *button, gpointer null) -{ - purple_request_file(NULL, - _("Select a PEM certificate"), - "certificate.pem", - FALSE, - G_CALLBACK(tls_peers_mgmt_import_ok_cb), - NULL, - NULL, NULL ); -} - -/* Save certs in some file */ -static void -tls_peers_mgmt_export_ok_cb(gpointer data, const char *filename) -{ - GTlsCertificate *crt = data; - gchar *pem = NULL; - GError *error = NULL; - - g_object_get(crt, "certificate-pem", &pem, NULL); - g_return_if_fail(crt != NULL); - - if (!g_file_set_contents(filename, pem, -1, &error)) { - gchar * secondary; - - purple_debug_error("gntcertmgr/tls_peers_mgmt", - "Failed to export certificate '%s': %s", - filename, error->message); - g_clear_error(&error); - - secondary = g_strdup_printf(_("Export to file %s failed.\nCheck that you have write permission to the target path\n"), filename); - purple_notify_error(NULL, - _("Certificate Export Error"), - _("X.509 certificate export failed"), - secondary, NULL); - g_free(secondary); - } - - g_free(pem); - g_object_unref(crt); -} - -static void -save_cert_cb(GntWidget *button, gpointer null) -{ - GTlsCertificate *crt; - const char *key; - GError *error = NULL; - - if (!certmgr.window) - return; - - key = gnt_tree_get_selection_data(GNT_TREE(certmgr.tree)); - if (!key) - return; - - crt = purple_tls_certificate_new_from_id(key, &error); - - if (!crt) { - purple_debug_error("gntcertmgr/tls_peers_mgmt", - "Failed to fetch trusted certificate '%s': %s", - key, error->message); - g_clear_error(&error); - return; - } - - purple_request_file((void*)key, - _("PEM X.509 Certificate Export"), - "certificate.pem", TRUE, - G_CALLBACK(tls_peers_mgmt_export_ok_cb), - G_CALLBACK(g_object_unref), - NULL, crt); -} - -/* Show information about a cert */ -static void -info_cert_cb(GntWidget *button, gpointer null) -{ - const char *key; - GTlsCertificate *crt; - PurpleTlsCertificateInfo *info; - gchar *subject; - GByteArray *fpr_sha1; - gchar *fpr_sha1_asc; - gchar *primary, *secondary; - - if (!certmgr.window) - return; - - key = gnt_tree_get_selection_data(GNT_TREE(certmgr.tree)); - if (!key) - return; - - crt = purple_tls_certificate_new_from_id(key, NULL); - g_return_if_fail(crt); - - primary = g_strdup_printf(_("Certificate for %s"), key); - - fpr_sha1 = purple_tls_certificate_get_fingerprint_sha1(crt); - fpr_sha1_asc = purple_base16_encode_chunked(fpr_sha1->data, - fpr_sha1->len); - - info = purple_tls_certificate_get_info(crt); - subject = purple_tls_certificate_info_get_subject_name(info); - purple_tls_certificate_info_free(info); - - secondary = g_strdup_printf(_("Common name: %s\n\nSHA1 fingerprint:\n%s"), subject, fpr_sha1_asc); - - purple_notify_info(NULL, - _("SSL Host Certificate"), primary, secondary, NULL); - - g_free(primary); - g_free(secondary); - g_byte_array_free(fpr_sha1, TRUE); - g_free(fpr_sha1_asc); - g_free(subject); - g_object_unref(crt); -} - -/* Delete a cert */ -static void -tls_peers_mgmt_delete_confirm_cb(gchar *id, gint dontcare) -{ - GError *error = NULL; - - if (!purple_tls_certificate_distrust(id, &error)) { - purple_debug_warning("gntcertmgr/tls_peers_mgmt", - "Deletion failed on id '%s': %s\n", - id, error->message); - g_clear_error(&error); - }; - - purple_request_close_with_handle((void*)id); - gnt_tree_remove(GNT_TREE(certmgr.tree), (void*)id); - - g_free(id); -} - -static void -delete_cert_cb(GntWidget *button, gpointer null) -{ - gchar *primary; - const char *key; - - if (!certmgr.window) - return; - - key = gnt_tree_get_selection_data(GNT_TREE(certmgr.tree)); - if (!key) - return; - - primary = g_strdup_printf(_("Really delete certificate for %s?"), key); - - purple_request_close_with_handle((void *)key); - purple_request_yes_no((void *)key, _("Confirm certificate delete"), - primary, NULL, - 0, - NULL, - g_strdup(key), - tls_peers_mgmt_delete_confirm_cb, - g_free); - - g_free(primary); -} - -/* populate the list */ -static void -populate_cert_list(void) -{ - GList *idlist, *l; - - if (!certmgr.window) - return; - - gnt_tree_remove_all(GNT_TREE(certmgr.tree)); - - idlist = purple_tls_certificate_list_ids(); - for (l = idlist; l; l = l->next) { - gnt_tree_add_row_last(GNT_TREE(certmgr.tree), g_strdup(l->data), - gnt_tree_create_row(GNT_TREE(certmgr.tree), l->data), NULL); - } - purple_tls_certificate_free_ids(idlist); -} - -void finch_certmgr_show(void) -{ - GntWidget *win, *tree, *box, *button; - - if (certmgr.window) { - gnt_window_present(certmgr.window); - return; - } - - certmgr.window = win = gnt_vwindow_new(FALSE); - gnt_box_set_title(GNT_BOX(win), _("Certificate Manager")); - gnt_box_set_pad(GNT_BOX(win), 0); - - certmgr.tree = tree = gnt_tree_new(); - gnt_tree_set_hash_fns(GNT_TREE(tree), g_str_hash, g_str_equal, g_free); - gnt_tree_set_column_title(GNT_TREE(tree), 0, _("Hostname")); - gnt_tree_set_show_title(GNT_TREE(tree), TRUE); - - gnt_box_add_widget(GNT_BOX(win), tree); - - box = gnt_hbox_new(FALSE); - gnt_box_add_widget(GNT_BOX(win), box); - - button = gnt_button_new(_("Add")); - gnt_box_add_widget(GNT_BOX(box), button); - g_signal_connect(G_OBJECT(button), "activate", G_CALLBACK(add_cert_cb), NULL); - gnt_util_set_trigger_widget(GNT_WIDGET(tree), GNT_KEY_INS, button); - - button = gnt_button_new(_("Save")); - gnt_box_add_widget(GNT_BOX(box), button); - g_signal_connect(G_OBJECT(button), "activate", G_CALLBACK(save_cert_cb), NULL); - - button = gnt_button_new(_("Info")); - gnt_box_add_widget(GNT_BOX(box), button); - g_signal_connect(G_OBJECT(button), "activate", G_CALLBACK(info_cert_cb), NULL); - - button = gnt_button_new(_("Delete")); - gnt_box_add_widget(GNT_BOX(box), button); - g_signal_connect(G_OBJECT(button), "activate", G_CALLBACK(delete_cert_cb), NULL); - gnt_util_set_trigger_widget(GNT_WIDGET(tree), GNT_KEY_DEL, button); - - button = gnt_button_new(_("Close")); - gnt_box_add_widget(GNT_BOX(box), button); - g_signal_connect_swapped(G_OBJECT(button), "activate", G_CALLBACK(gnt_widget_destroy), win); - - g_signal_connect_swapped(G_OBJECT(win), "destroy", G_CALLBACK(g_nullify_pointer), &certmgr.window); - - populate_cert_list(); - - g_signal_connect(G_OBJECT(win), "destroy", G_CALLBACK(purple_signals_disconnect_by_handle), NULL); - - gnt_widget_show(certmgr.window); -} -
--- a/finch/gntcertmgr.h Thu Nov 22 11:25:59 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,34 +0,0 @@ -/* finch - * - * Finch is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - * - */ - -#ifndef _GNT_CERTMGR_H -#define _GNT_CERTMGR_H -/** - * SECTION:gntcertmgr - * @section_id: finch-gntcertmgr - * @short_description: <filename>gntcertmgr.h</filename> - * @title: Certificate Manager API - */ - -void finch_certmgr_show(void); - -#endif
--- a/finch/gntrequest.c Thu Nov 22 11:25:59 2018 +0200 +++ b/finch/gntrequest.c Fri Nov 30 02:50:38 2018 +0000 @@ -34,7 +34,6 @@ #include "finch.h" #include "gntrequest.h" #include "debug.h" -#include "tls-certificate-info.h" #include "util.h" typedef struct @@ -575,26 +574,6 @@ return combo; } -static GntWidget* -create_certificate_field(PurpleRequestField *field) -{ - GntWidget *w; - GTlsCertificate *cert; - PurpleTlsCertificateInfo *info; - char *str; - - cert = purple_request_field_certificate_get_value(field); - info = purple_tls_certificate_get_info(cert); - str = purple_tls_certificate_info_get_display_string(info); - purple_tls_certificate_info_free(info); - - w = gnt_label_new(str); - - g_free(str); - - return w; -} - static void multifield_extra_cb(GntWidget *button, PurpleRequestFields *allfields) { @@ -695,10 +674,6 @@ 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."),
--- a/finch/gntui.c Thu Nov 22 11:25:59 2018 +0200 +++ b/finch/gntui.c Fri Nov 30 02:50:38 2018 +0000 @@ -26,7 +26,6 @@ #include "gntaccount.h" #include "gntblist.h" -#include "gntcertmgr.h" #include "gntconn.h" #include "gntconv.h" #include "gntdebug.h" @@ -103,7 +102,6 @@ gnt_register_action(_("Accounts"), finch_accounts_show_all); gnt_register_action(_("Buddy List"), finch_blist_show); gnt_register_action(_("Buddy Pounces"), finch_pounces_manager_show); - gnt_register_action(_("Certificates"), finch_certmgr_show); gnt_register_action(_("Debug Window"), finch_debug_window_show); gnt_register_action(_("File Transfers"), finch_xfer_dialog_show); gnt_register_action(_("Plugins"), finch_plugins_show_all);
--- a/finch/meson.build Thu Nov 22 11:25:59 2018 +0200 +++ b/finch/meson.build Fri Nov 30 02:50:38 2018 +0000 @@ -16,7 +16,6 @@ libfinch_SOURCES = [ 'gntaccount.c', 'gntblist.c', - 'gntcertmgr.c', 'gntconn.c', 'gntconv.c', 'gntdebug.c', @@ -41,7 +40,6 @@ libfinch_headers = [ 'gntaccount.h', 'gntblist.h', - 'gntcertmgr.h', 'gntconn.h', 'gntconv.h', 'gntdebug.h',
--- a/libpurple/http.c Thu Nov 22 11:25:59 2018 +0200 +++ b/libpurple/http.c Fri Nov 30 02:50:38 2018 +0000 @@ -30,14 +30,14 @@ #include "purple-gio.h" #define PURPLE_HTTP_URL_CREDENTIALS_CHARS "a-z0-9.,~_/*!&%?=+\\^-" -#define PURPLE_HTTP_MAX_RECV_BUFFER_LEN 10240 -#define PURPLE_HTTP_MAX_READ_BUFFER_LEN 10240 +#define PURPLE_HTTP_MAX_RECV_BUFFER_LEN 102400 +#define PURPLE_HTTP_MAX_READ_BUFFER_LEN 102400 #define PURPLE_HTTP_GZ_BUFF_LEN 1024 #define PURPLE_HTTP_REQUEST_DEFAULT_MAX_REDIRECTS 20 #define PURPLE_HTTP_REQUEST_DEFAULT_TIMEOUT 30 #define PURPLE_HTTP_REQUEST_DEFAULT_MAX_LENGTH 1048576 -#define PURPLE_HTTP_REQUEST_HARD_MAX_LENGTH G_MAXINT32-1 +#define PURPLE_HTTP_REQUEST_HARD_MAX_LENGTH (G_MAXINT32 - 1) #define PURPLE_HTTP_PROGRESS_WATCHER_DEFAULT_INTERVAL 250000 @@ -338,15 +338,17 @@ d_year, month, d_date, d_time); g_free(d_date); - g_free(d_month); g_free(d_year); g_free(d_time); if (month > 12) { purple_debug_warning("http", "Invalid month: %s\n", d_month); + g_free(d_month); g_free(iso_date); return 0; } + + g_free(d_month); t = purple_str_to_time(iso_date, TRUE, NULL, NULL, NULL); @@ -438,6 +440,7 @@ error->message); g_clear_error(&error); gzs->failed = TRUE; + g_string_free(ret, TRUE); return NULL; } } @@ -834,6 +837,17 @@ purple_http_conn_cancel(hc); } +static void memset_zero(gpointer pnt, gsize len) +{ + volatile unsigned char *volatile pnt_ = + (volatile unsigned char *volatile) pnt; + size_t i = (size_t) 0U; + + while (i < len) { + pnt_[i++] = 0U; + } +} + static void _purple_http_gen_headers(PurpleHttpConnection *hc) { GString *h; @@ -897,7 +911,7 @@ purple_http_request_is_method(req, "post"))) { g_string_append_printf(h, "Content-Length: %u\r\n", - req->contents_length); + (guint) req->contents_length); } if (proxy_http) @@ -915,7 +929,7 @@ tmp = g_strdup_printf("%s:%s", proxy_username, proxy_password); len = strlen(tmp); proxy_auth = g_base64_encode((const guchar *)tmp, len); - memset(tmp, 0, len); + memset_zero(tmp, len); g_free(tmp); ntlm_type1 = purple_http_ntlm_gen_type1(purple_get_host_name(), @@ -927,7 +941,7 @@ ntlm_type1); g_string_append(h, "Proxy-Connection: close\r\n"); /* TEST: proxy+KeepAlive */ - memset(proxy_auth, 0, strlen(proxy_auth)); + memset_zero(proxy_auth, strlen(proxy_auth)); g_free(proxy_auth); g_free(ntlm_type1); } @@ -1307,7 +1321,11 @@ int buffer_len = hc->response_buffer->len; gchar *buffer = g_string_free(hc->response_buffer, FALSE); hc->response_buffer = NULL; - _purple_http_recv_body(hc, buffer, buffer_len); + if (!_purple_http_recv_body(hc, buffer, buffer_len)) + { + g_free(buffer); + return FALSE; + } g_free(buffer); } if (!hc->headers_got) @@ -1578,6 +1596,10 @@ if (hc->response_buffer) g_string_free(hc->response_buffer, TRUE); hc->response_buffer = NULL; + + if (hc->gz_stream) + purple_http_gz_free(hc->gz_stream); + hc->gz_stream = NULL; if (hc->socket_request) purple_http_keepalive_pool_request_cancel(hc->socket_request); @@ -1876,7 +1898,9 @@ http_conn); } - http_conn->response->code = 0; + if (http_conn->response != NULL) { + http_conn->response->code = 0; + } _purple_http_disconnect(http_conn, FALSE); purple_http_connection_terminate(http_conn); } @@ -1889,7 +1913,9 @@ purple_debug_info("http", "Retrying connection %p...\n", http_conn); - http_conn->response->code = 0; + if (http_conn->response != NULL) { + http_conn->response->code = 0; + } _purple_http_disconnect(http_conn, FALSE); _purple_http_reconnect(http_conn); } @@ -1905,7 +1931,7 @@ gc_list = g_hash_table_lookup(purple_http_hc_by_gc, gc); - g_hash_table_insert(purple_http_cancelling_gc, gc, GINT_TO_POINTER(TRUE)); + g_hash_table_insert(purple_http_cancelling_gc, gc, GINT_TO_POINTER(1)); while (gc_list) { PurpleHttpConnection *hc = gc_list->data; @@ -2590,7 +2616,7 @@ purple_http_connection_set_remove(http_conn->connection_set, http_conn); } - g_hash_table_insert(set->connections, http_conn, (gpointer)TRUE); + g_hash_table_insert(set->connections, http_conn, GINT_TO_POINTER(1)); http_conn->connection_set = set; } @@ -3235,7 +3261,9 @@ if (parsed_url->username || parsed_url->password) { if (parsed_url->username) g_string_append(url, parsed_url->username); - g_string_append_printf(url, ":%s", parsed_url->password); + g_string_append_c(url, ':'); + if (parsed_url->password) + g_string_append(url, parsed_url->password); g_string_append(url, "@"); before_host_printed = TRUE; } @@ -3381,8 +3409,9 @@ g_regex_unref(purple_http_re_rfc1123); purple_http_re_rfc1123 = NULL; - g_list_foreach(purple_http_hc_list, purple_http_foreach_conn_cancel, - NULL); + if (purple_http_hc_list != NULL) { + g_list_foreach(purple_http_hc_list, purple_http_foreach_conn_cancel, NULL); + } if (purple_http_hc_list != NULL || 0 != g_hash_table_size(purple_http_hc_by_ptr) ||
--- a/libpurple/meson.build Thu Nov 22 11:25:59 2018 +0200 +++ b/libpurple/meson.build Fri Nov 30 02:50:38 2018 +0000 @@ -71,8 +71,6 @@ 'theme.c', 'theme-loader.c', 'theme-manager.c', - 'tls-certificate.c', - 'tls-certificate-info.c', 'trie.c', 'upnp.c', 'util.c', @@ -153,8 +151,6 @@ 'theme.h', 'theme-loader.h', 'theme-manager.h', - 'tls-certificate.h', - 'tls-certificate-info.h', 'trie.h', 'upnp.h', 'util.h',
--- a/libpurple/protocols/gg/gg.c Thu Nov 22 11:25:59 2018 +0200 +++ b/libpurple/protocols/gg/gg.c Fri Nov 30 02:50:38 2018 +0000 @@ -33,6 +33,7 @@ #include "notify.h" #include "buddylist.h" #include "accountopt.h" +#include "core.h" #include "debug.h" #include "util.h" #include "request.h" @@ -591,6 +592,56 @@ gg_free_event(ev); } +static gint +gg_uri_handler_find_account(gconstpointer a, gconstpointer b) +{ + PurpleAccount *account = PURPLE_ACCOUNT(a); + const gchar *protocol_id; + + protocol_id = purple_account_get_protocol_id(account); + + if (purple_strequal(protocol_id, "prpl-gg") && + purple_account_is_connected(account)) { + return 0; + } else { + return -1; + } +} + +static gboolean +gg_uri_handler(const gchar *scheme, const gchar *screenname, + GHashTable *params) +{ + GList *accounts; + GList *account_node; + PurpleIMConversation *im; + + g_return_val_if_fail(screenname != NULL, FALSE); + + if (!purple_strequal(scheme, "gg")) { + return FALSE; + } + + if (screenname[0] == '\0') { + purple_debug_warning("gg", "Invalid empty screenname in URI"); + return FALSE; + } + + /* Find online Gadu-Gadu account */ + accounts = purple_accounts_get_all(); + account_node = g_list_find_custom(accounts, NULL, + gg_uri_handler_find_account); + + if (account_node == NULL) { + return FALSE; + } + + im = purple_im_conversation_new(account_node->data, screenname); + purple_conversation_present(PURPLE_CONVERSATION(im)); + + return TRUE; +} + /* ---------------------------------------------------------------------- */ /* ----- PurpleProtocol ----------------------------------------- */ /* ---------------------------------------------------------------------- */ @@ -1154,12 +1205,18 @@ ggp_html_setup(); ggp_message_setup_global(); + purple_signal_connect(purple_get_core(), "uri-handler", plugin, + PURPLE_CALLBACK(gg_uri_handler), NULL); + return TRUE; } static gboolean plugin_unload(PurplePlugin *plugin, GError **error) { + purple_signal_disconnect(purple_get_core(), "uri-handler", plugin, + PURPLE_CALLBACK(gg_uri_handler)); + ggp_servconn_cleanup(); ggp_html_cleanup(); ggp_message_cleanup_global();
--- a/libpurple/protocols/irc/irc.h Thu Nov 22 11:25:59 2018 +0200 +++ b/libpurple/protocols/irc/irc.h Fri Nov 30 02:50:38 2018 +0000 @@ -34,7 +34,6 @@ #include "xfer.h" #include "queuedoutputstream.h" #include "roomlist.h" -#include "sslconn.h" #define IRC_TYPE_PROTOCOL (irc_protocol_get_type()) #define IRC_PROTOCOL(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), IRC_TYPE_PROTOCOL, IRCProtocol))
--- a/libpurple/protocols/jabber/jabber.c Thu Nov 22 11:25:59 2018 +0200 +++ b/libpurple/protocols/jabber/jabber.c Fri Nov 30 02:50:38 2018 +0000 @@ -3784,15 +3784,24 @@ return acct; } -static gboolean xmpp_uri_handler(const char *proto, const char *user, GHashTable *params) +static gboolean +xmpp_uri_handler(const char *proto, const char *user, GHashTable *params, + gpointer user_data) { - char *acct_id = params ? g_hash_table_lookup(params, "account") : NULL; + PurpleProtocol *protocol = (PurpleProtocol *)user_data; + const gchar *acct_id = NULL; PurpleAccount *acct; + g_return_val_if_fail(PURPLE_IS_PROTOCOL(protocol), FALSE); + if (g_ascii_strcasecmp(proto, "xmpp")) return FALSE; - acct = find_acct(proto, acct_id); + if (params != NULL) { + acct_id = g_hash_table_lookup(params, "account"); + } + + acct = find_acct(protocol->id, acct_id); if (!acct) return FALSE; @@ -3800,18 +3809,27 @@ /* xmpp:romeo@montague.net?message;subject=Test%20Message;body=Here%27s%20a%20test%20message */ /* params is NULL if the URI has no '?' (or anything after it) */ if (!params || g_hash_table_lookup_extended(params, "message", NULL, NULL)) { - char *body = g_hash_table_lookup(params, "body"); if (user && *user) { PurpleIMConversation *im = purple_im_conversation_new(acct, user); + const gchar *body = NULL; + purple_conversation_present(PURPLE_CONVERSATION(im)); + + if (params != NULL) { + body = g_hash_table_lookup(params, "body"); + } + if (body && *body) purple_conversation_send_confirm(PURPLE_CONVERSATION(im), body); + return TRUE; } } else if (g_hash_table_lookup_extended(params, "roster", NULL, NULL)) { char *name = g_hash_table_lookup(params, "name"); - if (user && *user) + if (user && *user) { purple_blist_request_add_buddy(acct, user, NULL, name); + return TRUE; + } } else if (g_hash_table_lookup_extended(params, "join", NULL, NULL)) { PurpleConnection *gc = purple_account_get_connection(acct); if (user && *user) { @@ -4267,9 +4285,9 @@ return FALSE; purple_signal_connect(purple_get_core(), "uri-handler", xmpp_protocol, - PURPLE_CALLBACK(xmpp_uri_handler), NULL); + PURPLE_CALLBACK(xmpp_uri_handler), xmpp_protocol); purple_signal_connect(purple_get_core(), "uri-handler", gtalk_protocol, - PURPLE_CALLBACK(xmpp_uri_handler), NULL); + PURPLE_CALLBACK(xmpp_uri_handler), gtalk_protocol); jabber_init_protocol(xmpp_protocol); jabber_init_protocol(gtalk_protocol); @@ -4280,6 +4298,11 @@ static gboolean plugin_unload(PurplePlugin *plugin, GError **error) { + purple_signal_disconnect(purple_get_core(), "uri-handler", + xmpp_protocol, PURPLE_CALLBACK(xmpp_uri_handler)); + purple_signal_disconnect(purple_get_core(), "uri-handler", + gtalk_protocol, PURPLE_CALLBACK(xmpp_uri_handler)); + jabber_uninit_protocol(gtalk_protocol); jabber_uninit_protocol(xmpp_protocol);
--- a/libpurple/protocols/oscar/oscar.c Thu Nov 22 11:25:59 2018 +0200 +++ b/libpurple/protocols/oscar/oscar.c Fri Nov 30 02:50:38 2018 +0000 @@ -5529,13 +5529,21 @@ gboolean oscar_uri_handler(const char *proto, const char *cmd, GHashTable *params) { - char *acct_id = g_hash_table_lookup(params, "account"); + char *acct_id; char prpl[11]; PurpleAccount *acct; if (g_ascii_strcasecmp(proto, "aim") && g_ascii_strcasecmp(proto, "icq")) return FALSE; + if (params == NULL) { + /* All Oscar URI actions require some parameters eventually */ + purple_debug_warning("oscar", + "No required params for handling URI"); + return FALSE; + } + + acct_id = g_hash_table_lookup(params, "account"); g_snprintf(prpl, sizeof(prpl), "prpl-%s", proto); acct = find_acct(proto, acct_id);
--- a/libpurple/protocols/simple/simple.c Thu Nov 22 11:25:59 2018 +0200 +++ b/libpurple/protocols/simple/simple.c Fri Nov 30 02:50:38 2018 +0000 @@ -29,6 +29,7 @@ #include "accountopt.h" #include "buddylist.h" #include "conversation.h" +#include "core.h" #include "debug.h" #include "notify.h" #include "protocol.h" @@ -65,6 +66,57 @@ return "simple"; } +static gint +simple_uri_handler_find_account(gconstpointer a, gconstpointer b) +{ + PurpleAccount *account = PURPLE_ACCOUNT(a); + const gchar *protocol_id; + + protocol_id = purple_account_get_protocol_id(account); + + if (purple_strequal(protocol_id, "prpl-simple") && + purple_account_is_connected(account)) { + return 0; + } else { + return -1; + } +} + +static gboolean +simple_uri_handler(const gchar *scheme, const gchar *screenname, + GHashTable *params) +{ + GList *accounts; + GList *account_node; + PurpleIMConversation *im; + + g_return_val_if_fail(screenname != NULL, FALSE); + + if (!purple_strequal(scheme, "sip")) { + return FALSE; + } + + if (screenname[0] == '\0') { + purple_debug_warning("simple", + "Invalid empty screenname in URI"); + return FALSE; + } + + /* Find online SIMPLE account */ + accounts = purple_accounts_get_all(); + account_node = g_list_find_custom(accounts, NULL, + simple_uri_handler_find_account); + + if (account_node == NULL) { + return FALSE; + } + + im = purple_im_conversation_new(account_node->data, screenname); + purple_conversation_present(PURPLE_CONVERSATION(im)); + + return TRUE; +} + static void simple_keep_alive(PurpleConnection *gc) { struct simple_account_data *sip = purple_connection_get_protocol_data(gc); if(sip->udp) { /* in case of UDP send a packet only with a 0 byte to @@ -2192,12 +2244,18 @@ if (!my_protocol) return FALSE; + purple_signal_connect(purple_get_core(), "uri-handler", plugin, + PURPLE_CALLBACK(simple_uri_handler), NULL); + return TRUE; } static gboolean plugin_unload(PurplePlugin *plugin, GError **error) { + purple_signal_disconnect(purple_get_core(), "uri-handler", plugin, + PURPLE_CALLBACK(simple_uri_handler)); + if (!purple_protocols_remove(my_protocol, error)) return FALSE;
--- a/libpurple/purple-gio.c Thu Nov 22 11:25:59 2018 +0200 +++ b/libpurple/purple-gio.c Fri Nov 30 02:50:38 2018 +0000 @@ -24,7 +24,6 @@ #include "internal.h" #include "proxy.h" #include "purple-gio.h" -#include "tls-certificate.h" typedef struct { GIOStream *stream; @@ -127,9 +126,6 @@ g_socket_client_set_proxy_resolver(client, resolver); g_object_unref(resolver); - /* Attach purple's tls certificate handler in case tls is used */ - purple_tls_certificate_attach_to_socket_client(client); - return client; }
--- a/libpurple/purple.h.in Thu Nov 22 11:25:59 2018 +0200 +++ b/libpurple/purple.h.in Fri Nov 30 02:50:38 2018 +0000 @@ -92,7 +92,6 @@ #include <theme.h> #include <theme-loader.h> #include <theme-manager.h> -#include <tls-certificate.h> #include <upnp.h> #include <util.h> #include <version.h>
--- a/libpurple/request.c Thu Nov 22 11:25:59 2018 +0200 +++ b/libpurple/request.c Fri Nov 30 02:50:38 2018 +0000 @@ -125,11 +125,6 @@ struct { - GTlsCertificate *cert; - } certificate; - - struct - { PurpleRequestDatasheet *sheet; } datasheet; } u; @@ -1954,31 +1949,6 @@ } PurpleRequestField * -purple_request_field_certificate_new(const char *id, const char *text, GTlsCertificate *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; -} - -GTlsCertificate * -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; -} - -PurpleRequestField * purple_request_field_datasheet_new(const char *id, const gchar *text, PurpleRequestDatasheet *sheet) { @@ -2472,29 +2442,6 @@ return NULL; } -void * -purple_request_certificate(void *handle, const char *title, - const char *primary, const char *secondary, - GTlsCertificate *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, user_data); -} - gboolean purple_request_is_valid_ui_handle(void *ui_handle, PurpleRequestType *type) {
--- a/libpurple/request.h Thu Nov 22 11:25:59 2018 +0200 +++ b/libpurple/request.h Fri Nov 30 02:50:38 2018 +0000 @@ -29,7 +29,6 @@ */ #include <stdlib.h> -#include <gio/gio.h> #include <glib-object.h> #include <glib.h> @@ -112,7 +111,6 @@ PURPLE_REQUEST_FIELD_LABEL, PURPLE_REQUEST_FIELD_IMAGE, PURPLE_REQUEST_FIELD_ACCOUNT, - PURPLE_REQUEST_FIELD_CERTIFICATE, PURPLE_REQUEST_FIELD_DATASHEET } PurpleRequestFieldType; @@ -1776,35 +1774,6 @@ const PurpleRequestField *field); /**************************************************************************/ -/* Certificate Field API */ -/**************************************************************************/ - -/** - * purple_request_field_certificate_new: - * @id: The field ID. - * @text: The label of the field. - * @cert: The certificate of the field. - * - * Creates a certificate field. - * - * Returns: The new field. - */ -PurpleRequestField *purple_request_field_certificate_new(const char *id, - const char *text, - GTlsCertificate *cert); - -/** - * purple_request_field_certificate_get_value: - * @field: The field. - * - * Returns the certificate in a certificate field. - * - * Returns: The certificate. - */ -GTlsCertificate *purple_request_field_certificate_get_value( - const PurpleRequestField *field); - -/**************************************************************************/ /* Datasheet Field API */ /**************************************************************************/ @@ -2240,39 +2209,6 @@ GCallback ok_cb, GCallback cancel_cb, PurpleRequestCommonParameters *cpar, void *user_data); -/** - * purple_request_certificate: - * @handle: The plugin or connection handle. For some things this - * is <emphasis>extremely</emphasis> important. See the comments on - * purple_request_input(). - * @title: The title of the message, or %NULL if it should have - * no title. - * @primary: The main point of the message, or %NULL if you're - * feeling enigmatic. - * @secondary: Secondary information, or %NULL if there is none. - * @cert: The #GTlsCertificate associated with this request. - * @ok_text: The text for the <literal>OK</literal> button, which may not - * be %NULL. - * @ok_cb: The callback for the <literal>OK</literal> button, which may - * not be %NULL. - * @cancel_text: The text for the <literal>Cancel</literal> button, which may - * not be %NULL. - * @cancel_cb: The callback for the <literal>Cancel</literal> button, which - * may be %NULL. - * @user_data: The data to pass to the callback. - * - * Prompts the user for action over a certificate. - * - * This is often represented as a dialog with a button for each action. - * - * Returns: A UI-specific handle. - */ -void *purple_request_certificate(void *handle, const char *title, - const char *primary, const char *secondary, GTlsCertificate *cert, - const char *ok_text, GCallback ok_cb, - const char *cancel_text, GCallback cancel_cb, - void *user_data); - /**************************************************************************/ /* UI Registration Functions */ /**************************************************************************/
--- a/libpurple/sslconn.c Thu Nov 22 11:25:59 2018 +0200 +++ b/libpurple/sslconn.c Fri Nov 30 02:50:38 2018 +0000 @@ -26,7 +26,6 @@ #include "plugins.h" #include "request.h" #include "sslconn.h" -#include "tls-certificate.h" #define CONNECTION_CLOSE_TIMEOUT 15 @@ -104,8 +103,6 @@ gsc->conn = G_TLS_CONNECTION(tls_conn); gsc->cancellable = g_cancellable_new(); - purple_tls_certificate_attach_to_tls_connection(gsc->conn); - g_tls_connection_handshake_async(gsc->conn, G_PRIORITY_DEFAULT, gsc->cancellable, tls_handshake_cb, gsc);
--- a/libpurple/tls-certificate-info.c Thu Nov 22 11:25:59 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,815 +0,0 @@ -/* - * - * purple - * - * Purple is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#include "internal.h" -#include "tls-certificate-info.h" -#include "debug.h" -#include "util.h" - -#define DER_TYPE_CLASS(type) (type & 0xc0) - -#define DER_TYPE_CLASS_UNIVERSAL 0x00 -#define DER_TYPE_CLASS_APPLICATION 0x40 -#define DER_TYPE_CLASS_CONTEXT_SPECIFIC 0x80 -#define DER_TYPE_CLASS_PRIVATE 0xc0 - -#define DER_TYPE_TAG(type) (type & 0x1f) - -#define DER_TYPE_IS_CONSTRUCTED(type) ((type & 0x20) ? TRUE : FALSE) - -#define DER_TYPE_TAG_IS_LONG_FORM(type) (DER_TYPE_TAG(type) == 0x1f) - -#define DER_LENGTH_IS_LONG_FORM(byte) ((byte & 0x80) ? TRUE : FALSE) -#define DER_LENGTH_LONG_FORM_SIZE(byte) (byte & 0x7f) - -typedef struct { - guint8 type_class; - gboolean constructed; - guint type; - GBytes *content; - GSList *children; -} DerNodeData; - -static void der_node_data_children_list_free(GSList *children); - -static void -der_node_data_free(DerNodeData *node_data) -{ - g_return_if_fail(node_data != NULL); - - g_clear_pointer(&node_data->content, g_bytes_unref); - g_clear_pointer(&node_data->children, - der_node_data_children_list_free); - - g_free(node_data); -} - -static void -der_node_data_children_list_free(GSList *children) -{ - g_return_if_fail(children != NULL); - - g_slist_free_full(children, (GDestroyNotify)der_node_data_free); -} - -/* Parses DER encoded data into a GSList of DerNodeData instances */ -static GSList * -der_parse(GBytes *data_bytes) -{ - const guint8 *data; - gsize size = 0; - gsize offset = 0; - GSList *nodes = NULL; - DerNodeData *node = NULL; - - data = g_bytes_get_data(data_bytes, &size); - - /* Parse data */ - while (offset < size) { - guint8 byte; - gsize length; - - /* Parse type */ - - byte = *(data + offset++); - node = g_new0(DerNodeData, 1); - node->type_class = DER_TYPE_CLASS(byte); - node->constructed = DER_TYPE_IS_CONSTRUCTED(byte); - - if (DER_TYPE_TAG_IS_LONG_FORM(byte)) { - /* Long-form type encoding */ - /* TODO: Handle long-form encoding. - * Maiku: The certificates I tested didn't do this. - */ - g_return_val_if_reached(NULL); - } else { - /* Short-form type encoding */ - node->type = DER_TYPE_TAG(byte); - } - - /* Parse content length */ - - if (offset >= size) { - purple_debug_error("tls-certificate", - "Not enough remaining data when " - "parsing DER chunk length byte: " - "read (%" G_GSIZE_FORMAT ") " - "available: ""(%" G_GSIZE_FORMAT ")", - offset, size); - break; - } - - byte = *(data + offset++); - - if (DER_LENGTH_IS_LONG_FORM(byte)) { - /* Long-form length encoding */ - guint num_len_bytes = DER_LENGTH_LONG_FORM_SIZE(byte); - guint i; - - /* Guard against overflowing the integer */ - if (num_len_bytes > sizeof(guint)) { - purple_debug_error("tls-certificate", - "Number of long-form length " - "bytes greater than guint " - "size: %u > %" G_GSIZE_FORMAT, - num_len_bytes, sizeof(guint)); - break; - } - - /* Guard against reading past the end of the buffer */ - if (offset + num_len_bytes > size) { - purple_debug_error("tls-certificate", - "Not enough remaining data " - "when parsing DER chunk " - "long-form length bytes: " - "read (%" G_GSIZE_FORMAT ") " - "available: ""(%" - G_GSIZE_FORMAT ")", - offset, size); - break; - } - - length = 0; - - for (i = 0; i < num_len_bytes; ++i) { - length = length << 8; - length |= *(data + offset++); - } - } else { - /* Short-form length encoding */ - length = byte; - } - - /* Parse content */ - - if (offset + length > size) { - purple_debug_error("tls-certificate", - "Not enough remaining data when " - "parsing DER chunk content: " - "content size (%" G_GSIZE_FORMAT ") " - "available: ""(%" G_GSIZE_FORMAT ")", - length, size - offset); - break; - } - - node->content = g_bytes_new_from_bytes(data_bytes, - offset, length); - offset += length; - - /* Maybe recurse */ - if (node->constructed) { - node->children = der_parse(node->content); - - if (node->children == NULL) { - /* No children on a constructed type - * should an error. If this happens, it - * outputs debug info inside der_parse(). - */ - break; - } - } - - nodes = g_slist_append(nodes, node); - node = NULL; - } - - if (node != NULL) { - /* There was an error. Free parsing data. */ - der_node_data_free(node); - g_clear_pointer(&nodes, der_node_data_children_list_free); - /* FIXME: Report error to calling function ala GError? */ - } - - return nodes; -} - -static gchar * -der_parse_string(DerNodeData *node) -{ - const gchar *str; - gsize length = 0; - - g_return_val_if_fail(node != NULL, NULL); - g_return_val_if_fail(node->content != NULL, NULL); - - str = g_bytes_get_data(node->content, &length); - return g_strndup(str, length); -} - -typedef struct { - gchar *oid; - gchar *value; -} DerOIDValue; - -static DerOIDValue * -der_oid_value_copy(DerOIDValue *data) -{ - DerOIDValue *ret; - - g_return_val_if_fail(data != NULL, NULL); - - ret = g_new0(DerOIDValue, 1); - ret->oid = g_strdup(data->oid); - ret->value = g_strdup(data->value); - return ret; -} - -static void -der_oid_value_free(DerOIDValue *data) -{ - g_return_if_fail(data != NULL); - - g_clear_pointer(&data->oid, g_free); - g_clear_pointer(&data->value, g_free); - - g_free(data); -} - -static void -der_oid_value_slist_free(GSList *list) -{ - g_return_if_fail(list != NULL); - - g_slist_free_full(list, (GDestroyNotify)der_oid_value_free); -} - -static const gchar * -der_oid_value_slist_get_value_by_oid(GSList *list, const gchar *oid) -{ - for (; list != NULL; list = g_slist_next(list)) { - DerOIDValue *value = list->data; - - if (!strcmp(oid, value->oid)) { - return value->value; - } - } - - return NULL; -} - -static gchar * -der_parse_oid(DerNodeData *node) -{ - const gchar *oid_data; - gsize length = 0; - gsize offset = 0; - guint8 byte; - GString *ret; - - g_return_val_if_fail(node != NULL, NULL); - g_return_val_if_fail(node->content != NULL, NULL); - - oid_data = g_bytes_get_data(node->content, &length); - /* Most OIDs used for certificates aren't larger than 9 bytes */ - ret = g_string_sized_new(9); - - /* First byte is encoded as num1 * 40 + num2 */ - if (length > 0) { - byte = *(oid_data + offset++); - g_string_append_printf(ret, "%u.%u", byte / 40, byte % 40); - } - - /* Subsequent numbers are in base 128 format (the most - * significant bit being set adds another 7 bits to the number) - */ - while (offset < length) { - guint value = 0; - - do { - byte = *(oid_data + offset++); - value = (value << 7) + (byte & 0x7f); - } while (byte & 0x80 && offset < length); - - g_string_append_printf(ret, ".%u", value); - } - - return g_string_free(ret, FALSE); -} - -/* Parses X.509 Issuer and Subject name structures - * into a GSList of DerOIDValue. - */ -static GSList * -der_parse_name(DerNodeData *name_node) -{ - GSList *list; - GSList *ret = NULL; - DerOIDValue *value = NULL; - - g_return_val_if_fail(name_node != NULL, NULL); - - /* Iterate over items in the name sequence */ - list = name_node->children; - - while (list != NULL) { - DerNodeData *child_node; - GSList *child_list; - - value = g_new(DerOIDValue, 1); - - /* Each item in the name sequence is a set containing - * a sequence of an ObjectID and a String-like value - */ - - /* Get the DerNode containing set data */ - if ((child_node = g_slist_nth_data(list, 0)) == NULL) { - break; - } - - /* Get the DerNode containing its sequence data */ - if (child_node == NULL || - (child_node = g_slist_nth_data( - child_node->children, 0)) == NULL) { - break; - } - - /* Get the GSList item containing the ObjectID DerNode */ - if ((child_list = child_node->children) == NULL) { - break; - } - - /* Get the DerNode containing the ObjectID */ - if ((child_node = child_list->data) == NULL) { - break; - } - - /* Parse ObjectID */ - value->oid = der_parse_oid(child_node); - - /* Get the GSList item containing the String-like value */ - if ((child_list = g_slist_next(child_list)) == NULL) { - break; - } - - /* Get the DerNode containing the String-like value */ - if ((child_node = child_list->data) == NULL) { - break; - } - - /* Parse String-like value */ - value->value = der_parse_string(child_node); - - ret = g_slist_prepend(ret, value); - list = g_slist_next(list); - value = NULL; - } - - if (value != NULL) { - der_oid_value_free(value); - der_oid_value_slist_free(ret); - } - - return g_slist_reverse(ret); -} - -static GDateTime * -der_parse_time(DerNodeData *node) -{ - gchar *time; - gchar *c; - gint time_parts[7]; - gint time_part_idx = 0; - int length; - - g_return_val_if_fail(node != NULL, NULL); - g_return_val_if_fail(node->content != NULL, NULL); - - memset(time_parts, 0, sizeof(time_parts)); - - time = der_parse_string(node); - - /* For the purposes of X.509 - * UTCTime format is "YYMMDDhhmmssZ" (YY >= 50 ? 19YY : 20YY) and - * GeneralizedTime format is "YYYYMMDDhhmmssZ" - * According to RFC2459, they both are GMT, which is weird - * considering one is named UTC, but for the purposes of display, - * for which this is used, it shouldn't matter. - */ - - length = strlen(time); - if (length == 13) { - /* UTCTime: Skip the first part as it's calculated later */ - time_part_idx = 1; - } else if (length == 15) { - /* Generalized Time */ - /* TODO: Handle generalized time - * Maiku: None of the certificates I tested used this - */ - g_free(time); - g_return_val_if_reached(NULL); - } else { - purple_debug_error("tls-certificate", - "Unrecognized time format (length: %i)", - length); - g_free(time); - return NULL; - } - - c = time; - - while (c - time < length) { - if (*c == 'Z') { - break; - } - - if (!g_ascii_isdigit(*c) || !g_ascii_isdigit(*(c + 1))) { - purple_debug_error("tls-certificate", - "Error parsing time. next characters " - "aren't both digits: '%c%c'", - *c, *(c + 1)); - break; - } - - time_parts[time_part_idx++] = - g_ascii_digit_value(*c) * 10 + - g_ascii_digit_value(*(c + 1)); - c += 2; - } - - if (length == 13) { - if (time_parts[1] >= 50) { - time_parts[0] = 19; - } else { - time_parts[0] = 20; - } - } - - return g_date_time_new_utc( - time_parts[0] * 100 + time_parts[1], /* year */ - time_parts[2], /* month */ - time_parts[3], /* day */ - time_parts[4], /* hour */ - time_parts[5], /* minute */ - time_parts[6]); /* seconds */ -} - -/* This structure contains the data which is in an X.509 certificate. - * Only the values actually parsed/used are here. The remaining commented - * out values are informative placeholders for the remaining data that - * could be in a standard certificate. - */ -struct _PurpleTlsCertificateInfo { - GTlsCertificate *cert; - - /* version (Optional, defaults to version 1 (version = value + 1)) */ - /* serialNumber */ - /* signature */ - GSList *issuer; - GDateTime *notBefore; - GDateTime *notAfter; - GSList *subject; - /* subjectPublicKeyInfo */ - /* issuerUniqueIdentifier (Optional, requires version 2 or 3) */ - /* subjectUniqueIdentifier (Optional, requires version 2 or 3) */ - /* extensions (Optional, requires version 3) */ -}; - -/* TODO: Make better API for this? */ -PurpleTlsCertificateInfo * -purple_tls_certificate_get_info(GTlsCertificate *certificate) -{ - GByteArray *der_array = NULL; - GBytes *root; - GSList *nodes; - DerNodeData *node; - DerNodeData *cert_node; - DerNodeData *valid_node; - PurpleTlsCertificateInfo *info; - - g_return_val_if_fail(G_IS_TLS_CERTIFICATE(certificate), NULL); - - /* Get raw bytes from DER formatted certificate */ - g_object_get(certificate, "certificate", &der_array, NULL); - - /* Parse raw bytes into DerNode tree */ - root = g_byte_array_free_to_bytes(der_array); - nodes = der_parse(root); - g_bytes_unref(root); - - if (nodes == NULL) { - purple_debug_warning("tls-certificate", - "Error parsing certificate"); - return NULL; - } - - /* Set up PurpleTlsCertificateInfo struct with initial data */ - info = g_new0(PurpleTlsCertificateInfo, 1); - info->cert = g_object_ref(certificate); - - /* Get certificate root sequence GSList item */ - node = g_slist_nth_data(nodes, 0); - if (node == NULL || node->children == NULL) { - purple_debug_warning("tls-certificate", - "Error parsing certificate root node"); - purple_tls_certificate_info_free(info); - return NULL; - } - - /* Get certificate sequence GSList DerNode */ - cert_node = g_slist_nth_data(node->children, 0); - if (cert_node == NULL || cert_node->children == NULL) { - purple_debug_warning("tls-certificate", - "Error to parsing certificate node"); - purple_tls_certificate_info_free(info); - return NULL; - } - - /* Check for optional certificate version */ - - node = g_slist_nth_data(cert_node->children, 0); - if (node == NULL || node->children == NULL) { - purple_debug_warning("tls-certificate", - "Error to parsing certificate version node"); - purple_tls_certificate_info_free(info); - return NULL; - } - - if (node->type_class != DER_TYPE_CLASS_CONTEXT_SPECIFIC) { - /* Include optional version so indices work right */ - /* TODO: Actually set default version value? */ - cert_node->children = - g_slist_prepend(cert_node->children, NULL); - } - - /* Get certificate issuer */ - - node = g_slist_nth_data(cert_node->children, 3); - if (node == NULL || node->children == NULL) { - purple_debug_warning("tls-certificate", - "Error to parsing certificate issuer node"); - purple_tls_certificate_info_free(info); - return NULL; - } - - info->issuer = der_parse_name(node); - - /* Get certificate validity */ - - valid_node = g_slist_nth_data(cert_node->children, 4); - if (valid_node == NULL || valid_node->children == NULL) { - purple_debug_warning("tls-certificate", - "Error to parsing certificate validity node"); - purple_tls_certificate_info_free(info); - return NULL; - } - - /* Get certificate validity (notBefore) */ - node = g_slist_nth_data(valid_node->children, 0); - if (node == NULL) { - purple_debug_warning("tls-certificate", - "Error to parsing certificate valid " - "notBefore node"); - purple_tls_certificate_info_free(info); - return NULL; - } - - info->notBefore = der_parse_time(node); - - /* Get certificate validity (notAfter) */ - node = g_slist_nth_data(valid_node->children, 1); - if (node == NULL) { - purple_debug_warning("tls-certificate", - "Error to parsing certificate valid " - "notAfter node"); - purple_tls_certificate_info_free(info); - return NULL; - } - - info->notAfter = der_parse_time(node); - - /* Get certificate subject */ - - node = g_slist_nth_data(cert_node->children, 5); - if (node == NULL || node->children == NULL) { - purple_debug_warning("tls-certificate", - "Error to parsing certificate subject node"); - purple_tls_certificate_info_free(info); - return NULL; - } - - info->subject = der_parse_name(node); - - /* Clean up */ - der_node_data_children_list_free(nodes); - - return info; -} - -static PurpleTlsCertificateInfo * -purple_tls_certificate_info_copy(PurpleTlsCertificateInfo *info) -{ - PurpleTlsCertificateInfo *ret; - - g_return_val_if_fail(info != NULL, NULL); - - ret = g_new0(PurpleTlsCertificateInfo, 1); - ret->issuer = g_slist_copy_deep(info->issuer, - (GCopyFunc)der_oid_value_copy, NULL); - ret->notBefore = g_date_time_ref(info->notBefore); - ret->notAfter = g_date_time_ref(info->notAfter); - ret->subject = g_slist_copy_deep(info->subject, - (GCopyFunc)der_oid_value_copy, NULL); - - return ret; -} - -void -purple_tls_certificate_info_free(PurpleTlsCertificateInfo *info) -{ - g_return_if_fail(info != NULL); - - g_clear_object(&info->cert); - - g_clear_pointer(&info->issuer, der_oid_value_slist_free); - g_clear_pointer(&info->notBefore, g_date_time_unref); - g_clear_pointer(&info->notAfter, g_date_time_unref); - g_clear_pointer(&info->subject, der_oid_value_slist_free); - - g_free(info); -} - -G_DEFINE_BOXED_TYPE(PurpleTlsCertificateInfo, purple_tls_certificate_info, - purple_tls_certificate_info_copy, - purple_tls_certificate_info_free); - -/* Looks up the relative distinguished name (RDN) from an ObjectID */ -static const gchar * -lookup_rdn_name_by_oid(const gchar *oid) -{ - static GHashTable *ht = NULL; - - if (G_UNLIKELY(ht == NULL)) { - ht = g_hash_table_new_full(g_str_hash, g_str_equal, - NULL, NULL); - - /* commonName */ - g_hash_table_insert(ht, "2.5.4.3", "CN"); - /* countryName */ - g_hash_table_insert(ht, "2.5.4.6", "C"); - /* localityName */ - g_hash_table_insert(ht, "2.5.4.7", "L"); - /* stateOrProvinceName */ - g_hash_table_insert(ht, "2.5.4.8", "ST"); - /* organizationName */ - g_hash_table_insert(ht, "2.5.4.10", "O"); - /* organizationalUnitName */ - g_hash_table_insert(ht, "2.5.4.11", "OU"); - } - - return g_hash_table_lookup(ht, oid); -} - -/* Makes a distinguished name (DN) from - * a list of relative distinguished names (RDN). - * Order matters. - */ -static gchar * -make_dn_from_oid_value_slist(GSList *list) -{ - GString *str = g_string_new(NULL); - - for (; list != NULL; list = g_slist_next(list)) { - DerOIDValue *value = list->data; - const gchar *name; - gchar *new_value; - - if (value == NULL) { - purple_debug_error("tls-certificate", - "DerOIDValue data missing from GSList"); - continue; - } - - name = lookup_rdn_name_by_oid(value->oid); - /* Escape commas in value as that's the DN separator */ - new_value = purple_strreplace(value->value, ",", "\\,"); - g_string_append_printf(str, "%s=%s,", name, new_value); - g_free(new_value); - } - - /* Remove trailing comma */ - g_string_truncate(str, str->len - 1); - - return g_string_free(str, FALSE); -} - -static gchar * -purple_tls_certificate_info_get_issuer_dn(PurpleTlsCertificateInfo *info) -{ - g_return_val_if_fail(info != NULL, NULL); - g_return_val_if_fail(info->issuer != NULL, NULL); - - return make_dn_from_oid_value_slist(info->issuer); -} - -gchar * -purple_tls_certificate_info_get_display_string(PurpleTlsCertificateInfo *info) -{ - gchar *subject_name; - gchar *issuer_name = NULL; - GByteArray *sha1_bytes; - gchar *sha1_str = NULL; - gchar *activation_time; - gchar *expiration_time; - gchar *ret; - - g_return_val_if_fail(info != NULL, NULL); - - /* Getting the commonName of a CA supposedly doesn't work, but we - * shouldn't be dealing with those here anyway. - */ - subject_name = purple_tls_certificate_info_get_subject_name(info); - - issuer_name = purple_tls_certificate_info_get_issuer_dn(info); - - sha1_bytes = purple_tls_certificate_get_fingerprint_sha1(info->cert); - if (sha1_bytes != NULL) { - sha1_str = purple_base16_encode_chunked(sha1_bytes->data, - sha1_bytes->len); - g_byte_array_unref(sha1_bytes); - } - - activation_time = g_date_time_format(info->notBefore, "%c"); - expiration_time = g_date_time_format(info->notAfter, "%c"); - - ret = g_strdup_printf( - _("Common name: %s\n\n" - "Issued by: %s\n\n" - "Fingerprint (SHA1): %s\n\n" - "Activation date: %s\n" - "Expiriation date: %s\n"), - subject_name, - issuer_name, - sha1_str, - activation_time, - expiration_time); - - g_free(subject_name); - g_free(issuer_name); - g_free(sha1_str); - g_free(activation_time); - g_free(expiration_time); - - return ret; -} - -/* TODO: Make better API for this? */ -gchar * -purple_tls_certificate_info_get_subject_name(PurpleTlsCertificateInfo *info) -{ - g_return_val_if_fail(info != NULL, NULL); - g_return_val_if_fail(info->subject != NULL, NULL); - - /* commonName component of the subject */ - return g_strdup(der_oid_value_slist_get_value_by_oid(info->subject, - "2.5.4.3")); -} - -/* TODO: Make better API for this? */ -GByteArray * -purple_tls_certificate_get_fingerprint_sha1(GTlsCertificate *certificate) -{ - GChecksum *hash; - GByteArray *der = NULL; - guint8 *data = NULL; - gsize buf_size = 0; - - g_return_val_if_fail(G_IS_TLS_CERTIFICATE(certificate), NULL); - - g_object_get(certificate, "certificate", &der, NULL); - - g_return_val_if_fail(der != NULL, NULL); - - hash = g_checksum_new(G_CHECKSUM_SHA1); - - buf_size = g_checksum_type_get_length(G_CHECKSUM_SHA1); - data = g_malloc(buf_size); - - g_checksum_update(hash, der->data, der->len); - g_byte_array_unref(der); - - g_checksum_get_digest(hash, data, &buf_size); - g_checksum_free(hash); - - return g_byte_array_new_take(data, buf_size); -} -
--- a/libpurple/tls-certificate-info.h Thu Nov 22 11:25:59 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,115 +0,0 @@ -/* - * - * purple - * - * Purple is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#ifndef _PURPLE_TLS_CERTIFICATE_INFO_H -#define _PURPLE_TLS_CERTIFICATE_INFO_H -/** - * SECTION:tls-certificate-info - * @section_id: libpurple-tls-certificate-info - * @short_description: TLS certificate information parsing - * @title: TLS Certificate Info API - * - * The TLS certificate info API provides information parsing functions - * for #GTlsCertificate's. This information can then be presented to the - * user, usually to help them decide whether or not to trust a given - * certificate. - */ - -#include <gio/gio.h> - -/** - * PurpleTlsCertificateInfo - * - * An opaque structure to contain parsed certificate info, which - * can subsequently be accessed by purple_tls_certificate_info_* - * functions. - */ -typedef struct _PurpleTlsCertificateInfo PurpleTlsCertificateInfo; - -#define PURPLE_TYPE_TLS_CERTIFICATE_INFO \ - (purple_tls_certificate_info_get_type()) - -/** - * purple_tls_certificate_info_get_type: - * - * Returns: The #GType for the #PurpleTlsCertificateInfo boxed structure. - */ -GType purple_tls_certificate_info_get_type(void); - -/** - * purple_tls_certificate_get_info: - * @certificate: Certificate from which to parse the info - * - * Returns a #PurpleTlsCertificateInfo containing parsed information - * of the certificate. - * - * Returns: #PurpleTlsCertificateInfo parsed from the certificate - */ -PurpleTlsCertificateInfo * -purple_tls_certificate_get_info(GTlsCertificate *certificate); - -/** - * purple_tls_certificate_info_free: - * @info: #PurpleTlsCertificateInfo object to free - * - * Frees @info. - */ -void -purple_tls_certificate_info_free(PurpleTlsCertificateInfo *info); - -/** - * purple_tls_certificate_info_get_display_string: - * @info: #PurpleTlsCertificateInfo from which to generate a display string - * - * Generates a user readable string to display information from @info - * - * Returns: A user readable string suitable to display to the user - */ -gchar * -purple_tls_certificate_info_get_display_string(PurpleTlsCertificateInfo *info); - -/** - * purple_tls_certificate_get_subject_name: - * @certificate: Certificate from which to get the subject name - * - * Returns the common subject name of the cert - * - * Returns: The subject name of the cert - */ -gchar * -purple_tls_certificate_info_get_subject_name(PurpleTlsCertificateInfo *info); - -/** - * purple_tls_certificate_get_fingerprint_sha1: - * @certificate: Certificate from which to get the SHA1 fingerprint - * - * Returns the SHA1 fingerprint of the cert - * - * Returns: (transfer full): The SHA1 fingerprint of the cert - */ -GByteArray * -purple_tls_certificate_get_fingerprint_sha1(GTlsCertificate *certificate); - -G_END_DECLS - -#endif /* _PURPLE_TLS_CERTIFICATE_INFO_H */
--- a/libpurple/tls-certificate.c Thu Nov 22 11:25:59 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,390 +0,0 @@ -/* - * - * purple - * - * Purple is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#include "internal.h" -#include "tls-certificate.h" -#include "debug.h" -#include "util.h" - -/* Makes a filename path for a certificate. If id is NULL, - * just return the directory - */ -static gchar * -make_certificate_path(const gchar *id) -{ - return g_build_filename(purple_data_dir(), - "certificates", "tls", - id != NULL ? purple_escape_filename(id) : NULL, - NULL); -} - -/* Creates the certificate directory if it doesn't exist, - * returns TRUE if it's successful or it already exists, - * returns FALSE if there was an error. - */ -static gboolean -ensure_certificate_dir(GError **error) -{ - gchar *dir = make_certificate_path(NULL); - gboolean ret = TRUE; - - if (purple_build_dir(dir, 0700) != 0) { - g_set_error_literal(error, G_FILE_ERROR, - g_file_error_from_errno(errno), - g_strerror(errno)); - ret = FALSE; - } - - g_free(dir); - return ret; -} - -GList * -purple_tls_certificate_list_ids() -{ - gchar *dir_path; - GDir *dir; - const gchar *entry; - GList *idlist = NULL; - GError *error = NULL; - - /* Ensure certificate directory exists */ - - if (!ensure_certificate_dir(&error)) { - purple_debug_error("tls-certificate", - "Error creating certificate directory: %s", - error->message); - g_clear_error(&error); - return NULL; - } - - /* Open certificate directory */ - - dir_path = make_certificate_path(NULL); - dir = g_dir_open(dir_path, 0, &error); - - if (dir == NULL) { - purple_debug_error("tls-certificate", - "Error opening certificate directory (%s): %s", - dir_path, error->message); - g_free(dir_path); - g_clear_error(&error); - return NULL; - } - - g_free(dir_path); - - /* Traverse the directory listing and create an idlist */ - - while ((entry = g_dir_read_name(dir)) != NULL) { - /* Unescape the filename - * (GLib owns original string) - */ - const char *unescaped = purple_unescape_filename(entry); - - /* Copy the entry name into our list - * (Purple own the escaped string) - */ - idlist = g_list_prepend(idlist, g_strdup(unescaped)); - } - - g_dir_close(dir); - - return idlist; -} - -void -purple_tls_certificate_free_ids(GList *ids) -{ - g_list_free_full(ids, g_free); -} - -GTlsCertificate * -purple_tls_certificate_new_from_id(const gchar *id, GError **error) -{ - GTlsCertificate *cert; - gchar *path; - - g_return_val_if_fail(id != NULL && id[0] != '\0', NULL); - - /* Load certificate from file if it exists */ - - path = make_certificate_path(id); - cert = g_tls_certificate_new_from_file(path, error); - g_free(path); - - return cert; -} - -gboolean -purple_tls_certificate_trust(const gchar *id, GTlsCertificate *certificate, - GError **error) -{ - gchar *path; - gchar *pem = NULL; - gboolean ret; - - g_return_val_if_fail(id != NULL && id[0] != '\0', FALSE); - g_return_val_if_fail(G_IS_TLS_CERTIFICATE(certificate), FALSE); - - /* Ensure certificate directory exists */ - - if (!ensure_certificate_dir(error)) { - return FALSE; - } - - /* Get the text representation of the certificate */ - - g_object_get(certificate, "certificate-pem", &pem, NULL); - g_return_val_if_fail(pem != NULL, FALSE); - - /* Save certificate text to a fail */ - - path = make_certificate_path(id); - ret = g_file_set_contents(path, pem, -1, error); - g_free(path); - g_free(pem); - - return ret; -} - -gboolean -purple_tls_certificate_distrust(const gchar *id, GError **error) -{ - gchar *path; - gboolean ret = TRUE; - - g_return_val_if_fail(id != NULL && id[0] != '\0', FALSE); - - /* Delete certificate file if it exists */ - - path = make_certificate_path(id); - - if (g_unlink(path) != 0) { - g_set_error_literal(error, G_FILE_ERROR, - g_file_error_from_errno(errno), - g_strerror(errno)); - ret = FALSE; - } - - g_free(path); - - return ret; -} - -/* Converts GTlsCertificateFlags to a translated string representation - * of the first set error flag in the order checked - */ -static const gchar * -tls_certificate_flags_to_reason(GTlsCertificateFlags flags) -{ - if (flags & G_TLS_CERTIFICATE_UNKNOWN_CA) { - return _("The certificate is not trusted because no " - "certificate that can verify it is " - "currently trusted."); - } else if (flags & G_TLS_CERTIFICATE_BAD_IDENTITY) { - /* Translators: "domain" refers to a DNS domain - * (e.g. talk.google.com) - */ - return _("The certificate presented is not issued to " - "this domain."); - } else if (flags & G_TLS_CERTIFICATE_NOT_ACTIVATED) { - return _("The certificate is not valid yet. Check that your " - "computer's date and time are accurate."); - } else if (flags & G_TLS_CERTIFICATE_EXPIRED) { - return _("The certificate has expired and should not be " - "considered valid. Check that your " - "computer's date and time are accurate."); - } else if (flags & G_TLS_CERTIFICATE_REVOKED) { - return _("The certificate has been revoked."); - } else if (flags & G_TLS_CERTIFICATE_INSECURE) { - return _("The certificate's algorithm is considered insecure."); - } else { - /* Also catches G_TLS_CERTIFICATE_GENERIC_ERROR here */ - return _("An unknown certificate error occurred."); - } -} - -/* Holds data for requesting the user to accept a given certificate */ -typedef struct { - gchar *identity; - GTlsCertificate *cert; -} UserCertRequestData; - -static void -user_cert_request_data_free(UserCertRequestData *data) -{ - g_return_if_fail(data != NULL); - - g_free(data->identity); - g_object_unref(data->cert); - - g_free(data); -} - -static void -user_cert_request_accept_cb(UserCertRequestData *data) -{ - GError *error = NULL; - - g_return_if_fail(data != NULL); - - /* User accepted. Trust this certificate */ - if(!purple_tls_certificate_trust(data->identity, data->cert, &error)) { - purple_debug_error("tls-certificate", - "Error trusting certificate '%s': %s", - data->identity, error->message); - g_clear_error(&error); - } - - user_cert_request_data_free(data); -} - -static void -user_cert_request_deny_cb(UserCertRequestData *data) -{ - /* User denied. Free data related to the requst */ - user_cert_request_data_free(data); -} - -/* Prompts the user to accept the certificate as it failed due to the - * passed errors. - */ -static void -request_accept_certificate(const gchar *identity, GTlsCertificate *peer_cert, - GTlsCertificateFlags errors) -{ - UserCertRequestData *data; - gchar *primary; - - g_return_if_fail(identity != NULL && identity[0] != '\0'); - g_return_if_fail(G_IS_TLS_CERTIFICATE(peer_cert)); - g_return_if_fail(errors != 0); - - data = g_new(UserCertRequestData, 1); - data->identity = g_strdup(identity); - data->cert = g_object_ref(peer_cert); - - primary = g_strdup_printf(_("Accept certificate for %s?"), identity); - purple_request_certificate(data, - _("TLS Certificate Verification"), - primary, - tls_certificate_flags_to_reason(errors), - data->cert, - _("Accept"), G_CALLBACK(user_cert_request_accept_cb), - _("Reject"), G_CALLBACK(user_cert_request_deny_cb), - data); - g_free(primary); -} - -/* Called when a GTlsConnection (which this handler has been connected to) - * has an error validating its certificate. - * Returns TRUE if the certificate is already trusted, so the connection - * can continue. - * Returns FALSE if the certificate is not trusted, causing the - * connection's handshake to fail, and then prompts the user to accept - * the certificate. - */ -static gboolean -accept_certificate_cb(GTlsConnection *conn, GTlsCertificate *peer_cert, - GTlsCertificateFlags errors, gpointer user_data) -{ - GTlsCertificate *trusted_cert; - GSocketConnectable *connectable; - const gchar *identity; - - g_return_val_if_fail(G_IS_TLS_CLIENT_CONNECTION(conn), FALSE); - g_return_val_if_fail(G_IS_TLS_CERTIFICATE(peer_cert), FALSE); - - /* Get the certificate identity from the GTlsClientConnection */ - - connectable = g_tls_client_connection_get_server_identity( - G_TLS_CLIENT_CONNECTION(conn)); - - g_return_val_if_fail(G_IS_SOCKET_CONNECTABLE(connectable), FALSE); - - /* identity is owned by the connectable */ - if (G_IS_NETWORK_ADDRESS(connectable)) { - identity = g_network_address_get_hostname( - G_NETWORK_ADDRESS(connectable)); - } else if (G_IS_NETWORK_SERVICE(connectable)) { - identity = g_network_service_get_domain( - G_NETWORK_SERVICE(connectable)); - } else { - g_return_val_if_reached(FALSE); - } - - /* See if a trusted certificate matching the peer certificate exists */ - - trusted_cert = purple_tls_certificate_new_from_id(identity, NULL); - - if (trusted_cert != NULL && - g_tls_certificate_is_same(peer_cert, trusted_cert)) { - /* It's manually trusted. Accept certificate */ - g_object_unref(trusted_cert); - return TRUE; - } - - g_clear_object(&trusted_cert); - - /* Certificate failed and isn't trusted. - * Fail certificate and prompt user. - */ - - request_accept_certificate(identity, peer_cert, errors); - - return FALSE; -} - -gpointer -purple_tls_certificate_attach_to_tls_connection(GTlsConnection *conn) -{ - return g_object_connect(conn, "signal::accept-certificate", - accept_certificate_cb, NULL, NULL); -} - -/* Called when GSocketClient signals an event. - * Calls purple_tls_certificate_attach_to_tls_connection() on the client's - * connection when it's about to handshake. - */ -static void -socket_client_event_cb(GSocketClient *client, GSocketClientEvent event, - GSocketConnectable *connectable, GIOStream *connection, - gpointer user_data) -{ - if (event == G_SOCKET_CLIENT_TLS_HANDSHAKING) { - /* Attach libpurple's certificate subsystem to the - * GTlsConnection right before it starts the handshake - */ - purple_tls_certificate_attach_to_tls_connection( - G_TLS_CONNECTION(connection)); - } -} - -gpointer -purple_tls_certificate_attach_to_socket_client(GSocketClient *client) -{ - return g_object_connect(client, "signal::event", - socket_client_event_cb, NULL, NULL); -} -
--- a/libpurple/tls-certificate.h Thu Nov 22 11:25:59 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,134 +0,0 @@ -/* - * - * purple - * - * Purple is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#ifndef _PURPLE_TLS_CERTIFICATE_H -#define _PURPLE_TLS_CERTIFICATE_H -/** - * SECTION:tls-certificate - * @section_id: libpurple-tls-certificate - * @short_description: TLS certificate trust and storage API - * @title: TLS Certificate API - * - * The TLS Certificate API provides functions for trusting and storing - * certificates for use with TLS/SSL connections. This allows certificates, - * which aren't considered valid by the TLS implementation, to be manually - * trusted by the user, distrusted at a later time, and queried by the UI. - * It also provides functions to simply wire this system into Gio. - */ - -#include <gio/gio.h> - -/** - * purple_tls_certificate_list_ids: - * - * Returns a list of the IDs for certificates trusted with - * purple_tls_certificate_trust() and friends. These IDs can then be passed - * to purple_tls_certificate_new_from_id() or used directly, if desired. - * - * Returns: (transfer full) (element-type utf8): #GList of IDs described above - * Free with purple_tls_certificate_free_ids() - */ -GList * -purple_tls_certificate_list_ids(void); - -/** - * purple_tls_certificate_free_ids: - * @ids: (transfer full) (element-type utf8): List of ids retrieved from - * purple_tls_certificate_list_ids() - * - * Frees the list of IDs returned from purple_tls_certificate_list_ids(). - */ -void -purple_tls_certificate_free_ids(GList *ids); - -/** - * purple_tls_certificate_new_from_id: - * @id: ID of certificate to load - * @error: A GError location to store the error occurring, or NULL to ignore - * - * Loads the certificate referenced by ID into a #GTlsCertificate object. - * - * Returns: (transfer full): #GTlsCertificate loaded from ID - */ -GTlsCertificate * -purple_tls_certificate_new_from_id(const gchar *id, GError **error); - -/** - * purple_tls_certificate_trust: - * @id: ID to associate with the certificate - * @certificate: Certificate to trust for TLS operations - * @error: A GError location to store the error occurring, or NULL to ignore - * - * Trusts the certificate to be allowed for TLS operations even if - * it would otherwise fail. - * - * Returns: #TRUE on success, #FALSE otherwise - */ -gboolean -purple_tls_certificate_trust(const gchar *id, GTlsCertificate *certificate, - GError **error); - -/** - * purple_tls_certificate_distrust: - * @id: ID associated with the certificate to distrust - * @error: A GError location to store the error occurring, or NULL to ignore - * - * Revokes full trust of certificate. The certificate will be accepted - * in TLS operations only if it passes normal validation. - * - * Returns: #TRUE on success, #FALSE otherwise - */ -gboolean -purple_tls_certificate_distrust(const gchar *id, GError **error); - - -/** - * purple_tls_certificate_attach_to_tls_connection: - * @conn: #GTlsConnection to connect to - * - * Connects the Purple TLS certificate subsystem to @conn so it will accept - * certificates trusted by purple_tls_certificate_trust() and friends. - * - * Returns: (transfer none) (type GObject.Object): @conn, similar to - * g_object_connect() - */ -gpointer -purple_tls_certificate_attach_to_tls_connection(GTlsConnection *conn); - -/** - * purple_tls_certificate_attach_to_socket_client: - * @client: #GSocketClient to connect to - * - * Connects the Purple TLS certificate subsystem to @client so any TLS - * connections it creates will accept certificates trusted by - * purple_tls_certificate_trust() and friends. - * - * Returns: (transfer none) (type GObject.Object): @client, similar to - * g_object_connect() - */ -gpointer -purple_tls_certificate_attach_to_socket_client(GSocketClient *client); - -G_END_DECLS - -#endif /* _PURPLE_TLS_CERTIFICATE_H */
--- a/libpurple/util.c Thu Nov 22 11:25:59 2018 +0200 +++ b/libpurple/util.c Fri Nov 30 02:50:38 2018 +0000 @@ -3333,12 +3333,6 @@ /************************************************************************** * String Functions **************************************************************************/ -gboolean -purple_strequal(const gchar *left, const gchar *right) -{ - return (g_strcmp0(left, right) == 0); -} - const char * purple_normalize(const PurpleAccount *account, const char *str) {
--- a/libpurple/util.h Thu Nov 22 11:25:59 2018 +0200 +++ b/libpurple/util.h Fri Nov 30 02:50:38 2018 +0000 @@ -1107,7 +1107,11 @@ * * Returns: %TRUE if the strings are the same, else %FALSE. */ -gboolean purple_strequal(const gchar *left, const gchar *right); +static inline gboolean +purple_strequal(const gchar *left, const gchar *right) +{ + return (g_strcmp0(left, right) == 0); +} /** * purple_normalize:
--- a/meson.build Thu Nov 22 11:25:59 2018 +0200 +++ b/meson.build Fri Nov 30 02:50:38 2018 +0000 @@ -295,7 +295,6 @@ # # Check for GTK+ 2.18 and other things used by the GTK UI # ####################################################################### enable_gestures = get_option('gestures') -enable_gcr = get_option('gcr') # ####################################################################### # Check Pidgin dependencies @@ -322,24 +321,7 @@ else enchant = [] endif - - ####################################################################### - # Check for GCR for its certificate widgets - ####################################################################### - if enable_gcr - GCR = dependency('gcr-3', required : force_deps) - if GCR.found() - conf.set('ENABLE_GCR', true) - else - enable_gcr = false - endif - else - GCR = [] - endif - - else # GTK - enable_gcr = false enable_enchant = false endif # GTK @@ -1104,7 +1086,6 @@ message('Has you....................... : yes') message('') message('Build with Enchant support.... : ' + enable_enchant.to_string()) -message('Build with GCR widgets........ : ' + enable_gcr.to_string()) message('Build Unity integration plugin.: ' + enable_unity.to_string()) message('') message('Build with KWallet............ : ' + enable_kwallet.to_string())
--- a/meson_options.txt Thu Nov 22 11:25:59 2018 +0200 +++ b/meson_options.txt Fri Nov 30 02:50:38 2018 +0000 @@ -29,9 +29,6 @@ option('gestures', type : 'boolean', value : true, description : 'compile with the gestures plugin') -option('gcr', type : 'boolean', value : false, - description : 'compile with GCR certificate widgets') - option('gstreamer', type : 'boolean', value : true, description : 'compile with GStreamer audio support')
--- a/pidgin/gtkaccount.c Thu Nov 22 11:25:59 2018 +0200 +++ b/pidgin/gtkaccount.c Fri Nov 30 02:50:38 2018 +0000 @@ -1350,7 +1350,11 @@ if (purple_accounts_get_all() == NULL) { /* We're adding our first account. Be polite and show the buddy list */ - purple_blist_set_visible(TRUE); + PidginBuddyList *blist = + pidgin_blist_get_default_gtk_blist(); + if (blist != NULL && blist->window != NULL) { + gtk_window_present(GTK_WINDOW(blist->window)); + } } account = purple_account_new(username, dialog->protocol_id);
--- a/pidgin/gtkblist.c Thu Nov 22 11:25:59 2018 +0200 +++ b/pidgin/gtkblist.c Fri Nov 30 02:50:38 2018 +0000 @@ -40,7 +40,6 @@ #include "gtkaccount.h" #include "gtkblist.h" #include "gtkcellrendererexpander.h" -#include "gtkcertmgr.h" #include "gtkconv.h" #include "gtkdialogs.h" #include "gtkxfer.h" @@ -246,59 +245,37 @@ return TRUE; } -static gboolean gtk_blist_configure_cb(GtkWidget *w, GdkEventConfigure *event, gpointer data) -{ - /* unfortunately GdkEventConfigure ignores the window gravity, but * - * the only way we have of setting the position doesn't. we have to * - * call get_position because it does pay attention to the gravity. * - * this is inefficient and I agree it sucks, but it's more likely * - * to work correctly. - Robot101 */ - gint x, y; - - /* check for visibility because when we aren't visible, this will * - * give us bogus (0,0) coordinates. - xOr */ - if (gtk_widget_get_visible(w)) - gtk_window_get_position(GTK_WINDOW(w), &x, &y); - else - return FALSE; /* carry on normally */ - -#ifdef _WIN32 - /* Workaround for GTK+ bug # 169811 - "configure_event" is fired - * when the window is being maximized */ - if (PIDGIN_WINDOW_MAXIMIZED(w)) - return FALSE; -#endif - - /* don't save if nothing changed */ - if (x == purple_prefs_get_int(PIDGIN_PREFS_ROOT "/blist/x") && - y == purple_prefs_get_int(PIDGIN_PREFS_ROOT "/blist/y") && - event->width == purple_prefs_get_int(PIDGIN_PREFS_ROOT "/blist/width") && - event->height == purple_prefs_get_int(PIDGIN_PREFS_ROOT "/blist/height")) { - - return FALSE; /* carry on normally */ - } - - /* don't save off-screen positioning */ - if (x + event->width < 0 || - y + event->height < 0 || - x > gdk_screen_width() || - y > gdk_screen_height()) { - - return FALSE; /* carry on normally */ - } +static void +gtk_blist_hide_cb(GtkWidget *widget, gpointer data) +{ + purple_signal_emit(pidgin_blist_get_handle(), + "gtkblist-hiding", gtkblist); +} + +static void +gtk_blist_show_cb(GtkWidget *widget, gpointer data) +{ + purple_signal_emit(pidgin_blist_get_handle(), + "gtkblist-unhiding", gtkblist); +} + +static void +gtk_blist_size_allocate_cb(GtkWidget *widget, GtkAllocation *allocation, + gpointer data) +{ + int new_width; + int new_height; /* ignore changes when maximized */ - if(purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/list_maximized")) - return FALSE; - - /* store the position */ - purple_prefs_set_int(PIDGIN_PREFS_ROOT "/blist/x", x); - purple_prefs_set_int(PIDGIN_PREFS_ROOT "/blist/y", y); - purple_prefs_set_int(PIDGIN_PREFS_ROOT "/blist/width", event->width); - purple_prefs_set_int(PIDGIN_PREFS_ROOT "/blist/height", event->height); - - /* continue to handle event normally */ - return FALSE; + if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/list_maximized")) { + return; + } + + gtk_window_get_size(GTK_WINDOW(widget), &new_width, &new_height); + + /* store the size */ + purple_prefs_set_int(PIDGIN_PREFS_ROOT "/blist/width", new_width); + purple_prefs_set_int(PIDGIN_PREFS_ROOT "/blist/height", new_height); } static void gtk_blist_menu_info_cb(GtkWidget *w, PurpleBuddy *b) @@ -3651,7 +3628,6 @@ /* Tools */ { "ToolsMenu", NULL, N_("_Tools"), NULL, NULL, NULL }, { "BuddyPounces", NULL, N_("Buddy _Pounces"), NULL, NULL, pidgin_pounces_manager_show }, - { "Certificates", NULL, N_("_Certificates"), NULL, NULL, pidgin_certmgr_show }, { "CustomSmileys", PIDGIN_STOCK_TOOLBAR_SMILEY, N_("Custom Smile_ys"), "<control>Y", NULL, pidgin_smiley_manager_show }, { "Plugins", PIDGIN_STOCK_TOOLBAR_PLUGINS, N_("Plu_gins"), "<control>U", NULL, pidgin_plugin_dialog_show }, { "Preferences", GTK_STOCK_PREFERENCES, N_("Pr_eferences"), "<control>P", NULL, pidgin_prefs_show }, @@ -3711,7 +3687,6 @@ "</menu>" "<menu action='ToolsMenu'>" "<menuitem action='BuddyPounces'/>" - "<menuitem action='Certificates'/>" "<menuitem action='CustomSmileys'/>" "<menuitem action='Plugins'/>" "<menuitem action='Preferences'/>" @@ -4464,35 +4439,21 @@ return text; } -static void pidgin_blist_restore_position(void) -{ - int blist_x, blist_y, blist_width, blist_height; +static void pidgin_blist_restore_window_state(void) +{ + int blist_width, blist_height; blist_width = purple_prefs_get_int(PIDGIN_PREFS_ROOT "/blist/width"); - /* if the window exists, is hidden, we're saving positions, and the - * position is sane... */ + /* if the window exists, is hidden, we're saving sizes, and the + * size is sane... */ if (gtkblist && gtkblist->window && !gtk_widget_get_visible(gtkblist->window) && blist_width != 0) { - blist_x = purple_prefs_get_int(PIDGIN_PREFS_ROOT "/blist/x"); - blist_y = purple_prefs_get_int(PIDGIN_PREFS_ROOT "/blist/y"); blist_height = purple_prefs_get_int(PIDGIN_PREFS_ROOT "/blist/height"); - /* ...check position is on screen... */ - if (blist_x >= gdk_screen_width()) - blist_x = gdk_screen_width() - 100; - else if (blist_x + blist_width < 0) - blist_x = 100; - - if (blist_y >= gdk_screen_height()) - blist_y = gdk_screen_height() - 100; - else if (blist_y + blist_height < 0) - blist_y = 100; - - /* ...and move it back. */ - gtk_window_move(GTK_WINDOW(gtkblist->window), blist_x, blist_y); - gtk_window_resize(GTK_WINDOW(gtkblist->window), blist_width, blist_height); + gtk_window_set_default_size(GTK_WINDOW(gtkblist->window), + blist_width, blist_height); if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/list_maximized")) gtk_window_maximize(GTK_WINDOW(gtkblist->window)); } @@ -5808,7 +5769,12 @@ gtk_container_add(GTK_CONTAINER(gtkblist->window), gtkblist->main_vbox); g_signal_connect(G_OBJECT(gtkblist->window), "delete_event", G_CALLBACK(gtk_blist_delete_cb), NULL); - g_signal_connect(G_OBJECT(gtkblist->window), "configure_event", G_CALLBACK(gtk_blist_configure_cb), NULL); + g_signal_connect(G_OBJECT(gtkblist->window), "hide", + G_CALLBACK(gtk_blist_hide_cb), NULL); + g_signal_connect(G_OBJECT(gtkblist->window), "show", + G_CALLBACK(gtk_blist_show_cb), NULL); + g_signal_connect(G_OBJECT(gtkblist->window), "size-allocate", + G_CALLBACK(gtk_blist_size_allocate_cb), NULL); g_signal_connect(G_OBJECT(gtkblist->window), "visibility_notify_event", G_CALLBACK(gtk_blist_visibility_cb), NULL); g_signal_connect(G_OBJECT(gtkblist->window), "window_state_event", G_CALLBACK(gtk_blist_window_state_cb), NULL); g_signal_connect(G_OBJECT(gtkblist->window), "key_press_event", G_CALLBACK(gtk_blist_window_key_press_cb), gtkblist); @@ -6051,7 +6017,7 @@ /* OK... let's show this bad boy. */ pidgin_blist_refresh(list); - pidgin_blist_restore_position(); + pidgin_blist_restore_window_state(); gtk_widget_show_all(GTK_WIDGET(gtkblist->vbox)); gtk_widget_realize(GTK_WIDGET(gtkblist->window)); purple_blist_set_visible(purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/list_visible")); @@ -6935,14 +6901,9 @@ return; if (show) { - if(!PIDGIN_WINDOW_ICONIFIED(gtkblist->window) && - !gtk_widget_get_visible(gtkblist->window)) - purple_signal_emit(pidgin_blist_get_handle(), "gtkblist-unhiding", gtkblist); - pidgin_blist_restore_position(); - gtk_window_present(GTK_WINDOW(gtkblist->window)); + gtk_widget_show(gtkblist->window); } else { if(visibility_manager_count) { - purple_signal_emit(pidgin_blist_get_handle(), "gtkblist-hiding", gtkblist); gtk_widget_hide(gtkblist->window); } else { if (!gtk_widget_get_visible(gtkblist->window)) @@ -7567,8 +7528,6 @@ purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/blist/list_visible", FALSE); purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/blist/list_maximized", FALSE); purple_prefs_add_string(PIDGIN_PREFS_ROOT "/blist/sort_type", "alphabetical"); - purple_prefs_add_int(PIDGIN_PREFS_ROOT "/blist/x", 0); - purple_prefs_add_int(PIDGIN_PREFS_ROOT "/blist/y", 0); purple_prefs_add_int(PIDGIN_PREFS_ROOT "/blist/width", 250); /* Golden ratio, baby */ purple_prefs_add_int(PIDGIN_PREFS_ROOT "/blist/height", 405); /* Golden ratio, baby */ purple_prefs_add_string(PIDGIN_PREFS_ROOT "/blist/theme", "");
--- a/pidgin/gtkcertmgr.c Thu Nov 22 11:25:59 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,663 +0,0 @@ -/* pidgin - * - * Pidgin is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - * - */ - -#include "internal.h" -#include "core.h" -#include "pidgin.h" -#include "pidginstock.h" - -#include "debug.h" -#include "notify.h" -#include "request.h" -#include "tls-certificate.h" -#include "tls-certificate-info.h" - -#include "gtk3compat.h" -#include "gtkblist.h" -#include "gtkutils.h" - -#include "gtkcertmgr.h" - -/***************************************************************************** - * X.509 certificate management interface * - *****************************************************************************/ - -typedef struct { - GtkWidget *mgmt_widget; - GtkTreeView *listview; - GtkTreeSelection *listselect; - GtkWidget *importbutton; - GtkWidget *exportbutton; - GtkWidget *infobutton; - GtkWidget *deletebutton; -} tls_peers_mgmt_data; - -tls_peers_mgmt_data *tpm_dat = NULL; - -/* Columns - See http://developer.gnome.org/doc/API/2.0/gtk/TreeWidget.html */ -enum -{ - TPM_HOSTNAME_COLUMN, - TPM_N_COLUMNS -}; - -static void -tls_peers_mgmt_destroy(GtkWidget *mgmt_widget, gpointer data) -{ - purple_debug_info("certmgr", - "tls peers self-destructs\n"); - - purple_signals_disconnect_by_handle(tpm_dat); - purple_request_close_with_handle(tpm_dat); - g_free(tpm_dat); tpm_dat = NULL; -} - -static void -tls_peers_mgmt_repopulate_list(void) -{ - GtkTreeView *listview = tpm_dat->listview; - GList *idlist, *l; - - GtkListStore *store = GTK_LIST_STORE( - gtk_tree_view_get_model(GTK_TREE_VIEW(listview))); - - /* First, delete everything in the list */ - gtk_list_store_clear(store); - - /* Grab the available certificates */ - idlist = purple_tls_certificate_list_ids(); - - /* Populate the listview */ - for (l = idlist; l; l = l->next) { - GtkTreeIter iter; - gtk_list_store_append(store, &iter); - - gtk_list_store_set(GTK_LIST_STORE(store), &iter, - TPM_HOSTNAME_COLUMN, l->data, - -1); - } - - purple_tls_certificate_free_ids(idlist); -} - -static void -tls_peers_mgmt_select_chg_cb(GtkTreeSelection *ignored, gpointer data) -{ - GtkTreeSelection *select = tpm_dat->listselect; - GtkTreeIter iter; - GtkTreeModel *model; - - /* See if things are selected */ - if (gtk_tree_selection_get_selected(select, &model, &iter)) { - /* Enable buttons if something is selected */ - gtk_widget_set_sensitive(GTK_WIDGET(tpm_dat->exportbutton), TRUE); - gtk_widget_set_sensitive(GTK_WIDGET(tpm_dat->infobutton), TRUE); - gtk_widget_set_sensitive(GTK_WIDGET(tpm_dat->deletebutton), TRUE); - } else { - /* Otherwise, disable them */ - gtk_widget_set_sensitive(GTK_WIDGET(tpm_dat->exportbutton), FALSE); - gtk_widget_set_sensitive(GTK_WIDGET(tpm_dat->infobutton), FALSE); - gtk_widget_set_sensitive(GTK_WIDGET(tpm_dat->deletebutton), FALSE); - - } -} - -static void -tls_peers_mgmt_import_ok2_cb(gpointer data, const char *result) -{ - GTlsCertificate *crt = data; - GError *error = NULL; - - /* TODO: Perhaps prompt if you're overwriting a cert? */ - - /* Trust the certificate */ - if (result && *result) { - if(!purple_tls_certificate_trust(result, crt, &error)) { - purple_debug_error("gtkcertmgr/tls_peers_mgmt", - "Error trusting certificate '%s': %s", - result, error->message); - g_clear_error(&error); - } - - tls_peers_mgmt_repopulate_list(); - } - - /* And this certificate is not needed any more */ - g_object_unref(crt); -} - -static void -tls_peers_mgmt_import_cancel2_cb(gpointer data, const char *result) -{ - GTlsCertificate *crt = data; - g_object_unref(crt); -} - -static void -tls_peers_mgmt_import_ok_cb(gpointer data, const char *filename) -{ - GTlsCertificate *crt; - GError *error = NULL; - - /* Now load the certificate from disk */ - crt = g_tls_certificate_new_from_file(filename, &error); - - /* Did it work? */ - if (crt != NULL) { - gchar *default_hostname; - PurpleTlsCertificateInfo *info; - - /* Get name to add trust as */ - /* Make a guess about what the hostname should be */ - info = purple_tls_certificate_get_info(crt); - default_hostname = purple_tls_certificate_info_get_subject_name(info); - purple_tls_certificate_info_free(info); - - /* TODO: Find a way to make sure that crt gets destroyed - if the window gets closed unusually, such as by handle - deletion */ - /* TODO: Display some more information on the certificate? */ - purple_request_input(tpm_dat, - _("Certificate Import"), - _("Specify a hostname"), - _("Type the host name for this certificate."), - default_hostname, - FALSE, /* Not multiline */ - FALSE, /* Not masked? */ - NULL, /* No hints? */ - _("OK"), - G_CALLBACK(tls_peers_mgmt_import_ok2_cb), - _("Cancel"), - G_CALLBACK(tls_peers_mgmt_import_cancel2_cb), - NULL, /* No additional parameters */ - crt /* Pass cert instance to callback*/ - ); - - g_free(default_hostname); - } else { - /* Errors! Oh no! */ - /* TODO: Perhaps find a way to be specific about what just - went wrong? */ - gchar * secondary; - - purple_debug_warning("gtkcertmgr/tls_peers_mgmt", - "File %s couldn't be imported: %s", - filename, error->message); - g_clear_error(&error); - - secondary = g_strdup_printf(_("File %s could not be imported.\nMake sure that the file is readable and in PEM format.\n"), filename); - purple_notify_error(NULL, - _("Certificate Import Error"), - _("X.509 certificate import failed"), - secondary, NULL); - g_free(secondary); - } -} - -static void -tls_peers_mgmt_import_cb(GtkWidget *button, gpointer data) -{ - /* TODO: need to tell the user that we want a .PEM file! */ - purple_request_file(tpm_dat, - _("Select a PEM certificate"), - "certificate.pem", - FALSE, /* Not a save dialog */ - G_CALLBACK(tls_peers_mgmt_import_ok_cb), - NULL, /* Do nothing if cancelled */ - NULL, NULL); /* No extra parameters */ -} - -static void -tls_peers_mgmt_export_ok_cb(gpointer data, const char *filename) -{ - GTlsCertificate *crt = data; - gchar *pem = NULL; - GError *error = NULL; - - g_assert(filename); - - g_object_get(crt, "certificate-pem", &pem, NULL); - - if (!g_file_set_contents(filename, pem, -1, &error)) { - /* Errors! Oh no! */ - /* TODO: Perhaps find a way to be specific about what just - went wrong? */ - gchar * secondary; - - purple_debug_warning("gtkcertmgr/tls_peers_mgmt", - "File %s couldn't be exported: %s", - filename, error->message); - g_clear_error(&error); - - secondary = g_strdup_printf(_("Export to file %s failed.\nCheck that you have write permission to the target path\n"), filename); - purple_notify_error(NULL, - _("Certificate Export Error"), - _("X.509 certificate export failed"), - secondary, NULL); - g_free(secondary); - } else { - tls_peers_mgmt_repopulate_list(); - } - - g_free(pem); - g_object_unref(crt); -} - -static void -tls_peers_mgmt_export_cb(GtkWidget *button, gpointer data) -{ - GTlsCertificate *crt; - GtkTreeSelection *select = tpm_dat->listselect; - GtkTreeIter iter; - GtkTreeModel *model; - gchar *id; - GError *error = NULL; - - /* See if things are selected */ - if (!gtk_tree_selection_get_selected(select, &model, &iter)) { - purple_debug_warning("gtkcertmgr/tls_peers_mgmt", - "Export clicked with no selection?\n"); - return; - } - - /* Retrieve the selected hostname */ - gtk_tree_model_get(model, &iter, TPM_HOSTNAME_COLUMN, &id, -1); - - /* Extract the certificate from the pool now to make sure it doesn't - get deleted out from under us */ - crt = purple_tls_certificate_new_from_id(id, &error); - - if (NULL == crt) { - purple_debug_error("gtkcertmgr/tls_peers_mgmt", - "Error fetching trusted cert '%s': %s\n", - id, error->message); - g_clear_error(&error); - g_free(id); - return; - } - g_free(id); - - /* TODO: inform user that it will be a PEM? */ - purple_request_file(tpm_dat, - _("PEM X.509 Certificate Export"), - "certificate.pem", - TRUE, /* Is a save dialog */ - G_CALLBACK(tls_peers_mgmt_export_ok_cb), - G_CALLBACK(g_object_unref), - NULL, /* No extra parameters */ - crt); /* Pass the certificate on to the callback */ -} - -static void -tls_peers_mgmt_info_cb(GtkWidget *button, gpointer data) -{ - GtkTreeSelection *select = tpm_dat->listselect; - GtkTreeIter iter; - GtkTreeModel *model; - gchar *id; - GTlsCertificate *crt; - gchar *title; - GError *error = NULL; - - /* See if things are selected */ - if (!gtk_tree_selection_get_selected(select, &model, &iter)) { - purple_debug_warning("gtkcertmgr/tls_peers_mgmt", - "Info clicked with no selection?\n"); - return; - } - - /* Retrieve the selected hostname */ - gtk_tree_model_get(model, &iter, TPM_HOSTNAME_COLUMN, &id, -1); - - /* Now retrieve the certificate */ - crt = purple_tls_certificate_new_from_id(id, &error); - - if (crt == NULL) { - purple_debug_warning("gtkcertmgr/tls_peers_mgmt", - "Unable to fetch certificate '%s': %s", - id, error ? error->message : "unknown error"); - g_clear_error(&error); - g_free(id); - } - - /* Fire the notification */ - title = g_strdup_printf(_("Certificate Information for %s"), id); - purple_request_certificate(tpm_dat, title, NULL, NULL, crt, - _("OK"), G_CALLBACK(g_object_unref), - _("Cancel"), G_CALLBACK(g_object_unref), - crt); - - g_free(id); - g_free(title); -} - -static void -tls_peers_mgmt_activated_cb(GtkTreeView *treeview, GtkTreePath *path, GtkTreeViewColumn *column, gpointer data) -{ - tls_peers_mgmt_info_cb(NULL, NULL); -} - -static void -tls_peers_mgmt_delete_confirm_cb(gchar *id, gint choice) -{ - GError *error = NULL; - - if (1 == choice) { - /* Yes, distrust was confirmed */ - /* Now distrust the thing */ - if (!purple_tls_certificate_distrust(id, &error)) { - purple_debug_warning("gtkcertmgr/tls_peers_mgmt", - "Deletion failed on id %s: %s\n", - id, error->message); - g_clear_error(&error); - } else { - tls_peers_mgmt_repopulate_list(); - } - } - - g_free(id); -} - -static void -tls_peers_mgmt_delete_cb(GtkWidget *button, gpointer data) -{ - GtkTreeSelection *select = tpm_dat->listselect; - GtkTreeIter iter; - GtkTreeModel *model; - - /* See if things are selected */ - if (gtk_tree_selection_get_selected(select, &model, &iter)) { - - gchar *id; - gchar *primary; - - /* Retrieve the selected hostname */ - gtk_tree_model_get(model, &iter, TPM_HOSTNAME_COLUMN, &id, -1); - - /* Prompt to confirm deletion */ - primary = g_strdup_printf( - _("Really delete certificate for %s?"), id ); - - purple_request_yes_no(tpm_dat, _("Confirm certificate delete"), - primary, NULL, /* Can this be NULL? */ - 0, /* "yes" is the default action */ - NULL, - id, /* id ownership passed to callback */ - tls_peers_mgmt_delete_confirm_cb, - tls_peers_mgmt_delete_confirm_cb ); - - g_free(primary); - - } else { - purple_debug_warning("gtkcertmgr/tls_peers_mgmt", - "Delete clicked with no selection?\n"); - return; - } -} - -static GtkWidget * -tls_peers_mgmt_build(void) -{ - GtkWidget *bbox; - GtkListStore *store; - - /* This block of variables will end up in tpm_dat */ - GtkTreeView *listview; - GtkTreeSelection *select; - GtkWidget *importbutton; - GtkWidget *exportbutton; - GtkWidget *infobutton; - GtkWidget *deletebutton; - /** Element to return to the Certmgr window to put in the Notebook */ - GtkWidget *mgmt_widget; - - /* Create a struct to store context information about this window */ - tpm_dat = g_new0(tls_peers_mgmt_data, 1); - - tpm_dat->mgmt_widget = mgmt_widget = gtk_box_new( - GTK_ORIENTATION_HORIZONTAL, PIDGIN_HIG_BOX_SPACE); - gtk_container_set_border_width(GTK_CONTAINER(mgmt_widget), - PIDGIN_HIG_BOX_SPACE); - gtk_widget_show(mgmt_widget); - - /* Ensure that everything gets cleaned up when the dialog box - is closed */ - g_signal_connect(G_OBJECT(mgmt_widget), "destroy", - G_CALLBACK(tls_peers_mgmt_destroy), NULL); - - /* List view */ - store = gtk_list_store_new(TPM_N_COLUMNS, G_TYPE_STRING); - - tpm_dat->listview = listview = - GTK_TREE_VIEW(gtk_tree_view_new_with_model(GTK_TREE_MODEL(store))); - g_object_unref(G_OBJECT(store)); - - { - GtkCellRenderer *renderer; - GtkTreeViewColumn *column; - - /* Set up the display columns */ - renderer = gtk_cell_renderer_text_new(); - column = gtk_tree_view_column_new_with_attributes( - _("Hostname"), - renderer, - "text", TPM_HOSTNAME_COLUMN, - NULL); - gtk_tree_view_append_column(GTK_TREE_VIEW(listview), column); - - gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(store), - TPM_HOSTNAME_COLUMN, GTK_SORT_ASCENDING); - } - - /* Get the treeview selector into the struct */ - tpm_dat->listselect = select = - gtk_tree_view_get_selection(GTK_TREE_VIEW(listview)); - - /* Force the selection mode */ - gtk_tree_selection_set_mode(select, GTK_SELECTION_SINGLE); - - /* Use a callback to enable/disable the buttons based on whether - something is selected */ - g_signal_connect(G_OBJECT(select), "changed", - G_CALLBACK(tls_peers_mgmt_select_chg_cb), NULL); - - g_signal_connect(G_OBJECT(listview), "row-activated", - G_CALLBACK(tls_peers_mgmt_activated_cb), NULL); - - gtk_box_pack_start(GTK_BOX(mgmt_widget), - pidgin_make_scrollable(GTK_WIDGET(listview), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS, GTK_SHADOW_IN, -1, -1), - TRUE, TRUE, /* Take up lots of space */ - 0); - gtk_widget_show(GTK_WIDGET(listview)); - - /* Fill the list for the first time */ - tls_peers_mgmt_repopulate_list(); - - /* Right-hand side controls box */ - bbox = gtk_button_box_new(GTK_ORIENTATION_VERTICAL); - gtk_box_pack_end(GTK_BOX(mgmt_widget), bbox, - FALSE, FALSE, /* Do not take up space */ - 0); - gtk_box_set_spacing(GTK_BOX(bbox), PIDGIN_HIG_BOX_SPACE); - gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_START); - gtk_widget_show(bbox); - - /* Import button */ - tpm_dat->importbutton = importbutton = - gtk_button_new_with_mnemonic(_("_Import...")); - gtk_box_pack_start(GTK_BOX(bbox), importbutton, FALSE, FALSE, 0); - gtk_widget_show(importbutton); - g_signal_connect(G_OBJECT(importbutton), "clicked", - G_CALLBACK(tls_peers_mgmt_import_cb), NULL); - - - /* Export button */ - tpm_dat->exportbutton = exportbutton = - gtk_button_new_with_mnemonic(_("_Export...")); - gtk_box_pack_start(GTK_BOX(bbox), exportbutton, FALSE, FALSE, 0); - gtk_widget_show(exportbutton); - g_signal_connect(G_OBJECT(exportbutton), "clicked", - G_CALLBACK(tls_peers_mgmt_export_cb), NULL); - - - /* Info button */ - tpm_dat->infobutton = infobutton = - gtk_button_new_with_mnemonic(_("_Get Info")); - gtk_box_pack_start(GTK_BOX(bbox), infobutton, FALSE, FALSE, 0); - gtk_widget_show(infobutton); - g_signal_connect(G_OBJECT(infobutton), "clicked", - G_CALLBACK(tls_peers_mgmt_info_cb), NULL); - - - /* Delete button */ - tpm_dat->deletebutton = deletebutton = - gtk_button_new_with_mnemonic(_("_Delete")); - gtk_box_pack_start(GTK_BOX(bbox), deletebutton, FALSE, FALSE, 0); - gtk_widget_show(deletebutton); - g_signal_connect(G_OBJECT(deletebutton), "clicked", - G_CALLBACK(tls_peers_mgmt_delete_cb), NULL); - - /* Call the "selection changed" callback, which will probably disable - all the buttons since nothing is selected yet */ - tls_peers_mgmt_select_chg_cb(select, NULL); - - return mgmt_widget; -} - -const PidginCertificateManager tls_peers_mgmt = { - tls_peers_mgmt_build, /* Widget creation function */ - N_("SSL Servers") -}; - -/***************************************************************************** - * GTK+ main certificate manager * - *****************************************************************************/ -typedef struct -{ - GtkWidget *window; - GtkWidget *notebook; - - GtkWidget *closebutton; -} CertMgrDialog; - -/* If a certificate manager window is open, this will point to it. - So if it is set, don't open another one! */ -CertMgrDialog *certmgr_dialog = NULL; - -static gboolean -certmgr_close_cb(GtkWidget *w, CertMgrDialog *dlg) -{ - /* TODO: Ignoring the arguments to this function may not be ideal, - but there *should* only be "one dialog to rule them all" at a time*/ - pidgin_certmgr_hide(); - return FALSE; -} - -void -pidgin_certmgr_show(void) -{ - CertMgrDialog *dlg; - GtkWidget *win; - GtkWidget *vbox; - - /* Enumerate all the certificates on file */ - { - GList *idlist; - GList *l; - - purple_debug_info("gtkcertmgr", - "Enumerating X.509 certificates:\n"); - - idlist = purple_tls_certificate_list_ids(); - - for (l=idlist; l; l = l->next) { - purple_debug_info("gtkcertmgr", - "- %s\n", - l->data ? (gchar *) l->data : "(null)"); - } /* idlist */ - - purple_tls_certificate_free_ids(idlist); - } - - - /* If the manager is already open, bring it to the front */ - if (certmgr_dialog != NULL) { - gtk_window_present(GTK_WINDOW(certmgr_dialog->window)); - return; - } - - /* Create the dialog, and set certmgr_dialog so we never create - more than one at a time */ - dlg = certmgr_dialog = g_new0(CertMgrDialog, 1); - - win = dlg->window = - pidgin_create_dialog(_("Certificate Manager"),/* Title */ - 0, /*Window border*/ - "certmgr", /* Role */ - TRUE); /* Allow resizing */ - g_signal_connect(G_OBJECT(win), "delete_event", - G_CALLBACK(certmgr_close_cb), dlg); - - - /* TODO: Retrieve the user-set window size and use it */ - gtk_window_set_default_size(GTK_WINDOW(win), 400, 400); - - /* Main vbox */ - vbox = pidgin_dialog_get_vbox_with_properties(GTK_DIALOG(win), FALSE, PIDGIN_HIG_BORDER); - - /* Notebook of various certificate managers */ - dlg->notebook = gtk_notebook_new(); - gtk_box_pack_start(GTK_BOX(vbox), dlg->notebook, - TRUE, TRUE, /* Notebook should take extra space */ - 0); - gtk_widget_show(dlg->notebook); - - /* Close button */ - dlg->closebutton = pidgin_dialog_add_button(GTK_DIALOG(win), - _("_Close"), G_CALLBACK(certmgr_close_cb), dlg); - - /* Add the defined certificate managers */ - /* TODO: Find a way of determining whether each is shown or not */ - /* TODO: Implement this correctly */ - gtk_notebook_append_page(GTK_NOTEBOOK (dlg->notebook), - (tls_peers_mgmt.build)(), - gtk_label_new(_(tls_peers_mgmt.label)) ); - - gtk_widget_show(win); -} - -void -pidgin_certmgr_hide(void) -{ - /* If it isn't open, do nothing */ - if (certmgr_dialog == NULL) { - return; - } - - purple_signals_disconnect_by_handle(certmgr_dialog); - purple_prefs_disconnect_by_handle(certmgr_dialog); - - gtk_widget_destroy(certmgr_dialog->window); - g_free(certmgr_dialog); - certmgr_dialog = NULL; -}
--- a/pidgin/gtkcertmgr.h Thu Nov 22 11:25:59 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,72 +0,0 @@ -/* - * pidgin - * - * Pidgin is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - * - */ - -#ifndef _PIDGINCERTMGR_H_ -#define _PIDGINCERTMGR_H_ -/** - * SECTION:gtkcertmgr - * @section_id: pidgin-gtkcertmgr - * @short_description: <filename>gtkcertmgr.h</filename> - * @title: Certificate Manager API - */ - -/************************************************************************** - * Structures * - **************************************************************************/ -typedef struct _PidginCertificateManager PidginCertificateManager; - -/** - * PidginCertificateManager: - * - * GTK+ Certificate Manager subwidget - */ -struct _PidginCertificateManager { - /* Create, configure, show, and return the management interface */ - GtkWidget * (* build)(void); - /* Notebook label to use in the CertMgr dialog */ - gchar *label; -}; - -G_BEGIN_DECLS - -/**************************************************************************/ -/* Certificate Manager API */ -/**************************************************************************/ - -/** - * pidgin_certmgr_show: - * - * Show the certificate manager window - */ -void pidgin_certmgr_show(void); - -/** - * pidgin_certmgr_hide: - * - * Hide the certificate manager window - */ -void pidgin_certmgr_hide(void); - -G_END_DECLS - -#endif /* _PIDGINCERTMGR_H_ */
--- a/pidgin/gtkprefs.c Thu Nov 22 11:25:59 2018 +0200 +++ b/pidgin/gtkprefs.c Fri Nov 30 02:50:38 2018 +0000 @@ -4202,6 +4202,8 @@ purple_prefs_remove(PIDGIN_PREFS_ROOT "/blist/show_group_count"); purple_prefs_remove(PIDGIN_PREFS_ROOT "/blist/show_warning_level"); purple_prefs_remove(PIDGIN_PREFS_ROOT "/blist/tooltip_delay"); + purple_prefs_remove(PIDGIN_PREFS_ROOT "/blist/x"); + purple_prefs_remove(PIDGIN_PREFS_ROOT "/blist/y"); purple_prefs_remove(PIDGIN_PREFS_ROOT "/conversations/button_type"); purple_prefs_remove(PIDGIN_PREFS_ROOT "/conversations/ctrl_enter_sends"); purple_prefs_remove(PIDGIN_PREFS_ROOT "/conversations/enter_sends");
--- a/pidgin/gtkrequest.c Thu Nov 22 11:25:59 2018 +0200 +++ b/pidgin/gtkrequest.c Fri Nov 30 02:50:38 2018 +0000 @@ -26,7 +26,6 @@ #include "debug.h" #include "prefs.h" -#include "tls-certificate-info.h" #include "util.h" #include "gtkrequest.h" @@ -37,11 +36,6 @@ #include <gdk/gdkkeysyms.h> -#ifdef ENABLE_GCR -#define GCR_API_SUBJECT_TO_CHANGE -#include <gcr/gcr.h> -#endif - #include "gtk3compat.h" typedef struct @@ -1485,56 +1479,6 @@ return pidgin_make_scrollable(treeview, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC, GTK_SHADOW_IN, -1, -1); } -static GtkWidget * -create_certificate_field(PurpleRequestField *field) -{ - GTlsCertificate *cert; -#ifdef ENABLE_GCR - GByteArray *der = NULL; - GcrCertificateBasicsWidget *cert_widget; - GcrCertificate *gcrt; -#else - PurpleTlsCertificateInfo *info; - GtkWidget *cert_label; - char *str; - char *escaped; -#endif - - cert = purple_request_field_certificate_get_value(field); - -#ifdef ENABLE_GCR - g_object_get(cert, "certificate", &der, NULL); - 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 - info = purple_tls_certificate_get_info(cert); - str = purple_tls_certificate_info_get_display_string(info); - purple_tls_certificate_info_free(info); - - 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_label_set_xalign(GTK_LABEL(cert_label), 0); - gtk_label_set_yalign(GTK_LABEL(cert_label), 0); - - g_free(str); - g_free(escaped); - - return cert_label; -#endif -} - static GdkPixbuf* _pidgin_datasheet_stock_icon_get(const gchar *stock_name) { @@ -2331,8 +2275,6 @@ 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 if (type == PURPLE_REQUEST_FIELD_DATASHEET) widget = create_datasheet_field(field, datasheet_buttons_sg); else
--- a/pidgin/libpidgin.c Thu Nov 22 11:25:59 2018 +0200 +++ b/pidgin/libpidgin.c Fri Nov 30 02:50:38 2018 +0000 @@ -366,7 +366,36 @@ static void pidgin_activate_cb(GApplication *application, gpointer user_data) { - purple_blist_set_visible(TRUE); + PidginBuddyList *blist = pidgin_blist_get_default_gtk_blist(); + + if (blist != NULL && blist->window != NULL) { + gtk_window_present(GTK_WINDOW(blist->window)); + } +} + +static gint +pidgin_command_line_cb(GApplication *application, + GApplicationCommandLine *cmdline, gpointer user_data) +{ + gchar **argv; + int argc; + int i; + + argv = g_application_command_line_get_arguments(cmdline, &argc); + + if (argc == 1) { + /* No arguments, just activate */ + g_application_activate(application); + } + + /* Start at 1 to skip the executable name */ + for (i = 1; i < argc; ++i) { + purple_got_protocol_handler_uri(argv[i]); + } + + g_strfreev(argv); + + return 0; } static gchar *opt_config_dir_arg = NULL; @@ -703,11 +732,9 @@ app = G_APPLICATION(gtk_application_new("im.pidgin.Pidgin", #if GLIB_CHECK_VERSION(2, 48, 0) - G_APPLICATION_CAN_OVERRIDE_APP_ID -#else - G_APPLICATION_FLAGS_NONE + G_APPLICATION_CAN_OVERRIDE_APP_ID | #endif - )); + G_APPLICATION_HANDLES_COMMAND_LINE)); summary = g_strdup_printf("%s %s", PIDGIN_NAME, DISPLAY_VERSION); g_application_set_option_context_summary(app, summary); @@ -727,6 +754,8 @@ G_CALLBACK(pidgin_startup_cb), NULL); g_signal_connect(app, "activate", G_CALLBACK(pidgin_activate_cb), NULL); + g_signal_connect(app, "command-line", + G_CALLBACK(pidgin_command_line_cb), NULL); ret = g_application_run(app, argc, argv);
--- a/pidgin/meson.build Thu Nov 22 11:25:59 2018 +0200 +++ b/pidgin/meson.build Fri Nov 30 02:50:38 2018 +0000 @@ -5,7 +5,6 @@ 'gtkblist-theme.c', 'gtkblist-theme-loader.c', 'gtkcellrendererexpander.c', - 'gtkcertmgr.c', 'gtkconn.c', 'gtkconv.c', 'gtkconv-theme.c', @@ -54,7 +53,6 @@ 'gtkblist-theme.h', 'gtkblist-theme-loader.h', 'gtkcellrendererexpander.h', - 'gtkcertmgr.h', 'gtkconn.h', 'gtkconv.h', 'gtkconvwin.h', @@ -162,7 +160,6 @@ dependencies : [ dbus, enchant, - GCR, glib, gstreamer_video, gtk,
--- a/pidgin/win32/gtkwin32dep.c Thu Nov 22 11:25:59 2018 +0200 +++ b/pidgin/win32/gtkwin32dep.c Fri Nov 30 02:50:38 2018 +0000 @@ -39,6 +39,7 @@ #include "untar.h" #include "gtkwin32dep.h" +#include "gtkblist.h" #include "gtkconv.h" #include "gtkconn.h" #include "util.h" @@ -237,8 +238,12 @@ static LRESULT CALLBACK message_window_handler(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { if (msg == PIDGIN_WM_FOCUS_REQUEST) { + PidginBuddyList *blist; purple_debug_info("winpidgin", "Got external Buddy List focus request."); - purple_blist_set_visible(TRUE); + blist = pidgin_blist_get_default_gtk_blist(); + if (blist != NULL && blist->window != NULL) { + gtk_window_present(GTK_WINDOW(blist->window)); + } return TRUE; } else if (msg == PIDGIN_WM_PROTOCOL_HANDLE) { char *proto_msg = (char *) lparam;
--- a/po/POTFILES.in Thu Nov 22 11:25:59 2018 +0200 +++ b/po/POTFILES.in Fri Nov 30 02:50:38 2018 +0000 @@ -2,7 +2,6 @@ finch/finch.c finch/gntaccount.c finch/gntblist.c -finch/gntcertmgr.c finch/gntconn.c finch/gntconv.c finch/gntdebug.c @@ -162,8 +161,6 @@ libpurple/smiley.c libpurple/sslconn.c libpurple/status.c -libpurple/tls-certificate-info.c -libpurple/tls-certificate.c libpurple/util.c libpurple/win32/libc_interface.c libpurple/xfer.c @@ -175,7 +172,6 @@ pidgin/gtkaccount.c pidgin/gtkblist-theme.c pidgin/gtkblist.c -pidgin/gtkcertmgr.c pidgin/gtkconn.c pidgin/gtkconv.c pidgin/gtkdebug.c