Mercurial > pidgin
changeset 21947:c6b408d16011
merge of '791803b6696dd26a5193ad76f80dbc7c6cb2687a'
and 'e7dd3b30ece9f95dd95249583812659312c457e6'
author | Stu Tomlinson <stu@nosnilmot.com> |
---|---|
date | Fri, 28 Dec 2007 02:49:23 +0000 |
parents | 1981f277ab01 (current diff) ddd53c9174bc (diff) |
children | af2c4ef3e61d |
files | |
diffstat | 23 files changed, 384 insertions(+), 298 deletions(-) [+] |
line wrap: on
line diff
--- a/ChangeLog.API Fri Dec 28 02:49:10 2007 +0000 +++ b/ChangeLog.API Fri Dec 28 02:49:23 2007 +0000 @@ -21,8 +21,9 @@ smileys in the text. (Florian 'goutnet' Delizy) * pidgin_auto_parent_window to make a window transient for a suitable parent window. - * pidgin_tooltip_setup_for_treeview, pidgin_tooltip_destroy and - pidgin_tooltip_show to simplify the process of drawing tooltips. + * pidgin_tooltip_setup_for_treeview, pidgin_tooltip_destroy, + pidgin_tooltip_show and pidgin_tooltip_setup_for_widget to simplify + the process of drawing tooltips. Finch: libgnt:
--- a/configure.ac Fri Dec 28 02:49:10 2007 +0000 +++ b/configure.ac Fri Dec 28 02:49:23 2007 +0000 @@ -678,7 +678,6 @@ PKG_CHECK_MODULES(MEANWHILE, [meanwhile >= 1.0.0 meanwhile < 2.0.0], [ have_meanwhile="yes" ], [ - AC_MSG_RESULT(no) have_meanwhile="no" ]) AC_SUBST(MEANWHILE_CFLAGS) @@ -697,7 +696,6 @@ avahiincludes="yes" avahilibs="yes" ], [ - AC_MSG_RESULT(no) avahiincludes="no" avahilibs="no" ]) @@ -742,7 +740,6 @@ silcincludes="yes" silcclient="yes" ], [ - AC_MSG_RESULT(no) have_silc="no" ]) if test "x$have_silc" = "xno"; then @@ -751,7 +748,6 @@ silc10includes="yes" silc10client="yes" ], [ - AC_MSG_RESULT(no) have_silc="no" ]) dnl If silcclient.pc wasn't found, check for just silc.pc @@ -761,7 +757,6 @@ silc10includes="yes" silc10client="yes" ], [ - AC_MSG_RESULT(no) have_silc="no" ]) fi @@ -1154,7 +1149,6 @@ AC_SUBST(DBUS_LIBS) enable_dbus=yes ], [ - AC_MSG_RESULT(no) enable_dbus=no ])
--- a/libpurple/account.c Fri Dec 28 02:49:10 2007 +0000 +++ b/libpurple/account.c Fri Dec 28 02:49:23 2007 +0000 @@ -1645,7 +1645,7 @@ if (status == NULL) { purple_debug_error("account", - "Invalid status ID %s for account %s (%s)\n", + "Invalid status ID '%s' for account %s (%s)\n", status_id, purple_account_get_username(account), purple_account_get_protocol_id(account)); return;
--- a/libpurple/blist.h Fri Dec 28 02:49:10 2007 +0000 +++ b/libpurple/blist.h Fri Dec 28 02:49:23 2007 +0000 @@ -680,7 +680,8 @@ * * @param g The group * - * @return A list of purple_accounts + * @return A GSList of accounts (which must be freed), or NULL if the group + * has no accounts. */ GSList *purple_group_get_accounts(PurpleGroup *g);
--- a/libpurple/certificate.c Fri Dec 28 02:49:10 2007 +0000 +++ b/libpurple/certificate.c Fri Dec 28 02:49:23 2007 +0000 @@ -1228,6 +1228,9 @@ } static void +x509_tls_cached_unknown_peer(PurpleCertificateVerificationRequest *vrq); + +static void x509_tls_cached_cert_in_cache(PurpleCertificateVerificationRequest *vrq) { /* TODO: Looking this up by name over and over is expensive. @@ -1268,8 +1271,8 @@ } else { purple_debug_info("certificate/x509/tls_cached", "Peer cert did NOT match cached\n"); - /* vrq now becomes the problem of cert_changed */ - x509_tls_cached_peer_cert_changed(vrq); + /* vrq now becomes the problem of the user */ + x509_tls_cached_unknown_peer(vrq); } purple_certificate_destroy(cached_crt); @@ -1280,7 +1283,9 @@ /* For when we've never communicated with this party before */ /* TODO: Need ways to specify possibly multiple problems with a cert, or at least reprioritize them. For example, maybe the signature ought to be - checked BEFORE the hostname checking? */ + checked BEFORE the hostname checking? + Stu thinks we should check the signature before the name, so we do now. + The above TODO still stands. */ static void x509_tls_cached_unknown_peer(PurpleCertificateVerificationRequest *vrq) { @@ -1292,35 +1297,6 @@ peer_crt = (PurpleCertificate *) chain->data; - /* First, check that the hostname matches */ - if ( ! purple_certificate_check_subject_name(peer_crt, - vrq->subject_name) ) { - gchar *sn = purple_certificate_get_subject_name(peer_crt); - gchar *msg; - - purple_debug_info("certificate/x509/tls_cached", - "Name mismatch: Certificate given for %s " - "has a name of %s\n", - vrq->subject_name, sn); - - /* Prompt the user to authenticate the certificate */ - /* TODO: Provide the user with more guidance about why he is - being prompted */ - /* vrq will be completed by user_auth */ - msg = g_strdup_printf(_("The certificate presented by \"%s\" " - "claims to be from \"%s\" instead. " - "This could mean that you are not " - "connecting to the service you " - "believe you are."), - vrq->subject_name, sn); - - x509_tls_cached_user_auth(vrq,msg); - - g_free(sn); - g_free(msg); - return; - } /* if (name mismatch) */ - /* TODO: Figure out a way to check for a bad signature, as opposed to "not self-signed" */ if ( purple_certificate_signed_by(peer_crt, peer_crt) ) { @@ -1341,7 +1317,7 @@ g_free(msg); return; - } /* if (name mismatch) */ + } /* if (self signed) */ /* Next, check that the certificate chain is valid */ if ( ! purple_certificate_check_signature_chain(chain) ) { @@ -1440,6 +1416,35 @@ return; } /* if (CA signature not good) */ + /* Last, check that the hostname matches */ + if ( ! purple_certificate_check_subject_name(peer_crt, + vrq->subject_name) ) { + gchar *sn = purple_certificate_get_subject_name(peer_crt); + gchar *msg; + + purple_debug_info("certificate/x509/tls_cached", + "Name mismatch: Certificate given for %s " + "has a name of %s\n", + vrq->subject_name, sn); + + /* Prompt the user to authenticate the certificate */ + /* TODO: Provide the user with more guidance about why he is + being prompted */ + /* vrq will be completed by user_auth */ + msg = g_strdup_printf(_("The certificate presented by \"%s\" " + "claims to be from \"%s\" instead. " + "This could mean that you are not " + "connecting to the service you " + "believe you are."), + vrq->subject_name, sn); + + x509_tls_cached_user_auth(vrq,msg); + + g_free(sn); + g_free(msg); + return; + } /* if (name mismatch) */ + /* If we reach this point, the certificate is good. */ /* Look up the local cache and store it there for future use */ tls_peers = purple_certificate_find_pool(x509_tls_cached.scheme_name,
--- a/libpurple/cmds.h Fri Dec 28 02:49:10 2007 +0000 +++ b/libpurple/cmds.h Fri Dec 28 02:49:23 2007 +0000 @@ -30,25 +30,20 @@ /**************************************************************************/ /*@{*/ -typedef enum _PurpleCmdPriority PurpleCmdPriority; -typedef enum _PurpleCmdFlag PurpleCmdFlag; -typedef enum _PurpleCmdStatus PurpleCmdStatus; -typedef enum _PurpleCmdRet PurpleCmdRet; - -enum _PurpleCmdStatus { +typedef enum _PurpleCmdStatus { PURPLE_CMD_STATUS_OK, PURPLE_CMD_STATUS_FAILED, PURPLE_CMD_STATUS_NOT_FOUND, PURPLE_CMD_STATUS_WRONG_ARGS, PURPLE_CMD_STATUS_WRONG_PRPL, PURPLE_CMD_STATUS_WRONG_TYPE, -}; +} PurpleCmdStatus; -enum _PurpleCmdRet { +typedef enum _PurpleCmdRet { PURPLE_CMD_RET_OK, /**< Everything's okay. Don't look for another command to call. */ PURPLE_CMD_RET_FAILED, /**< The command failed, but stop looking.*/ PURPLE_CMD_RET_CONTINUE, /**< Continue, looking for other commands with the same name to call. */ -}; +} PurpleCmdRet; #define PURPLE_CMD_FUNC(func) ((PurpleCmdFunc)func) @@ -56,7 +51,7 @@ gchar **args, gchar **error, void *data); typedef guint PurpleCmdId; -enum _PurpleCmdPriority { +typedef enum _PurpleCmdPriority { PURPLE_CMD_P_VERY_LOW = -1000, PURPLE_CMD_P_LOW = 0, PURPLE_CMD_P_DEFAULT = 1000, @@ -65,7 +60,7 @@ PURPLE_CMD_P_ALIAS = 4000, PURPLE_CMD_P_HIGH = 5000, PURPLE_CMD_P_VERY_HIGH = 6000, -}; +} PurpleCmdPriority; /** Flags used to set various properties of commands. Every command should * have at least one of #PURPLE_CMD_FLAG_IM and #PURPLE_CMD_FLAG_CHAT set in @@ -73,7 +68,7 @@ * * @see purple_cmd_register */ -enum _PurpleCmdFlag { +typedef enum _PurpleCmdFlag { /** Command is usable in IMs. */ PURPLE_CMD_FLAG_IM = 0x01, /** Command is usable in multi-user chats. */ @@ -82,7 +77,7 @@ PURPLE_CMD_FLAG_PRPL_ONLY = 0x04, /** Incorrect arguments to this command should be accepted anyway. */ PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS = 0x08, -}; +} PurpleCmdFlag; /*@}*/
--- a/libpurple/prefs.c Fri Dec 28 02:49:10 2007 +0000 +++ b/libpurple/prefs.c Fri Dec 28 02:49:23 2007 +0000 @@ -438,19 +438,6 @@ g_free(filename); prefs_loaded = TRUE; - /* I introduced a bug in 2.0.0beta2. This fixes the broken - * scores on upgrade. This can be removed sometime shortly - * after 2.0.0 final is released. -- rlaager */ - if (purple_prefs_get_int("/purple/status/scores/offline") == -500 && - purple_prefs_get_int("/purple/status/scores/available") == 100 && - purple_prefs_get_int("/purple/status/scores/invisible") == -50 && - purple_prefs_get_int("/purple/status/scores/away") == -100 && - purple_prefs_get_int("/purple/status/scores/extended_away") == -200 && - purple_prefs_get_int("/purple/status/scores/idle") == -400) - { - purple_prefs_set_int("/purple/status/scores/idle", -10); - } - return TRUE; }
--- a/libpurple/protocols/msn/soap2.c Fri Dec 28 02:49:10 2007 +0000 +++ b/libpurple/protocols/msn/soap2.c Fri Dec 28 02:49:23 2007 +0000 @@ -170,6 +170,9 @@ { MsnSoapConnection *conn = data; + /* sslconn already frees the connection in case of error */ + conn->ssl = NULL; + g_hash_table_remove(conn->session->soap_table, conn->host); }
--- a/libpurple/protocols/qq/group_opt.c Fri Dec 28 02:49:10 2007 +0000 +++ b/libpurple/protocols/qq/group_opt.c Fri Dec 28 02:49:23 2007 +0000 @@ -39,37 +39,12 @@ #include "packet_parse.h" #include "utils.h" -/* TODO: can't we use qsort here? */ -/* This implement quick sort algorithm (low->high) */ -static void _quick_sort(gint *numbers, gint left, gint right) +static int _compare_guint32(const void *a, + const void *b) { - gint pivot, l_hold, r_hold; - - l_hold = left; - r_hold = right; - pivot = numbers[left]; - while (left < right) { - while ((numbers[right] >= pivot) && (left < right)) - right--; - if (left != right) { - numbers[left] = numbers[right]; - left++; - } - while ((numbers[left] <= pivot) && (left < right)) - left++; - if (left != right) { - numbers[right] = numbers[left]; - right--; - } - } - numbers[left] = pivot; - pivot = left; - left = l_hold; - right = r_hold; - if (left < pivot) - _quick_sort(numbers, left, pivot - 1); - if (right > pivot) - _quick_sort(numbers, pivot + 1, right); + const guint32 *x = a; + const guint32 *y = b; + return (*x - *y); } static void _sort(guint32 *list) @@ -77,7 +52,7 @@ gint i; for (i = 0; list[i] < 0xffffffff; i++) {; } - _quick_sort((gint *) list, 0, i - 1); + qsort (list, i, sizeof (guint32), _compare_guint32); } static void _qq_group_member_opt(PurpleConnection *gc, qq_group *group, gint operation, guint32 *members)
--- a/libpurple/xmlnode.c Fri Dec 28 02:49:10 2007 +0000 +++ b/libpurple/xmlnode.c Fri Dec 28 02:49:23 2007 +0000 @@ -345,6 +345,7 @@ g_free(node->name); g_free(node->data); g_free(node->xmlns); + g_free(node->prefix); if(node->namespace_map) g_hash_table_destroy(node->namespace_map);
--- a/pidgin/gtkaccount.c Fri Dec 28 02:49:10 2007 +0000 +++ b/pidgin/gtkaccount.c Fri Dec 28 02:49:23 2007 +0000 @@ -1759,16 +1759,14 @@ } } -static gint +static gboolean accedit_win_destroy_cb(GtkWidget *w, GdkEvent *event, AccountsWindow *dialog) { - /* Since this is called as the window is closing, we don't need - * pidgin_accounts_window_hide() to also dispose of the window */ dialog->window = NULL; pidgin_accounts_window_hide(); - return 0; + return FALSE; } static gboolean @@ -2102,24 +2100,24 @@ GtkTreeViewColumn *column; GtkTreeIter iter; PurpleAccount *account; - const gchar *title; dialog = (AccountsWindow *)user_data; + if (event->window != gtk_tree_view_get_bin_window(treeview)) + return FALSE; + /* Figure out which node was clicked */ if (!gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(dialog->treeview), event->x, event->y, &path, &column, NULL, NULL)) return FALSE; - title = gtk_tree_view_column_get_title(column); - /* The -1 is required because the first two columns of the list - * store are displayed as only one column in the tree view. */ - column = gtk_tree_view_get_column(treeview, COLUMN_ENABLED-1); + if (column == gtk_tree_view_get_column(treeview, 0)) + return FALSE; + gtk_tree_model_get_iter(GTK_TREE_MODEL(dialog->model), &iter, path); gtk_tree_path_free(path); gtk_tree_model_get(GTK_TREE_MODEL(dialog->model), &iter, COLUMN_DATA, &account, -1); if ((account != NULL) && (event->button == 1) && - (event->type == GDK_2BUTTON_PRESS) && - (strcmp(gtk_tree_view_column_get_title(column), title))) + (event->type == GDK_2BUTTON_PRESS)) { pidgin_account_dialog_show(PIDGIN_MODIFY_ACCOUNT_DIALOG, account); return TRUE;
--- a/pidgin/gtkblist.c Fri Dec 28 02:49:10 2007 +0000 +++ b/pidgin/gtkblist.c Fri Dec 28 02:49:23 2007 +0000 @@ -409,6 +409,7 @@ static void gtk_blist_renderer_editing_cancelled_cb(GtkCellRenderer *renderer, PurpleBuddyList *list) { editing_blist = FALSE; + g_object_set(G_OBJECT(renderer), "editable", FALSE, NULL); pidgin_blist_refresh(list); } @@ -534,12 +535,14 @@ if (node_alias && !g_utf8_collate(node_alias, a)) { merges = g_list_append(merges, buddy); i++; + g_free(node_alias); + break; } g_free(node_alias); } } g_free(a); - + if (i > 1) { char *msg = g_strdup_printf(ngettext("You have %d contact named %s. Would you like to merge them?", "You currently have %d contacts named %s. Would you like to merge them?", i), i, alias); @@ -2575,28 +2578,37 @@ static struct tooltip_data * create_tip_for_node(PurpleBlistNode *node, gboolean full) { - char *tooltip_text = NULL; struct tooltip_data *td = g_new0(struct tooltip_data, 1); PurpleAccount *account = NULL; - char *tmp, *node_name; - - if(PURPLE_BLIST_NODE_IS_BUDDY(node)) { + char *tmp = NULL, *node_name = NULL, *tooltip_text = NULL; + + if (PURPLE_BLIST_NODE_IS_BUDDY(node)) { account = ((PurpleBuddy*)(node))->account; - } else if(PURPLE_BLIST_NODE_IS_CHAT(node)) { + } else if (PURPLE_BLIST_NODE_IS_CHAT(node)) { account = ((PurpleChat*)(node))->account; } td->status_icon = pidgin_blist_get_status_icon(node, PIDGIN_STATUS_ICON_LARGE); td->avatar = pidgin_blist_get_buddy_icon(node, !full, FALSE); - td->prpl_icon = pidgin_create_prpl_icon(account, PIDGIN_PRPL_ICON_SMALL); + if (account != NULL) { + td->prpl_icon = pidgin_create_prpl_icon(account, PIDGIN_PRPL_ICON_SMALL); + } tooltip_text = pidgin_get_tooltip_text(node, full); td->layout = gtk_widget_create_pango_layout(gtkblist->tipwindow, NULL); td->name_layout = gtk_widget_create_pango_layout(gtkblist->tipwindow, NULL); - if (PURPLE_BLIST_NODE_IS_BUDDY(node)) + if (PURPLE_BLIST_NODE_IS_BUDDY(node)) { tmp = g_markup_escape_text(purple_buddy_get_name((PurpleBuddy*)node), -1); - else + } else if (PURPLE_BLIST_NODE_IS_CHAT(node)) { tmp = g_markup_escape_text(purple_chat_get_name((PurpleChat*)node), -1); + } else if (PURPLE_BLIST_NODE_IS_GROUP(node)) { + tmp = g_markup_escape_text(purple_group_get_name((PurpleGroup*)node), -1); + } else { + /* I don't believe this can happen currently, I think + * everything that calls this function checks for one of the + * above node types first. */ + tmp = g_strdup(_("Unknown node type")); + } node_name = g_strdup_printf("<span size='x-large' weight='bold'>%s</span>", tmp); g_free(tmp); @@ -2647,8 +2659,6 @@ return FALSE; style = gtkblist->tipwindow->style; - gtk_paint_flat_box(style, gtkblist->tipwindow->window, GTK_STATE_NORMAL, GTK_SHADOW_OUT, - NULL, gtkblist->tipwindow, "tooltip", 0, 0, -1, -1); max_text_width = 0; max_avatar_width = 0; @@ -2687,14 +2697,16 @@ } #if GTK_CHECK_VERSION(2,2,0) - if (dir == GTK_TEXT_DIR_RTL) - gdk_draw_pixbuf(GDK_DRAWABLE(gtkblist->tipwindow->window), NULL, td->status_icon, - 0, 0, max_width - TOOLTIP_BORDER - STATUS_SIZE, current_height, -1, -1, GDK_RGB_DITHER_NONE, 0, 0); - else - gdk_draw_pixbuf(GDK_DRAWABLE(gtkblist->tipwindow->window), NULL, td->status_icon, - 0, 0, TOOLTIP_BORDER, current_height, -1 , -1, GDK_RGB_DITHER_NONE, 0, 0); - if(td->avatar) - { + if (td->status_icon) { + if (dir == GTK_TEXT_DIR_RTL) + gdk_draw_pixbuf(GDK_DRAWABLE(gtkblist->tipwindow->window), NULL, td->status_icon, + 0, 0, max_width - TOOLTIP_BORDER - STATUS_SIZE, current_height, -1, -1, GDK_RGB_DITHER_NONE, 0, 0); + else + gdk_draw_pixbuf(GDK_DRAWABLE(gtkblist->tipwindow->window), NULL, td->status_icon, + 0, 0, TOOLTIP_BORDER, current_height, -1 , -1, GDK_RGB_DITHER_NONE, 0, 0); + } + + if(td->avatar) { if (dir == GTK_TEXT_DIR_RTL) gdk_draw_pixbuf(GDK_DRAWABLE(gtkblist->tipwindow->window), NULL, td->avatar, 0, 0, TOOLTIP_BORDER, current_height, -1, -1, GDK_RGB_DITHER_NONE, 0, 0); @@ -2704,7 +2716,7 @@ current_height, -1 , -1, GDK_RGB_DITHER_NONE, 0, 0); } - if (!td->avatar_is_prpl_icon) + if (!td->avatar_is_prpl_icon && td->prpl_icon) gdk_draw_pixbuf(GDK_DRAWABLE(gtkblist->tipwindow->window), NULL, td->prpl_icon, 0, 0, prpl_col, @@ -2712,7 +2724,9 @@ -1 , -1, GDK_RGB_DITHER_NONE, 0, 0); #else - gdk_pixbuf_render_to_drawable(td->status_icon, GDK_DRAWABLE(gtkblist->tipwindow->window), NULL, 0, 0, 12, current_height, -1, -1, GDK_RGB_DITHER_NONE, 0, 0); + if (td->status_icon) { + gdk_pixbuf_render_to_drawable(td->status_icon, GDK_DRAWABLE(gtkblist->tipwindow->window), NULL, 0, 0, 12, current_height, -1, -1, GDK_RGB_DITHER_NONE, 0, 0); + } if(td->avatar) gdk_pixbuf_render_to_drawable(td->avatar, GDK_DRAWABLE(gtkblist->tipwindow->window), NULL, 0, 0, @@ -2777,8 +2791,15 @@ PurpleBlistNode *node = data; int width, height; + if (gtkblist->tooltipdata) { + gtkblist->tipwindow = NULL; + pidgin_blist_destroy_tooltip_data(); + } + gtkblist->tipwindow = widget; - if(PURPLE_BLIST_NODE_IS_CHAT(node) || PURPLE_BLIST_NODE_IS_BUDDY(node)) { + if(PURPLE_BLIST_NODE_IS_CHAT(node) || + PURPLE_BLIST_NODE_IS_BUDDY(node) || + PURPLE_BLIST_NODE_IS_GROUP(node)) { struct tooltip_data *td = create_tip_for_node(node, TRUE); gtkblist->tooltipdata = g_list_append(gtkblist->tooltipdata, td); width = TOOLTIP_BORDER + STATUS_SIZE + SMALL_SPACE + @@ -3271,10 +3292,44 @@ g_free(tmp); purple_notify_user_info_destroy(user_info); - } - - purple_signal_emit(pidgin_blist_get_handle(), - "drawing-tooltip", node, str, full); + } else if (PURPLE_BLIST_NODE_IS_GROUP(node)) { + GSList *accounts; + PurpleGroup *group = (PurpleGroup*)node; + PurpleNotifyUserInfo *user_info; + + user_info = purple_notify_user_info_new(); + + /* Total buddies (from online accounts) in group */ + tmp = g_strdup_printf("%d", + purple_blist_get_group_size(group, FALSE)); + purple_notify_user_info_add_pair(user_info, _("Total Buddies"), + tmp); + g_free(tmp); + + /* Online buddies in group */ + tmp = g_strdup_printf("%d", + purple_blist_get_group_online_count(group)); + purple_notify_user_info_add_pair(user_info, _("Online Buddies"), + tmp); + g_free(tmp); + + /* Accounts with buddies in group */ + accounts = purple_group_get_accounts(group); + for (; accounts != NULL; + accounts = g_slist_delete_link(accounts, accounts)) { + PurpleAccount *account = accounts->data; + purple_notify_user_info_add_pair(user_info, _("Account"), purple_account_get_username(account)); + } + + tmp = purple_notify_user_info_get_text_with_newline(user_info, "\n"); + g_string_append(str, tmp); + g_free(tmp); + + purple_notify_user_info_destroy(user_info); + } + + purple_signal_emit(pidgin_blist_get_handle(), "drawing-tooltip", + node, str, full); return g_string_free(str, FALSE); }
--- a/pidgin/gtkconv.c Fri Dec 28 02:49:10 2007 +0000 +++ b/pidgin/gtkconv.c Fri Dec 28 02:49:23 2007 +0000 @@ -67,6 +67,7 @@ #include "gtkthemes.h" #include "gtkutils.h" #include "pidginstock.h" +#include "pidgintooltip.h" #include "gtknickcolors.h" @@ -164,8 +165,6 @@ static void focus_out_from_menubar(GtkWidget *wid, PidginWindow *win); static void pidgin_conv_tab_pack(PidginWindow *win, PidginConversation *gtkconv); static gboolean infopane_press_cb(GtkWidget *widget, GdkEventButton *e, PidginConversation *conv); -static gboolean pidgin_userlist_motion_cb (GtkWidget *w, GdkEventMotion *event, PidginConversation *gtkconv); -static gboolean pidgin_conv_leave_cb (GtkWidget *w, GdkEventCrossing *e, PidginConversation *gtkconv); static void hide_conv(PidginConversation *gtkconv, gboolean closetimer); static void pidgin_conv_set_position_size(PidginWindow *win, int x, int y, @@ -4434,6 +4433,36 @@ } } +static gboolean +pidgin_conv_userlist_create_tooltip(GtkWidget *tipwindow, GtkTreePath *path, + gpointer userdata, int *w, int *h) +{ + PidginConversation *gtkconv = userdata; + GtkTreeIter iter; + GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(gtkconv->u.chat->list)); + PurpleConversation *conv = gtkconv->active_conv; + PurpleBlistNode *node; + PurplePluginProtocolInfo *prpl_info; + PurpleAccount *account = purple_conversation_get_account(conv); + char *who = NULL; + + if (account->gc == NULL) + return FALSE; + + if (!gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, path)) + return FALSE; + + gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, CHAT_USERS_NAME_COLUMN, &who, -1); + + prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(account->gc->prpl); + node = (PurpleBlistNode*)(purple_find_buddy(conv->account, who)); + if (node && prpl_info && (prpl_info->options & OPT_PROTO_UNIQUE_CHATNAME)) + pidgin_blist_draw_tooltip(node, gtkconv->infopane); + + g_free(who); + return FALSE; +} + static void setup_chat_userlist(PidginConversation *gtkconv, GtkWidget *hpaned) { @@ -4488,14 +4517,13 @@ g_signal_connect(G_OBJECT(list), "button_press_event", G_CALLBACK(right_click_chat_cb), gtkconv); - g_signal_connect(G_OBJECT(list), "motion-notify-event", - G_CALLBACK(pidgin_userlist_motion_cb), gtkconv); - g_signal_connect(G_OBJECT(list), "leave-notify-event", - G_CALLBACK(pidgin_conv_leave_cb), gtkconv); g_signal_connect(G_OBJECT(list), "popup-menu", G_CALLBACK(gtkconv_chat_popup_menu_cb), gtkconv); g_signal_connect(G_OBJECT(lbox), "size-allocate", G_CALLBACK(lbox_size_allocate_cb), gtkconv); + pidgin_tooltip_setup_for_treeview(list, gtkconv, + pidgin_conv_userlist_create_tooltip, NULL); + rend = gtk_cell_renderer_text_new(); g_object_set(rend, "foreground-set", TRUE, @@ -4531,32 +4559,12 @@ gtk_container_add(GTK_CONTAINER(sw), list); } -/* Stuff used to display tooltips on the infopane */ -static struct { - int timeout; - PidginConversation *gtkconv; /* This is the Pidgin conversation that - triggered the tooltip */ - int userlistx; - int userlisty; -} tooltip; - -static void -reset_tooltip() -{ - if (tooltip.timeout != 0) { - g_source_remove(tooltip.timeout); - tooltip.timeout = 0; - } - tooltip.gtkconv = NULL; -} - static gboolean -pidgin_conv_tooltip_timeout(PidginConversation *gtkconv) +pidgin_conv_create_tooltip(GtkWidget *tipwindow, gpointer userdata, int *w, int *h) { PurpleBlistNode *node = NULL; PurpleConversation *conv; - - g_return_val_if_fail (tooltip.gtkconv == gtkconv, FALSE); + PidginConversation *gtkconv = userdata; conv = gtkconv->active_conv; if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_CHAT) { @@ -4579,103 +4587,6 @@ return FALSE; } -static gboolean -pidgin_conv_leave_cb (GtkWidget *w, GdkEventCrossing *e, PidginConversation *gtkconv) -{ - pidgin_blist_tooltip_destroy(); - reset_tooltip(); - return FALSE; -} - -static gboolean -pidgin_conv_motion_cb (GtkWidget *infopane, GdkEventMotion *event, PidginConversation *gtkconv) -{ - int delay = purple_prefs_get_int(PIDGIN_PREFS_ROOT "/blist/tooltip_delay"); - - pidgin_blist_tooltip_destroy(); - if (delay == 0) - return FALSE; - - if (tooltip.timeout != 0) - g_source_remove(tooltip.timeout); - - tooltip.timeout = g_timeout_add(delay, (GSourceFunc)pidgin_conv_tooltip_timeout, gtkconv); - tooltip.gtkconv = gtkconv; - return FALSE; -} - -static gboolean -pidgin_userlist_tooltip_timeout(PidginConversation *gtkconv) -{ - PurplePluginProtocolInfo *prpl_info; - PurpleConversation *conv = gtkconv->active_conv; - PidginChatPane *gtkchat; - PurpleBlistNode *node = NULL; - PurpleAccount *account; - GtkTreePath *path; - GtkTreeIter iter; - GtkTreeModel *model; - GtkTreeViewColumn *column; - gchar *who; - int x, y; - - gtkchat = gtkconv->u.chat; - account = purple_conversation_get_account(conv); - - if (account->gc == NULL) - return FALSE; - - prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(account->gc->prpl); - - model = gtk_tree_view_get_model(GTK_TREE_VIEW(gtkchat->list)); - - if (!gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(gtkchat->list), - tooltip.userlistx, tooltip.userlisty, &path, &column, &x, &y)) - return FALSE; - - gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, path); - gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, CHAT_USERS_NAME_COLUMN, &who, -1); - - node = (PurpleBlistNode*)(purple_find_buddy(conv->account, who)); - if (node && prpl_info && (prpl_info->options & OPT_PROTO_UNIQUE_CHATNAME)) - pidgin_blist_draw_tooltip(node, gtkconv->infopane); - - g_free(who); - gtk_tree_path_free(path); - - - return FALSE; -} - -static gboolean -pidgin_userlist_motion_cb (GtkWidget *w, GdkEventMotion *event, PidginConversation *gtkconv) -{ - PurpleConversation *conv; - PurpleAccount *account; - int delay = purple_prefs_get_int(PIDGIN_PREFS_ROOT "/blist/tooltip_delay"); - - pidgin_blist_tooltip_destroy(); - if (delay == 0) - return FALSE; - - if (tooltip.timeout != 0) - g_source_remove(tooltip.timeout); - tooltip.timeout = 0; - - conv = gtkconv->active_conv; - account = purple_conversation_get_account(conv); - - if (account->gc == NULL) - return FALSE; - - tooltip.timeout = g_timeout_add(delay, (GSourceFunc)pidgin_userlist_tooltip_timeout, gtkconv); - tooltip.gtkconv = gtkconv; - tooltip.userlistx = event->x; - tooltip.userlisty = event->y; - - return FALSE; -} - static GtkWidget * setup_common_pane(PidginConversation *gtkconv) { @@ -4705,10 +4616,8 @@ g_signal_connect(G_OBJECT(event_box), "button-press-event", G_CALLBACK(infopane_press_cb), gtkconv); - g_signal_connect(G_OBJECT(event_box), "motion-notify-event", - G_CALLBACK(pidgin_conv_motion_cb), gtkconv); - g_signal_connect(G_OBJECT(event_box), "leave-notify-event", - G_CALLBACK(pidgin_conv_leave_cb), gtkconv); + pidgin_tooltip_setup_for_widget(event_box, gtkconv, + pidgin_conv_create_tooltip, NULL); gtkconv->infopane = gtk_cell_view_new(); gtkconv->infopane_model = gtk_list_store_new(CONV_NUM_COLUMNS, GDK_TYPE_PIXBUF, G_TYPE_STRING, GDK_TYPE_PIXBUF, GDK_TYPE_PIXBUF); @@ -5214,9 +5123,6 @@ g_source_remove(gtkconv->attach.timer); } - if (tooltip.gtkconv == gtkconv) - reset_tooltip(); - g_free(gtkconv); } @@ -6925,10 +6831,8 @@ GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK); g_signal_connect(G_OBJECT(event), "button-press-event", G_CALLBACK(icon_menu), gtkconv); - g_signal_connect(G_OBJECT(event), "motion-notify-event", - G_CALLBACK(pidgin_conv_motion_cb), gtkconv); - g_signal_connect(G_OBJECT(event), "leave-notify-event", - G_CALLBACK(pidgin_conv_leave_cb), gtkconv); + + pidgin_tooltip_setup_for_widget(event, gtkconv, pidgin_conv_create_tooltip, NULL); gtk_widget_show(event); gtkconv->u.im->icon = gtk_image_new_from_pixbuf(scale);
--- a/pidgin/gtkft.c Fri Dec 28 02:49:10 2007 +0000 +++ b/pidgin/gtkft.c Fri Dec 28 02:49:23 2007 +0000 @@ -156,15 +156,15 @@ } if (time_remaining != NULL) { - if (purple_xfer_get_size(xfer) == 0) { - *time_remaining = g_strdup(_("Unknown")); - } - else if (purple_xfer_is_completed(xfer)) { + if (purple_xfer_is_completed(xfer)) { *time_remaining = g_strdup(_("Finished")); } else if (purple_xfer_is_canceled(xfer)) { *time_remaining = g_strdup(_("Canceled")); } + else if (purple_xfer_get_size(xfer) == 0 || (kb_sent > 0 && kbps == 0)) { + *time_remaining = g_strdup(_("Unknown")); + } else if (kb_sent <= 0) { *time_remaining = g_strdup(_("Waiting for transfer to begin")); }
--- a/pidgin/gtkplugin.c Fri Dec 28 02:49:10 2007 +0000 +++ b/pidgin/gtkplugin.c Fri Dec 28 02:49:23 2007 +0000 @@ -31,6 +31,7 @@ #include "debug.h" #include "prefs.h" #include "request.h" +#include "pidgintooltip.h" #include <string.h> @@ -531,6 +532,58 @@ plugin_dialog_response_cb(dialog, PIDGIN_RESPONSE_CONFIGURE, sel); } +static gboolean +pidgin_plugins_paint_tooltip(GtkWidget *tipwindow, gpointer data) +{ + PangoLayout *layout = g_object_get_data(G_OBJECT(tipwindow), "tooltip-plugin"); + gtk_paint_layout(tipwindow->style, tipwindow->window, GTK_STATE_NORMAL, FALSE, + NULL, tipwindow, "tooltip", + 6, 6, layout); + return TRUE; +} + +static gboolean +pidgin_plugins_create_tooltip(GtkWidget *tipwindow, GtkTreePath *path, + gpointer data, int *w, int *h) +{ + GtkTreeIter iter; + GtkTreeView *treeview = GTK_TREE_VIEW(data); + PurplePlugin *plugin = NULL; + GtkTreeModel *model = gtk_tree_view_get_model(treeview); + PangoLayout *layout; + int width, height; + char *markup, *name, *desc, *author; + + if (!gtk_tree_model_get_iter(model, &iter, path)) + return FALSE; + + gtk_tree_model_get(model, &iter, 2, &plugin, -1); + + markup = g_strdup_printf("<span size='x-large' weight='bold'>%s</span>\n<b>Description:</b> %s\n<b>Author:</b> %s", + name = g_markup_escape_text(purple_plugin_get_name(plugin), -1), + desc = g_markup_escape_text(purple_plugin_get_description(plugin), -1), + author = g_markup_escape_text(purple_plugin_get_author(plugin), -1)); + + layout = gtk_widget_create_pango_layout(tipwindow, NULL); + pango_layout_set_markup(layout, markup, -1); + pango_layout_set_wrap(layout, PANGO_WRAP_WORD); + pango_layout_set_width(layout, 600000); + pango_layout_get_size(layout, &width, &height); + g_object_set_data_full(G_OBJECT(tipwindow), "tooltip-plugin", layout, g_object_unref); + + if (w) + *w = PANGO_PIXELS(width) + 12; + if (h) + *h = PANGO_PIXELS(height) + 12; + + g_free(markup); + g_free(name); + g_free(desc); + g_free(author); + + return TRUE; +} + void pidgin_plugin_dialog_show() { GtkWidget *sw; @@ -613,6 +666,10 @@ gtk_tree_view_set_search_equal_func(GTK_TREE_VIEW(event_view), pidgin_tree_view_search_equal_func, NULL, NULL); + pidgin_tooltip_setup_for_treeview(event_view, event_view, + pidgin_plugins_create_tooltip, + pidgin_plugins_paint_tooltip); + expander = gtk_expander_new(_("<b>Plugin Details</b>")); gtk_expander_set_use_markup(GTK_EXPANDER(expander), TRUE); plugin_details = gtk_label_new(NULL);
--- a/pidgin/gtkroomlist.c Fri Dec 28 02:49:10 2007 +0000 +++ b/pidgin/gtkroomlist.c Fri Dec 28 02:49:23 2007 +0000 @@ -356,8 +356,6 @@ GtkTextDirection dir = gtk_widget_get_direction(GTK_WIDGET(grl->tree)); style = grl->tipwindow->style; - gtk_paint_flat_box(style, grl->tipwindow->window, GTK_STATE_NORMAL, GTK_SHADOW_OUT, - NULL, grl->tipwindow, "tooltip", 0, 0, -1, -1); max_text_width = 0;
--- a/pidgin/minidialog.c Fri Dec 28 02:49:10 2007 +0000 +++ b/pidgin/minidialog.c Fri Dec 28 02:49:23 2007 +0000 @@ -63,6 +63,7 @@ sizeof (PidginMiniDialog), 0, /* n_preallocs */ (GInstanceInitFunc) pidgin_mini_dialog_init, + NULL, }; g_define_type_id = g_type_register_static (GTK_TYPE_VBOX, "PidginMiniDialog", &g_define_type_info, 0);
--- a/pidgin/pidgincombobox.c Fri Dec 28 02:49:10 2007 +0000 +++ b/pidgin/pidgincombobox.c Fri Dec 28 02:49:23 2007 +0000 @@ -2980,7 +2980,7 @@ g_return_if_fail (link != NULL); - combo_box->priv->cells = g_slist_remove_link (combo_box->priv->cells, link); + combo_box->priv->cells = g_slist_delete_link (combo_box->priv->cells, link); combo_box->priv->cells = g_slist_insert (combo_box->priv->cells, info, position);
--- a/pidgin/pidgintooltip.c Fri Dec 28 02:49:10 2007 +0000 +++ b/pidgin/pidgintooltip.c Fri Dec 28 02:49:23 2007 +0000 @@ -43,15 +43,22 @@ { GtkWidget *widget; gpointer userdata; - PidginTooltipCreateForTree create_tooltip; PidginTooltipPaint paint_tooltip; - GtkTreePath *path; + union { + struct { + PidginTooltipCreateForTree create_tooltip; + GtkTreePath *path; + } treeview; + struct { + PidginTooltipCreate create_tooltip; + } widget; + } common; } PidginTooltipData; static void destroy_tooltip_data(PidginTooltipData *data) { - gtk_tree_path_free(data->path); + gtk_tree_path_free(data->common.treeview.path); g_free(data); } @@ -70,8 +77,11 @@ static gboolean pidgin_tooltip_expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer data) { - if (pidgin_tooltip.paint_tooltip) + if (pidgin_tooltip.paint_tooltip) { + gtk_paint_flat_box(widget->style, widget->window, GTK_STATE_NORMAL, GTK_SHADOW_OUT, + NULL, widget, "tooltip", 0, 0, -1, -1); pidgin_tooltip.paint_tooltip(widget, data); + } return FALSE; } @@ -184,14 +194,35 @@ static void reset_data_treepath(PidginTooltipData *data) { - gtk_tree_path_free(data->path); - data->path = NULL; + gtk_tree_path_free(data->common.treeview.path); + data->common.treeview.path = NULL; } static void pidgin_tooltip_draw(PidginTooltipData *data) { GtkWidget *tipwindow; + int w, h; + + pidgin_tooltip_destroy(); + + pidgin_tooltip.widget = gtk_widget_get_toplevel(data->widget); + pidgin_tooltip.tipwindow = tipwindow = setup_tooltip_window(); + pidgin_tooltip.paint_tooltip = data->paint_tooltip; + + if (!data->common.widget.create_tooltip(tipwindow, data->userdata, &w, &h)) { + if (tipwindow == pidgin_tooltip.tipwindow) + pidgin_tooltip_destroy(); + return; + } + + setup_tooltip_window_position(data->userdata, w, h); +} + +static void +pidgin_tooltip_draw_tree(PidginTooltipData *data) +{ + GtkWidget *tipwindow; GtkTreePath *path = NULL; int w, h; @@ -203,13 +234,13 @@ return; } - if (data->path) { - if (gtk_tree_path_compare(data->path, path) == 0) { + if (data->common.treeview.path) { + if (gtk_tree_path_compare(data->common.treeview.path, path) == 0) { gtk_tree_path_free(path); return; } - gtk_tree_path_free(data->path); - data->path = NULL; + gtk_tree_path_free(data->common.treeview.path); + data->common.treeview.path = NULL; } pidgin_tooltip_destroy(); @@ -218,24 +249,29 @@ pidgin_tooltip.tipwindow = tipwindow = setup_tooltip_window(); pidgin_tooltip.paint_tooltip = data->paint_tooltip; - if (!data->create_tooltip(tipwindow, path, data->userdata, &w, &h)) { - pidgin_tooltip_destroy(); + if (!data->common.treeview.create_tooltip(tipwindow, path, data->userdata, &w, &h)) { + if (tipwindow == pidgin_tooltip.tipwindow) + pidgin_tooltip_destroy(); gtk_tree_path_free(path); return; } setup_tooltip_window_position(data->userdata, w, h); - data->path = path; - g_signal_connect_swapped(G_OBJECT(tipwindow), "destroy", + data->common.treeview.path = path; + g_signal_connect_swapped(G_OBJECT(pidgin_tooltip.tipwindow), "destroy", G_CALLBACK(reset_data_treepath), data); } static gboolean pidgin_tooltip_timeout(gpointer data) { + PidginTooltipData *tdata = data; pidgin_tooltip.timeout = 0; - pidgin_tooltip_draw(data); + if (GTK_IS_TREE_VIEW(tdata->widget)) + pidgin_tooltip_draw_tree(data); + else + pidgin_tooltip_draw(data); return FALSE; } @@ -276,7 +312,7 @@ } static gboolean -row_leave_cb(GtkWidget *tv, GdkEvent *event, gpointer userdata) +widget_leave_cb(GtkWidget *tv, GdkEvent *event, gpointer userdata) { pidgin_tooltip_destroy(); return FALSE; @@ -288,12 +324,40 @@ PidginTooltipData *tdata = g_new0(PidginTooltipData, 1); tdata->widget = tree; tdata->userdata = userdata; - tdata->create_tooltip = create_tooltip; + tdata->common.treeview.create_tooltip = create_tooltip; tdata->paint_tooltip = paint_tooltip; g_signal_connect(G_OBJECT(tree), "motion-notify-event", G_CALLBACK(row_motion_cb), tdata); - g_signal_connect(G_OBJECT(tree), "leave-notify-event", G_CALLBACK(row_leave_cb), NULL); + g_signal_connect(G_OBJECT(tree), "leave-notify-event", G_CALLBACK(widget_leave_cb), NULL); g_signal_connect_swapped(G_OBJECT(tree), "destroy", G_CALLBACK(destroy_tooltip_data), tdata); return TRUE; } +static gboolean +widget_motion_cb(GtkWidget *widget, GdkEvent *event, gpointer data) +{ + int delay = purple_prefs_get_int(PIDGIN_PREFS_ROOT "/blist/tooltip_delay"); + + pidgin_tooltip_destroy(); + if (delay == 0) + return FALSE; + + pidgin_tooltip.timeout = g_timeout_add(delay, (GSourceFunc)pidgin_tooltip_timeout, data); + return FALSE; +} + +gboolean pidgin_tooltip_setup_for_widget(GtkWidget *widget, gpointer userdata, + PidginTooltipCreate create_tooltip, PidginTooltipPaint paint_tooltip) +{ + PidginTooltipData *wdata = g_new0(PidginTooltipData, 1); + wdata->widget = widget; + wdata->userdata = userdata; + wdata->common.widget.create_tooltip = create_tooltip; + wdata->paint_tooltip = paint_tooltip; + + g_signal_connect(G_OBJECT(widget), "motion-notify-event", G_CALLBACK(widget_motion_cb), wdata); + g_signal_connect(G_OBJECT(widget), "leave-notify-event", G_CALLBACK(widget_leave_cb), NULL); + g_signal_connect_swapped(G_OBJECT(widget), "destroy", G_CALLBACK(g_free), wdata); + return TRUE; +} +
--- a/pidgin/pidgintooltip.h Fri Dec 28 02:49:10 2007 +0000 +++ b/pidgin/pidgintooltip.h Fri Dec 28 02:49:23 2007 +0000 @@ -77,6 +77,20 @@ PidginTooltipCreateForTree create_cb, PidginTooltipPaint paint_cb); /** + * Setup tooltip drawing functions for any widget. + * + * @param widget The widget + * @param userdata The userdata to send to the callback functions + * @param create_cb Callback function to create the tooltip for the widget + * @param paint_cb Callback function to paint the tooltip + * + * @return @c TRUE if the tooltip callbacks were setup correctly. + * @since 2.4.0 + */ +gboolean pidgin_tooltip_setup_for_widget(GtkWidget *widget, gpointer userdata, + PidginTooltipCreate create_tooltip, PidginTooltipPaint paint_tooltip); + +/** * Destroy the tooltip. * @since 2.4.0 */ @@ -94,4 +108,5 @@ */ void pidgin_tooltip_show(GtkWidget *widget, gpointer userdata, PidginTooltipCreate create_cb, PidginTooltipPaint paint_cb); + #endif
--- a/pidgin/win32/nsis/pidgin-installer.nsi Fri Dec 28 02:49:10 2007 +0000 +++ b/pidgin/win32/nsis/pidgin-installer.nsi Fri Dec 28 02:49:23 2007 +0000 @@ -699,6 +699,7 @@ Delete "$INSTDIR\ca-certs\Equifax_Secure_CA.pem" Delete "$INSTDIR\ca-certs\GTE_CyberTrust_Global_Root.pem" Delete "$INSTDIR\ca-certs\Microsoft_Secure_Server_Authority.pem" + Delete "$INSTDIR\ca-certs\StartCom_Free_SSL_CA.pem" Delete "$INSTDIR\ca-certs\Verisign_Class3_Extended_Validation_CA.pem" Delete "$INSTDIR\ca-certs\Verisign_Class3_Primary_CA.pem" Delete "$INSTDIR\ca-certs\Verisign_RSA_Secure_Server_CA.pem"
--- a/share/ca-certs/Makefile.am Fri Dec 28 02:49:10 2007 +0000 +++ b/share/ca-certs/Makefile.am Fri Dec 28 02:49:23 2007 +0000 @@ -3,6 +3,7 @@ Equifax_Secure_CA.pem \ GTE_CyberTrust_Global_Root.pem \ Microsoft_Secure_Server_Authority.pem \ + StartCom_Free_SSL_CA.pem \ Verisign_RSA_Secure_Server_CA.pem \ Verisign_Class3_Primary_CA.pem
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/ca-certs/StartCom_Free_SSL_CA.pem Fri Dec 28 02:49:23 2007 +0000 @@ -0,0 +1,30 @@ +-----BEGIN CERTIFICATE----- +MIIFFjCCBH+gAwIBAgIBADANBgkqhkiG9w0BAQQFADCBsDELMAkGA1UEBhMCSUwx +DzANBgNVBAgTBklzcmFlbDEOMAwGA1UEBxMFRWlsYXQxFjAUBgNVBAoTDVN0YXJ0 +Q29tIEx0ZC4xGjAYBgNVBAsTEUNBIEF1dGhvcml0eSBEZXAuMSkwJwYDVQQDEyBG +cmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJARYS +YWRtaW5Ac3RhcnRjb20ub3JnMB4XDTA1MDMxNzE3Mzc0OFoXDTM1MDMxMDE3Mzc0 +OFowgbAxCzAJBgNVBAYTAklMMQ8wDQYDVQQIEwZJc3JhZWwxDjAMBgNVBAcTBUVp +bGF0MRYwFAYDVQQKEw1TdGFydENvbSBMdGQuMRowGAYDVQQLExFDQSBBdXRob3Jp +dHkgRGVwLjEpMCcGA1UEAxMgRnJlZSBTU0wgQ2VydGlmaWNhdGlvbiBBdXRob3Jp +dHkxITAfBgkqhkiG9w0BCQEWEmFkbWluQHN0YXJ0Y29tLm9yZzCBnzANBgkqhkiG +9w0BAQEFAAOBjQAwgYkCgYEA7YRgACOeyEpRKSfeOqE5tWmrCbIvNP1h3D3TsM+x +18LEwrHkllbEvqoUDufMOlDIOmKdw6OsWXuO7lUaHEe+o5c5s7XvIywI6Nivcy+5 +yYPo7QAPyHWlLzRMGOh2iCNJitu27Wjaw7ViKUylS7eYtAkUEKD4/mJ2IhULpNYI +LzUCAwEAAaOCAjwwggI4MA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgHmMB0G +A1UdDgQWBBQcicOWzL3+MtUNjIExtpidjShkjTCB3QYDVR0jBIHVMIHSgBQcicOW +zL3+MtUNjIExtpidjShkjaGBtqSBszCBsDELMAkGA1UEBhMCSUwxDzANBgNVBAgT +BklzcmFlbDEOMAwGA1UEBxMFRWlsYXQxFjAUBgNVBAoTDVN0YXJ0Q29tIEx0ZC4x +GjAYBgNVBAsTEUNBIEF1dGhvcml0eSBEZXAuMSkwJwYDVQQDEyBGcmVlIFNTTCBD +ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJARYSYWRtaW5Ac3Rh +cnRjb20ub3JnggEAMB0GA1UdEQQWMBSBEmFkbWluQHN0YXJ0Y29tLm9yZzAdBgNV +HRIEFjAUgRJhZG1pbkBzdGFydGNvbS5vcmcwEQYJYIZIAYb4QgEBBAQDAgAHMC8G +CWCGSAGG+EIBDQQiFiBGcmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAy +BglghkgBhvhCAQQEJRYjaHR0cDovL2NlcnQuc3RhcnRjb20ub3JnL2NhLWNybC5j +cmwwKAYJYIZIAYb4QgECBBsWGWh0dHA6Ly9jZXJ0LnN0YXJ0Y29tLm9yZy8wOQYJ +YIZIAYb4QgEIBCwWKmh0dHA6Ly9jZXJ0LnN0YXJ0Y29tLm9yZy9pbmRleC5waHA/ +YXBwPTExMTANBgkqhkiG9w0BAQQFAAOBgQBscSXhnjSRIe/bbL0BCFaPiNhBOlP1 +ct8nV0t2hPdopP7rPwl+KLhX6h/BquL/lp9JmeaylXOWxkjHXo0Hclb4g4+fd68p +00UOpO6wNnQt8M2YI3s3S9r+UZjEHjQ8iP2ZO1CnwYszx8JSFhKVU2Ui77qLzmLb +cCOxgN8aIDjnfg== +-----END CERTIFICATE-----