# HG changeset patch # User Elliott Sales de Andrade # Date 1267330059 0 # Node ID 6d3a90b49dba068afdb8b8dabb7a885b9a63b027 # Parent 221cebbc35d86c5b7b5c5f47a4f3464b82c32835# Parent f8a95fdab3bdf034e38525c519ae857feb81dba1 propagate from branch 'im.pidgin.pidgin' (head 8587687655d4e11f0965358e8a4378cfa3d1e4e7) to branch 'im.pidgin.cpw.malu.ft_thumbnails' (head 14eca8a36cf4d5e66226c1d94d6d44b5219b1476) diff -r 221cebbc35d8 -r 6d3a90b49dba COPYRIGHT --- a/COPYRIGHT Thu Feb 18 22:28:41 2010 +0000 +++ b/COPYRIGHT Sun Feb 28 04:07:39 2010 +0000 @@ -228,6 +228,7 @@ Instant Messaging Freedom, Inc. Vitaliy Ischenko Intel Corporation +Andrew Ivanov Scott Jackson Hans Petter Jansson David Jedelsky @@ -237,7 +238,7 @@ Yuriy Kaminskiy Anders Kaseorg Praveen Karadakal -Jaromír Karmazín +Tomáš Kebert John Kelm Jochen Kemnade Yann Kerherve @@ -541,6 +542,7 @@ Jared Yanovich Timmy Yee Li Yuan +Yuriy Yevgrafov Nickolai Zeldovich Tom Zickel Marco Ziech diff -r 221cebbc35d8 -r 6d3a90b49dba ChangeLog --- a/ChangeLog Thu Feb 18 22:28:41 2010 +0000 +++ b/ChangeLog Sun Feb 28 04:07:39 2010 +0000 @@ -18,6 +18,9 @@ * Make the search dialog unobtrusive in the conversation window (by making it look and behave like the search dialog in Firefox) + Bonjour: + * Added support for IPv6. (Thanks to T_X for testing) + version 2.6.6 (02/18/2010): libpurple: * Fix 'make check' on OS X. (David Fang) diff -r 221cebbc35d8 -r 6d3a90b49dba ChangeLog.API --- a/ChangeLog.API Thu Feb 18 22:28:41 2010 +0000 +++ b/ChangeLog.API Sun Feb 28 04:07:39 2010 +0000 @@ -146,6 +146,7 @@ * xmlnode_from_file * xmlnode_get_parent * xmlnode_set_attrib_full + * PURPLE_STATUS_MOOD as a new PurpleStatusPrimitive Changed: * xmlnode_remove_attrib now removes all attributes with the diff -r 221cebbc35d8 -r 6d3a90b49dba finch/gntplugin.c --- a/finch/gntplugin.c Thu Feb 18 22:28:41 2010 +0000 +++ b/finch/gntplugin.c Sun Feb 28 04:07:39 2010 +0000 @@ -498,7 +498,7 @@ break; } stringlist = g_list_prepend(stringlist, value); - purple_request_field_list_add(field, label, value); + purple_request_field_list_add_icon(field, label, NULL, value); if (strcmp(value, current_value) == 0) purple_request_field_list_add_selected(field, label); list = list->next->next; diff -r 221cebbc35d8 -r 6d3a90b49dba finch/gntprefs.c --- a/finch/gntprefs.c Thu Feb 18 22:28:41 2010 +0000 +++ b/finch/gntprefs.c Sun Feb 28 04:07:39 2010 +0000 @@ -171,7 +171,7 @@ default: break; } - purple_request_field_list_add(field, data, iter->data); + purple_request_field_list_add_icon(field, data, NULL, iter->data); if (select) purple_request_field_list_add_selected(field, data); } diff -r 221cebbc35d8 -r 6d3a90b49dba finch/plugins/gnthistory.c --- a/finch/plugins/gnthistory.c Thu Feb 18 22:28:41 2010 +0000 +++ b/finch/plugins/gnthistory.c Sun Feb 28 04:07:39 2010 +0000 @@ -158,7 +158,7 @@ while (list) { const char *label = _(list->data); list = g_list_delete_link(list, list); - purple_request_field_list_add(field, label, list->data); + purple_request_field_list_add_icon(field, label, NULL, list->data); if (system && strcmp(system, list->data) == 0) purple_request_field_list_add_selected(field, label); list = g_list_delete_link(list, list); diff -r 221cebbc35d8 -r 6d3a90b49dba libpurple/Makefile.mingw --- a/libpurple/Makefile.mingw Thu Feb 18 22:28:41 2010 +0000 +++ b/libpurple/Makefile.mingw Sun Feb 28 04:07:39 2010 +0000 @@ -8,7 +8,7 @@ include $(PIDGIN_TREE_TOP)/libpurple/win32/global.mak TARGET = libpurple -NEEDED_DLLS = $(LIBXML2_TOP)/bin/libxml2.dll +NEEDED_DLLS = $(LIBXML2_TOP)/bin/libxml2-2.dll ## ## INCLUDE PATHS @@ -20,7 +20,7 @@ -I$(GTK_TOP)/include \ -I$(GTK_TOP)/include/glib-2.0 \ -I$(GTK_TOP)/lib/glib-2.0/include \ - -I$(LIBXML2_TOP)/include + -I$(LIBXML2_TOP)/include/libxml2 LIB_PATHS += -L$(GTK_TOP)/lib \ -L$(LIBXML2_TOP)/lib diff -r 221cebbc35d8 -r 6d3a90b49dba libpurple/example/nullclient.c --- a/libpurple/example/nullclient.c Thu Feb 18 22:28:41 2010 +0000 +++ b/libpurple/example/nullclient.c Sun Feb 28 04:07:39 2010 +0000 @@ -27,7 +27,11 @@ #include #include +#ifndef _WIN32 #include +#else +#include "win32/win32dep.h" +#endif #include "defines.h" @@ -80,7 +84,11 @@ if (condition & PURPLE_INPUT_WRITE) cond |= PURPLE_GLIB_WRITE_COND; +#if defined _WIN32 && !defined WINPIDGIN_USE_GLIB_IO_CHANNEL + channel = wpurple_g_io_channel_win32_new_socket(fd); +#else channel = g_io_channel_unix_new(fd); +#endif closure->result = g_io_add_watch_full(channel, G_PRIORITY_DEFAULT, cond, purple_glib_io_invoke, closure, purple_glib_io_destroy); @@ -253,12 +261,14 @@ PurpleSavedStatus *status; char *res; +#ifndef _WIN32 /* libpurple's built-in DNS resolution forks processes to perform * blocking lookups without blocking the main process. It does not * handle SIGCHLD itself, so if the UI does not you quickly get an army * of zombie subprocesses marching around. */ signal(SIGCHLD, SIG_IGN); +#endif init_libpurple(); diff -r 221cebbc35d8 -r 6d3a90b49dba libpurple/plugins/log_reader.c --- a/libpurple/plugins/log_reader.c Thu Feb 18 22:28:41 2010 +0000 +++ b/libpurple/plugins/log_reader.c Sun Feb 28 04:07:39 2010 +0000 @@ -2644,7 +2644,7 @@ g_free(contents); } g_free(path); -#endif /* !GTK_CHECK_VERSION(2,6,0) */ +#endif /* !GLIB_CHECK_VERSION(2,6,0) */ } /* path */ if (!found) { diff -r 221cebbc35d8 -r 6d3a90b49dba libpurple/plugins/perl/common/Request.xs --- a/libpurple/plugins/perl/common/Request.xs Thu Feb 18 22:28:41 2010 +0000 +++ b/libpurple/plugins/perl/common/Request.xs Sun Feb 28 04:07:39 2010 +0000 @@ -380,6 +380,13 @@ void * data void +purple_request_field_list_add_icon(field, item, icon_path, data) + Purple::Request::Field field + const char *item + const char *icon_path + void * data + +void purple_request_field_list_add_selected(field, item) Purple::Request::Field field const char *item diff -r 221cebbc35d8 -r 6d3a90b49dba libpurple/protocols/bonjour/Makefile.mingw --- a/libpurple/protocols/bonjour/Makefile.mingw Thu Feb 18 22:28:41 2010 +0000 +++ b/libpurple/protocols/bonjour/Makefile.mingw Sun Feb 28 04:07:39 2010 +0000 @@ -30,7 +30,7 @@ -I$(GTK_TOP)/include/glib-2.0 \ -I$(GTK_TOP)/lib/glib-2.0/include \ -I$(BONJOUR_TOP)/Include \ - -I$(LIBXML2_TOP)/include \ + -I$(LIBXML2_TOP)/include/libxml2 \ -I$(PURPLE_TOP) \ -I$(PURPLE_TOP)/win32 \ -I$(PIDGIN_TREE_TOP) diff -r 221cebbc35d8 -r 6d3a90b49dba libpurple/protocols/bonjour/bonjour.c --- a/libpurple/protocols/bonjour/bonjour.c Thu Feb 18 22:28:41 2010 +0000 +++ b/libpurple/protocols/bonjour/bonjour.c Sun Feb 28 04:07:39 2010 +0000 @@ -101,6 +101,8 @@ /* Start waiting for jabber connections (iChat style) */ bd->jabber_data = g_new0(BonjourJabber, 1); + bd->jabber_data->socket = -1; + bd->jabber_data->socket6 = -1; bd->jabber_data->port = purple_account_get_int(account, "port", BONJOUR_DEFAULT_PORT); bd->jabber_data->account = account; @@ -525,7 +527,8 @@ sizeof(PurplePluginProtocolInfo), /* struct_size */ NULL, /* get_account_text_table */ NULL, /* initiate_media */ - NULL /* can_do_media */ + NULL, /* get_media_caps */ + NULL /* get_moods */ }; static PurplePluginInfo info = diff -r 221cebbc35d8 -r 6d3a90b49dba libpurple/protocols/bonjour/bonjour_ft.c --- a/libpurple/protocols/bonjour/bonjour_ft.c Thu Feb 18 22:28:41 2010 +0000 +++ b/libpurple/protocols/bonjour/bonjour_ft.c Sun Feb 28 04:07:39 2010 +0000 @@ -747,8 +747,7 @@ XepIq *iq; xmlnode *query, *streamhost; gchar *port; - const char *next_ip, *local_ip; - const char token [] = ";"; + GSList *local_ips; BonjourData *bd; purple_debug_info("bonjour", "Bonjour-bytestreams-listen. sock=%d.\n", sock); @@ -773,17 +772,16 @@ xfer->local_port = purple_network_get_port_from_fd(sock); - local_ip = purple_network_get_my_ip_ext2(sock); - /* cheat a little here - the intent of the "const" attribute is to make it clear that the string doesn't need to be freed */ - next_ip = strtok((char *)local_ip, token); + local_ips = bonjour_jabber_get_local_ips(sock); port = g_strdup_printf("%hu", xfer->local_port); - while(next_ip != NULL) { + while(local_ips) { streamhost = xmlnode_new_child(query, "streamhost"); xmlnode_set_attrib(streamhost, "jid", xf->sid); - xmlnode_set_attrib(streamhost, "host", next_ip); + xmlnode_set_attrib(streamhost, "host", local_ips->data); xmlnode_set_attrib(streamhost, "port", port); - next_ip = strtok(NULL, token); + g_free(local_ips->data); + local_ips = g_slist_delete_link(local_ips, local_ips); } g_free(port); @@ -796,15 +794,17 @@ XepXfer *xf; if(xfer == NULL) return; + purple_debug_info("bonjour", "Bonjour-bytestreams-init.\n"); xf = xfer->data; + purple_network_listen_map_external(FALSE); xf->listen_data = purple_network_listen_range(0, 0, SOCK_STREAM, bonjour_bytestreams_listen, xfer); purple_network_listen_map_external(TRUE); - if (xf->listen_data == NULL) { + if (xf->listen_data == NULL) purple_xfer_cancel_local(xfer); - } + return; } diff -r 221cebbc35d8 -r 6d3a90b49dba libpurple/protocols/bonjour/jabber.c --- a/libpurple/protocols/bonjour/jabber.c Thu Feb 18 22:28:41 2010 +0000 +++ b/libpurple/protocols/bonjour/jabber.c Sun Feb 28 04:07:39 2010 +0000 @@ -44,6 +44,11 @@ #endif #include +#ifdef HAVE_GETIFADDRS +#include +#endif + + #include "network.h" #include "eventloop.h" #include "connection.h" @@ -623,15 +628,22 @@ } +#ifndef INET6_ADDRSTRLEN +#define INET6_ADDRSTRLEN 46 +#endif + static void _server_socket_handler(gpointer data, int server_socket, PurpleInputCondition condition) { BonjourJabber *jdata = data; - struct sockaddr_in their_addr; /* connector's address information */ - socklen_t sin_size = sizeof(struct sockaddr); + struct sockaddr_storage their_addr; /* connector's address information */ + socklen_t sin_size = sizeof(struct sockaddr_storage); int client_socket; int flags; - char *address_text = NULL; +#ifdef HAVE_INET_NTOP + char addrstr[INET6_ADDRSTRLEN]; +#endif + const char *address_text; struct _match_buddies_by_address_t *mbba; BonjourJabberConversation *bconv; GSList *buddies; @@ -640,7 +652,9 @@ if (condition != PURPLE_INPUT_READ) return; - if ((client_socket = accept(server_socket, (struct sockaddr *)&their_addr, &sin_size)) == -1) + memset(&their_addr, 0, sin_size); + + if ((client_socket = accept(server_socket, (struct sockaddr*)&their_addr, &sin_size)) == -1) return; flags = fcntl(client_socket, F_GETFL); @@ -650,7 +664,16 @@ #endif /* Look for the buddy that has opened the conversation and fill information */ - address_text = inet_ntoa(their_addr.sin_addr); +#ifdef HAVE_INET_NTOP + if (their_addr.ss_family == AF_INET6) + address_text = inet_ntop(their_addr.ss_family, &((struct sockaddr_in6 *)&their_addr)->sin6_addr, + addrstr, sizeof(addrstr)); + else + address_text = inet_ntop(their_addr.ss_family, &((struct sockaddr_in *)&their_addr)->sin_addr, + addrstr, sizeof(addrstr)); +#else + address_text = inet_ntoa(((struct sockaddr_in *)&their_addr)->sin_addr); +#endif purple_debug_info("bonjour", "Received incoming connection from %s.\n", address_text); mbba = g_new0(struct _match_buddies_by_address_t, 1); mbba->address = address_text; @@ -680,52 +703,42 @@ } -gint -bonjour_jabber_start(BonjourJabber *jdata) +static int +start_serversocket_listening(int port, int socket, struct sockaddr *addr, size_t addr_size, gboolean ip6, gboolean allow_port_fallback) { - struct sockaddr_in my_addr; + int ret_port = port; - /* Open a listening socket for incoming conversations */ - jdata->socket = socket(PF_INET, SOCK_STREAM, 0); - if (jdata->socket < 0) { - gchar *buf = g_strdup_printf(_("Unable to create socket: %s"), - g_strerror(errno)); - purple_connection_error_reason(jdata->account->gc, - PURPLE_CONNECTION_ERROR_NETWORK_ERROR, buf); - g_free(buf); - return -1; - } - - memset(&my_addr, 0, sizeof(struct sockaddr_in)); - my_addr.sin_family = AF_INET; + purple_debug_info("bonjour", "Attempting to bind IPv%d socket to port %d.\n", ip6 ? 6 : 4, port); /* Try to use the specified port - if it isn't available, use a random port */ - my_addr.sin_port = htons(jdata->port); - if (bind(jdata->socket, (struct sockaddr*)&my_addr, sizeof(struct sockaddr)) != 0) - { + if (bind(socket, addr, addr_size) != 0) { + purple_debug_info("bonjour", "Unable to bind to specified " - "port %i: %s\n", jdata->port, g_strerror(errno)); - my_addr.sin_port = 0; - if (bind(jdata->socket, (struct sockaddr*)&my_addr, sizeof(struct sockaddr)) != 0) - { - gchar *buf = g_strdup_printf(_("Unable to bind socket " - "to port: %s"), g_strerror(errno)); - purple_connection_error_reason(jdata->account->gc, - PURPLE_CONNECTION_ERROR_NETWORK_ERROR, buf); - g_free(buf); + "port %i: %s\n", port, g_strerror(errno)); + + if (!allow_port_fallback) { + purple_debug_warning("bonjour", "Not attempting random port assignment.\n"); return -1; } - jdata->port = purple_network_get_port_from_fd(jdata->socket); +#ifdef PF_INET6 + if (ip6) + ((struct sockaddr_in6 *) addr)->sin6_port = 0; + else +#endif + ((struct sockaddr_in *) addr)->sin_port = 0; + + if (bind(socket, addr, addr_size) != 0) { + purple_debug_error("bonjour", "Unable to bind IPv%d socket to port: %s\n", ip6 ? 6 : 4, g_strerror(errno)); + return -1; + } + ret_port = purple_network_get_port_from_fd(socket); } + purple_debug_info("bonjour", "Bound IPv%d socket to port %d.\n", ip6 ? 6 : 4, ret_port); + /* Attempt to listen on the bound socket */ - if (listen(jdata->socket, 10) != 0) - { - gchar *buf = g_strdup_printf(_("Unable to listen on socket: %s"), - g_strerror(errno)); - purple_connection_error_reason(jdata->account->gc, - PURPLE_CONNECTION_ERROR_NETWORK_ERROR, buf); - g_free(buf); + if (listen(socket, 10) != 0) { + purple_debug_error("bonjour", "Unable to listen on IPv%d socket: %s\n", ip6 ? 6 : 4, g_strerror(errno)); return -1; } @@ -739,8 +752,66 @@ } #endif - /* Open a watcher in the socket we have just opened */ - jdata->watcher_id = purple_input_add(jdata->socket, PURPLE_INPUT_READ, _server_socket_handler, jdata); + return ret_port; +} + +gint +bonjour_jabber_start(BonjourJabber *jdata) +{ + int ipv6_port = -1, ipv4_port = -1; + + /* Open a listening socket for incoming conversations */ +#ifdef PF_INET6 + jdata->socket6 = socket(PF_INET6, SOCK_STREAM, 0); +#endif + jdata->socket = socket(PF_INET, SOCK_STREAM, 0); + if (jdata->socket == -1 && jdata->socket6 == -1) { + purple_debug_error("bonjour", "Unable to create socket: %s", + g_strerror(errno)); + return -1; + } + +#ifdef PF_INET6 + if (jdata->socket6 != -1) { + struct sockaddr_in6 addr6; + memset(&addr6, 0, sizeof(addr6)); + addr6.sin6_family = AF_INET6; + addr6.sin6_port = htons(jdata->port); + addr6.sin6_addr = in6addr_any; + ipv6_port = start_serversocket_listening(jdata->port, jdata->socket6, (struct sockaddr *) &addr6, sizeof(addr6), TRUE, TRUE); + /* Open a watcher in the socket we have just opened */ + if (ipv6_port > 0) { + jdata->watcher_id6 = purple_input_add(jdata->socket6, PURPLE_INPUT_READ, _server_socket_handler, jdata); + jdata->port = ipv6_port; + } else { + purple_debug_error("bonjour", "Failed to start listening on IPv6 socket.\n"); + close(jdata->socket6); + jdata->socket6 = -1; + } + } +#endif + if (jdata->socket != -1) { + struct sockaddr_in addr4; + memset(&addr4, 0, sizeof(addr4)); + addr4.sin_family = AF_INET; + addr4.sin_port = htons(jdata->port); + ipv4_port = start_serversocket_listening(jdata->port, jdata->socket, (struct sockaddr *) &addr4, sizeof(addr4), FALSE, ipv6_port != -1); + /* Open a watcher in the socket we have just opened */ + if (ipv4_port > 0) { + jdata->watcher_id = purple_input_add(jdata->socket, PURPLE_INPUT_READ, _server_socket_handler, jdata); + jdata->port = ipv4_port; + } else { + purple_debug_error("bonjour", "Failed to start listening on IPv4 socket.\n"); + close(jdata->socket); + jdata->socket = -1; + } + } + + if (!(ipv6_port > 0 || ipv4_port > 0)) { + purple_debug_error("bonjour", "Unable to listen on socket: %s", + g_strerror(errno)); + return -1; + } return jdata->port; } @@ -1101,6 +1172,10 @@ close(jdata->socket); if (jdata->watcher_id > 0) purple_input_remove(jdata->watcher_id); + if (jdata->socket6 >= 0) + close(jdata->socket6); + if (jdata->watcher_id6 > 0) + purple_input_remove(jdata->watcher_id6); /* Close all the conversation sockets and remove all the watchers after sending end streams */ if (jdata->account->gc != NULL) { @@ -1234,58 +1309,97 @@ return (ret >= 0) ? 0 : -1; } -/* This returns a ';' delimited string containing all non-localhost IPs */ -const char * -purple_network_get_my_ip_ext2(int fd) +/* This returns a list containing all non-localhost IPs */ +GSList * +bonjour_jabber_get_local_ips(int fd) { - char buffer[1024]; - static char ip_ext[17 * 10]; + GSList *ips = NULL; + const char *address_text; + int ret; + +#ifdef HAVE_GETIFADDRS /* This is required for IPv6 */ + { + struct ifaddrs *ifap, *ifa; + struct sockaddr *addr; + char addrstr[INET6_ADDRSTRLEN]; + + ret = getifaddrs(&ifap); + if (ret != 0) { + const char *error = g_strerror(errno); + purple_debug_error("bonjour", "getifaddrs() error: %s\n", error ? error : "(null)"); + return NULL; + } + + for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) { + if (!(ifa->ifa_flags & IFF_RUNNING) || (ifa->ifa_flags & IFF_LOOPBACK) || ifa->ifa_addr == NULL) + continue; + + addr = ifa->ifa_addr; + address_text = NULL; + switch (addr->sa_family) { + case AF_INET: + address_text = inet_ntop(addr->sa_family, &((struct sockaddr_in *)addr)->sin_addr, + addrstr, sizeof(addrstr)); + break; +#ifdef PF_INET6 + case AF_INET6: + address_text = inet_ntop(addr->sa_family, &((struct sockaddr_in6 *)addr)->sin6_addr, + addrstr, sizeof(addrstr)); + break; +#endif + } + + if (address_text != NULL) { + if (addr->sa_family == AF_INET) + ips = g_slist_append(ips, g_strdup(address_text)); + else + ips = g_slist_prepend(ips, g_strdup(address_text)); + } + } + + freeifaddrs(ifap); + + } +#else + { char *tmp; - char *tip; struct ifconf ifc; struct ifreq *ifr; + char buffer[1024]; struct sockaddr_in *sinptr; - guint32 lhost = htonl(127 * 256 * 256 * 256 + 1); - long unsigned int add; int source = fd; - int len, count = 0; if (fd < 0) source = socket(PF_INET, SOCK_STREAM, 0); ifc.ifc_len = sizeof(buffer); ifc.ifc_req = (struct ifreq *)buffer; - ioctl(source, SIOCGIFCONF, &ifc); + ret = ioctl(source, SIOCGIFCONF, &ifc); if (fd < 0) close(source); - memset(ip_ext, 0, sizeof(ip_ext)); - memcpy(ip_ext, "0.0.0.0", 7); + if (ret < 0) { + const char *error = g_strerror(errno); + purple_debug_error("bonjour", "ioctl(SIOCGIFCONF) error: %s\n", error ? error : "(null)"); + return NULL; + } + tmp = buffer; - tip = ip_ext; - while (tmp < buffer + ifc.ifc_len && count < 10) - { + while (tmp < buffer + ifc.ifc_len) { ifr = (struct ifreq *)tmp; tmp += HX_SIZE_OF_IFREQ(*ifr); - if (ifr->ifr_addr.sa_family == AF_INET) - { + if (ifr->ifr_addr.sa_family == AF_INET) { sinptr = (struct sockaddr_in *)&ifr->ifr_addr; - if (sinptr->sin_addr.s_addr != lhost) - { - add = ntohl(sinptr->sin_addr.s_addr); - len = g_snprintf(tip, 17, "%lu.%lu.%lu.%lu;", - ((add >> 24) & 255), - ((add >> 16) & 255), - ((add >> 8) & 255), - add & 255); - tip = &tip[len]; - count++; - continue; + if ((ntohl(sinptr->sin_addr.s_addr) >> 24) != 127) { + address_text = inet_ntoa(sinptr->sin_addr); + ips = g_slist_prepend(ips, g_strdup(address_text)); } - } + } } + } +#endif - return ip_ext; + return ips; } diff -r 221cebbc35d8 -r 6d3a90b49dba libpurple/protocols/bonjour/jabber.h --- a/libpurple/protocols/bonjour/jabber.h Thu Feb 18 22:28:41 2010 +0000 +++ b/libpurple/protocols/bonjour/jabber.h Sun Feb 28 04:07:39 2010 +0000 @@ -37,7 +37,9 @@ { gint port; gint socket; + gint socket6; gint watcher_id; + gint watcher_id6; PurpleAccount *account; GSList *pending_conversations; } BonjourJabber; @@ -105,6 +107,6 @@ XepIq *xep_iq_new(void *data, XepIqType type, const char *to, const char *from, const char *id); int xep_iq_send_and_free(XepIq *iq); -const char *purple_network_get_my_ip_ext2(int fd); +GSList * bonjour_jabber_get_local_ips(int fd); #endif /* _BONJOUR_JABBER_H_ */ diff -r 221cebbc35d8 -r 6d3a90b49dba libpurple/protocols/bonjour/mdns_avahi.c --- a/libpurple/protocols/bonjour/mdns_avahi.c Thu Feb 18 22:28:41 2010 +0000 +++ b/libpurple/protocols/bonjour/mdns_avahi.c Sun Feb 28 04:07:39 2010 +0000 @@ -189,8 +189,12 @@ bb->ips = g_slist_remove(bb->ips, rd->ip); g_free((gchar *) rd->ip); } - bb->ips = g_slist_prepend(bb->ips, g_strdup(ip)); - rd->ip = bb->ips->data; + rd->ip = g_strdup(ip); + /* IPv6 goes at the front of the list and IPv4 at the end so that we "prefer" IPv6, if present */ + if (protocol == AVAHI_PROTO_INET6) + bb->ips = g_slist_prepend(bb->ips, (gchar *) rd->ip); + else + bb->ips = g_slist_append(bb->ips, (gchar *) rd->ip); } bb->port_p2pj = port; @@ -249,7 +253,7 @@ /* Make sure it isn't us */ if (purple_utf8_strcasecmp(name, account->username) != 0) { if (!avahi_service_resolver_new(avahi_service_browser_get_client(b), - interface, protocol, name, type, domain, AVAHI_PROTO_INET, + interface, protocol, name, type, domain, protocol, 0, _resolver_callback, account)) { purple_debug_warning("bonjour", "_browser_callback -- Error initiating resolver: %s\n", avahi_strerror(avahi_client_errno(avahi_service_browser_get_client(b)))); @@ -448,14 +452,14 @@ case PUBLISH_START: publish_result = avahi_entry_group_add_service_strlst( idata->group, AVAHI_IF_UNSPEC, - AVAHI_PROTO_INET, 0, + AVAHI_PROTO_UNSPEC, 0, purple_account_get_username(data->account), LINK_LOCAL_RECORD_NAME, NULL, NULL, data->port_p2pj, lst); break; case PUBLISH_UPDATE: publish_result = avahi_entry_group_update_service_txt_strlst( idata->group, AVAHI_IF_UNSPEC, - AVAHI_PROTO_INET, 0, + AVAHI_PROTO_UNSPEC, 0, purple_account_get_username(data->account), LINK_LOCAL_RECORD_NAME, NULL, lst); break; @@ -487,7 +491,7 @@ g_return_val_if_fail(idata != NULL, FALSE); - idata->sb = avahi_service_browser_new(idata->client, AVAHI_IF_UNSPEC, AVAHI_PROTO_INET, LINK_LOCAL_RECORD_NAME, NULL, 0, _browser_callback, data->account); + idata->sb = avahi_service_browser_new(idata->client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, LINK_LOCAL_RECORD_NAME, NULL, 0, _browser_callback, data->account); if (!idata->sb) { purple_debug_error("bonjour", @@ -533,7 +537,7 @@ purple_account_get_username(data->account)); ret = avahi_entry_group_add_record(idata->buddy_icon_group, AVAHI_IF_UNSPEC, - AVAHI_PROTO_INET, flags, svc_name, + AVAHI_PROTO_UNSPEC, flags, svc_name, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_NULL, 120, avatar_data, avatar_len); g_free(svc_name); @@ -622,7 +626,7 @@ name = g_strdup_printf("%s." LINK_LOCAL_RECORD_NAME "local", buddy->name); idata->buddy_icon_rec_browser = avahi_record_browser_new(session_idata->client, AVAHI_IF_UNSPEC, - AVAHI_PROTO_INET, name, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_NULL, 0, + AVAHI_PROTO_UNSPEC, name, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_NULL, 0, _buddy_icon_record_cb, buddy); g_free(name); diff -r 221cebbc35d8 -r 6d3a90b49dba libpurple/protocols/gg/gg.c --- a/libpurple/protocols/gg/gg.c Thu Feb 18 22:28:41 2010 +0000 +++ b/libpurple/protocols/gg/gg.c Sun Feb 28 04:07:39 2010 +0000 @@ -2465,7 +2465,8 @@ sizeof(PurplePluginProtocolInfo), /* struct_size */ NULL, /* get_account_text_table */ NULL, /* initiate_media */ - NULL /* can_do_media */ + NULL, /* can_do_media */ + NULL /* get_moods */ }; static PurplePluginInfo info = { diff -r 221cebbc35d8 -r 6d3a90b49dba libpurple/protocols/irc/irc.c --- a/libpurple/protocols/irc/irc.c Thu Feb 18 22:28:41 2010 +0000 +++ b/libpurple/protocols/irc/irc.c Sun Feb 28 04:07:39 2010 +0000 @@ -944,7 +944,8 @@ sizeof(PurplePluginProtocolInfo), /* struct_size */ NULL, /* get_account_text_table */ NULL, /* initiate_media */ - NULL /* can_do_media */ + NULL, /* get_media_caps */ + NULL /* get_moods */ }; static gboolean load_plugin (PurplePlugin *plugin) { diff -r 221cebbc35d8 -r 6d3a90b49dba libpurple/protocols/jabber/Makefile.mingw --- a/libpurple/protocols/jabber/Makefile.mingw Thu Feb 18 22:28:41 2010 +0000 +++ b/libpurple/protocols/jabber/Makefile.mingw Sun Feb 28 04:07:39 2010 +0000 @@ -29,7 +29,7 @@ -I$(GTK_TOP)/include \ -I$(GTK_TOP)/include/glib-2.0 \ -I$(GTK_TOP)/lib/glib-2.0/include \ - -I$(LIBXML2_TOP)/include \ + -I$(LIBXML2_TOP)/include/libxml2 \ -I$(PURPLE_TOP) \ -I$(PURPLE_TOP)/win32 \ -I$(PIDGIN_TREE_TOP) diff -r 221cebbc35d8 -r 6d3a90b49dba libpurple/protocols/jabber/jabber.c --- a/libpurple/protocols/jabber/jabber.c Thu Feb 18 22:28:41 2010 +0000 +++ b/libpurple/protocols/jabber/jabber.c Sun Feb 28 04:07:39 2010 +0000 @@ -62,6 +62,7 @@ #include "roster.h" #include "ping.h" #include "si.h" +#include "usermood.h" #include "xdata.h" #include "pep.h" #include "adhoccommands.h" @@ -69,6 +70,8 @@ #include "jingle/jingle.h" #include "jingle/rtp.h" +#define PING_TIMEOUT 60 + GList *jabber_features = NULL; GList *jabber_identities = NULL; static GSList *jabber_cmds = NULL; @@ -520,9 +523,12 @@ void jabber_keepalive(PurpleConnection *gc) { - JabberStream *js = gc->proto_data; - - if (js->keepalive_timeout == 0) { + JabberStream *js = purple_connection_get_protocol_data(gc); + time_t now = time(NULL); + + if (js->keepalive_timeout == 0 && (now - js->last_ping) >= PING_TIMEOUT) { + js->last_ping = now; + jabber_keepalive_ping(js); js->keepalive_timeout = purple_timeout_add_seconds(120, (GSourceFunc)(jabber_keepalive_timeout), gc); @@ -2062,18 +2068,31 @@ if (full) { PurpleStatus *status; - status = purple_presence_get_active_status(presence); - mood = purple_status_get_attr_string(status, "mood"); - if(mood != NULL) { + status = purple_presence_get_status(presence, "mood"); + mood = purple_status_get_attr_string(status, PURPLE_MOOD_NAME); + if(mood && *mood) { const char *moodtext; - moodtext = purple_status_get_attr_string(status, "moodtext"); - if(moodtext != NULL) { - char *moodplustext = g_strdup_printf("%s (%s)", mood, moodtext); + /* find the mood */ + PurpleMood *moods = jabber_get_moods(account); + const char *description = NULL; + + for (; moods->mood ; moods++) { + if (purple_strequal(moods->mood, mood)) { + description = moods->description; + break; + } + } + + moodtext = purple_status_get_attr_string(status, PURPLE_MOOD_COMMENT); + if(moodtext && *moodtext) { + char *moodplustext = + g_strdup_printf("%s (%s)", description ? _(description) : mood, moodtext); purple_notify_user_info_add_pair(user_info, _("Mood"), moodplustext); g_free(moodplustext); } else - purple_notify_user_info_add_pair(user_info, _("Mood"), mood); + purple_notify_user_info_add_pair(user_info, _("Mood"), + description ? _(description) : mood); } if (purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_TUNE)) { PurpleStatus *tune = purple_presence_get_status(presence, "tune"); @@ -2134,7 +2153,15 @@ "nick", _("Nickname"), purple_value_new(PURPLE_TYPE_STRING), "buzz", _("Allow Buzz"), buzz_enabled, NULL); - types = g_list_append(types, type); + types = g_list_prepend(types, type); + + + type = purple_status_type_new_with_attrs(PURPLE_STATUS_MOOD, + "mood", NULL, TRUE, TRUE, TRUE, + PURPLE_MOOD_NAME, _("Mood Name"), purple_value_new(PURPLE_TYPE_STRING), + PURPLE_MOOD_COMMENT, _("Mood Comment"), purple_value_new(PURPLE_TYPE_STRING), + NULL); + types = g_list_prepend(types, type); priority_value = purple_value_new(PURPLE_TYPE_INT); purple_value_set_int(priority_value, 1); @@ -2150,7 +2177,7 @@ "nick", _("Nickname"), purple_value_new(PURPLE_TYPE_STRING), "buzz", _("Allow Buzz"), buzz_enabled, NULL); - types = g_list_append(types, type); + types = g_list_prepend(types, type); priority_value = purple_value_new(PURPLE_TYPE_INT); purple_value_set_int(priority_value, 0); @@ -2166,7 +2193,7 @@ "nick", _("Nickname"), purple_value_new(PURPLE_TYPE_STRING), "buzz", _("Allow Buzz"), buzz_enabled, NULL); - types = g_list_append(types, type); + types = g_list_prepend(types, type); priority_value = purple_value_new(PURPLE_TYPE_INT); purple_value_set_int(priority_value, 0); @@ -2182,7 +2209,7 @@ "nick", _("Nickname"), purple_value_new(PURPLE_TYPE_STRING), "buzz", _("Allow Buzz"), buzz_enabled, NULL); - types = g_list_append(types, type); + types = g_list_prepend(types, type); priority_value = purple_value_new(PURPLE_TYPE_INT); purple_value_set_int(priority_value, 0); @@ -2195,11 +2222,11 @@ "moodtext", _("Mood Text"), purple_value_new(PURPLE_TYPE_STRING), "nick", _("Nickname"), purple_value_new(PURPLE_TYPE_STRING), NULL); - types = g_list_append(types, type); + types = g_list_prepend(types, type); /* if(js->protocol_version == JABBER_PROTO_0_9) - m = g_list_append(m, _("Invisible")); + "Invisible" */ type = purple_status_type_new_with_attrs(PURPLE_STATUS_OFFLINE, @@ -2207,7 +2234,7 @@ NULL, TRUE, TRUE, FALSE, "message", _("Message"), purple_value_new(PURPLE_TYPE_STRING), NULL); - types = g_list_append(types, type); + types = g_list_prepend(types, type); type = purple_status_type_new_with_attrs(PURPLE_STATUS_TUNE, "tune", NULL, FALSE, TRUE, TRUE, @@ -2221,9 +2248,9 @@ PURPLE_TUNE_YEAR, _("Tune Year"), purple_value_new(PURPLE_TYPE_INT), PURPLE_TUNE_URL, _("Tune URL"), purple_value_new(PURPLE_TYPE_STRING), NULL); - types = g_list_append(types, type); - - return types; + types = g_list_prepend(types, type); + + return g_list_reverse(types); } static void diff -r 221cebbc35d8 -r 6d3a90b49dba libpurple/protocols/jabber/jabber.h --- a/libpurple/protocols/jabber/jabber.h Thu Feb 18 22:28:41 2010 +0000 +++ b/libpurple/protocols/jabber/jabber.h Sun Feb 28 04:07:39 2010 +0000 @@ -166,6 +166,11 @@ time_t idle; time_t old_idle; + /** When we last pinged the server, so we don't ping more + * often than once every minute. + */ + time_t last_ping; + JabberID *user; JabberBuddy *user_jb; diff -r 221cebbc35d8 -r 6d3a90b49dba libpurple/protocols/jabber/libxmpp.c --- a/libpurple/protocols/jabber/libxmpp.c Thu Feb 18 22:28:41 2010 +0000 +++ b/libpurple/protocols/jabber/libxmpp.c Sun Feb 28 04:07:39 2010 +0000 @@ -43,6 +43,7 @@ #include "presence.h" #include "google.h" #include "pep.h" +#include "usermood.h" #include "usertune.h" #include "caps.h" #include "data.h" @@ -126,6 +127,7 @@ NULL, /* get_account_text_table */ jabber_initiate_media, /* initiate_media */ jabber_get_media_caps, /* get_media_caps */ + jabber_get_moods /* get_moods */ }; static gboolean load_plugin(PurplePlugin *plugin) diff -r 221cebbc35d8 -r 6d3a90b49dba libpurple/protocols/jabber/presence.c --- a/libpurple/protocols/jabber/presence.c Thu Feb 18 22:28:41 2010 +0000 +++ b/libpurple/protocols/jabber/presence.c Sun Feb 28 04:07:39 2010 +0000 @@ -40,6 +40,7 @@ #include "jutil.h" #include "adhoccommands.h" +#include "usermood.h" #include "usertune.h" @@ -131,6 +132,15 @@ gc = purple_account_get_connection(account); js = purple_connection_get_protocol_data(gc); + + /* it's a mood update */ + if (purple_status_type_get_primitive(purple_status_get_type(status)) == PURPLE_STATUS_MOOD) { + const char *mood = + purple_status_get_attr_string(status, PURPLE_MOOD_NAME); + jabber_mood_set(js, mood, NULL); + return; + } + jabber_presence_send(js, FALSE); } diff -r 221cebbc35d8 -r 6d3a90b49dba libpurple/protocols/jabber/usermood.c --- a/libpurple/protocols/jabber/usermood.c Thu Feb 18 22:28:41 2010 +0000 +++ b/libpurple/protocols/jabber/usermood.c Sun Feb 28 04:07:39 2010 +0000 @@ -30,100 +30,106 @@ #include "request.h" #include "debug.h" -static const char * const moodstrings[] = { - "afraid", - "amazed", - "amorous", - "angry", - "annoyed", - "anxious", - "aroused", - "ashamed", - "bored", - "brave", - "calm", - "cautious", - "cold", - "confident", - "confused", - "contemplative", - "contented", - "cranky", - "crazy", - "creative", - "curious", - "dejected", - "depressed", - "disappointed", - "disgusted", - "dismayed", - "distracted", - "embarrassed", - "envious", - "excited", - "flirtatious", - "frustrated", - "grumpy", - "guilty", - "happy", - "hopeful", - "hot", - "humbled", - "humiliated", - "hungry", - "hurt", - "impressed", - "in_awe", - "in_love", - "indignant", - "interested", - "intoxicated", - "invincible", - "jealous", - "lonely", - "lucky", - "mean", - "moody", - "nervous", - "neutral", - "offended", - "outraged", - "playful", - "proud", - "relaxed", - "relieved", - "remorseful", - "restless", - "sad", - "sarcastic", - "serious", - "shocked", - "shy", - "sick", - "sleepy", - "spontaneous", - "stressed", - "strong", - "surprised", - "thankful", - "thirsty", - "tired", - "weak", - "worried" +static PurpleMood moods[] = { + {"afraid", N_("Afraid"), NULL}, + {"amazed", N_("Amazed"), NULL}, + {"amorous", N_("Amorous"), NULL}, + {"angry", N_("Angry"), NULL}, + {"annoyed", N_("Annoyed"), NULL}, + {"anxious", N_("Anxious"), NULL}, + {"aroused", N_("Aroused"), NULL}, + {"ashamed", N_("Ashamed"), NULL}, + {"bored", N_("Bored"), NULL}, + {"brave", N_("Brave"), NULL}, + {"calm", N_("Calm"), NULL}, + {"cautious", N_("Cautious"), NULL}, + {"cold", N_("Cold"), NULL}, + {"confident", N_("Confident"), NULL}, + {"confused", N_("Confused"), NULL}, + {"contemplative", N_("Contemplative"), NULL}, + {"contented", N_("Contented"), NULL}, + {"cranky", N_("Cranky"), NULL}, + {"crazy", N_("Crazy"), NULL}, + {"creative", N_("Creative"), NULL}, + {"curious", N_("Curious"), NULL}, + {"dejected", N_("Dejected"), NULL}, + {"depressed", N_("Depressed"), NULL}, + {"disappointed", N_("Disappointed"), NULL}, + {"disgusted", N_("Disgusted"), NULL}, + {"dismayed", N_("Dismayed"), NULL}, + {"distracted", N_("Distracted"), NULL}, + {"embarrassed", N_("Embarrassed"), NULL}, + {"envious", N_("Envious"), NULL}, + {"excited", N_("Excited"), NULL}, + {"flirtatious", N_("Flirtatious"), NULL}, + {"frustrated", N_("Frustrated"), NULL}, + {"grateful", N_("Grateful"), NULL}, + {"grieving", N_("Grieving"), NULL}, + {"grumpy", N_("Grumpy"), NULL}, + {"guilty", N_("Guilty"), NULL}, + {"happy", N_("Happy"), NULL}, + {"hopeful", N_("Hopeful"), NULL}, + {"hot", N_("Hot"), NULL}, + {"humbled", N_("Humbled"), NULL}, + {"humiliated", N_("Humiliated"), NULL}, + {"hungry", N_("Hungry"), NULL}, + {"hurt", N_("Hurt"), NULL}, + {"impressed", N_("Impressed"), NULL}, + {"in_awe", N_("In awe"), NULL}, + {"in_love", N_("In love"), NULL}, + {"indignant", N_("Indignant"), NULL}, + {"interested", N_("Interested"), NULL}, + {"intoxicated", N_("Intoxicated"), NULL}, + {"invincible", N_("Invincible"), NULL}, + {"jealous", N_("Jealous"), NULL}, + {"lonely", N_("Lonely"), NULL}, + {"lost", N_("Lost"), NULL}, + {"lucky", N_("Lucky"), NULL}, + {"mean", N_("Mean"), NULL}, + {"moody", N_("Moody"), NULL}, + {"nervous", N_("Nervous"), NULL}, + {"neutral", N_("Neutral"), NULL}, + {"offended", N_("Offended"), NULL}, + {"outraged", N_("Outraged"), NULL}, + {"playful", N_("Playful"), NULL}, + {"proud", N_("Proud"), NULL}, + {"relaxed", N_("Relaxed"), NULL}, + {"relieved", N_("Relieved"), NULL}, + {"remorseful", N_("Remorseful"), NULL}, + {"restless", N_("Restless"), NULL}, + {"sad", N_("Sad"), NULL}, + {"sarcastic", N_("Sarcastic"), NULL}, + {"satisfied", N_("Satisfied"), NULL}, + {"serious", N_("Serious"), NULL}, + {"shocked", N_("Shocked"), NULL}, + {"shy", N_("Shy"), NULL}, + {"sick", N_("Sick"), NULL}, + {"sleepy", N_("Sleepy"), NULL}, + {"spontaneous", N_("Spontaneous"), NULL}, + {"stressed", N_("Stressed"), NULL}, + {"strong", N_("Strong"), NULL}, + {"surprised", N_("Surprised"), NULL}, + {"thankful", N_("Thankful"), NULL}, + {"thirsty", N_("Thirsty"), NULL}, + {"tired", N_("Tired"), NULL}, + {"undefined", N_("Undefined"), NULL}, + {"weak", N_("Weak"), NULL}, + {"worried", N_("Worried"), NULL}, + /* Mark the last record. */ + {NULL, NULL, NULL} }; -static void -jabber_mood_cb(JabberStream *js, const char *from, xmlnode *items) -{ - xmlnode *item; - JabberBuddy *buddy = jabber_buddy_find(js, from, FALSE); +static PurpleMood empty_moods[] = { + {NULL, NULL, NULL} +}; + +static void jabber_mood_cb(JabberStream *js, const char *from, xmlnode *items) { + /* it doesn't make sense to have more than one item here, so let's just pick the first one */ + xmlnode *item = xmlnode_get_child(items, "item"); const char *newmood = NULL; char *moodtext = NULL; - xmlnode *child, *mood; - - /* it doesn't make sense to have more than one item here, so let's just pick the first one */ - item = xmlnode_get_child(items, "item"); - + JabberBuddy *buddy = jabber_buddy_find(js, from, FALSE); + xmlnode *moodinfo, *mood; /* ignore the mood of people not on our buddy list */ if (!buddy || !item) return; @@ -131,39 +137,34 @@ mood = xmlnode_get_child_with_namespace(item, "mood", "http://jabber.org/protocol/mood"); if (!mood) return; - for (child = mood->child; child; child = child->next) { - if (child->type != XMLNODE_TYPE_TAG) - continue; - - if (g_str_equal("text", child->name) && moodtext == NULL) - moodtext = xmlnode_get_data(child); - else { - int i; - for (i = 0; i < G_N_ELEMENTS(moodstrings); ++i) { - /* verify that the mood is known (valid) */ - if (g_str_equal(child->name, moodstrings[i])) { - newmood = moodstrings[i]; - break; + for (moodinfo = mood->child; moodinfo; moodinfo = moodinfo->next) { + if (moodinfo->type == XMLNODE_TYPE_TAG) { + if (!strcmp(moodinfo->name, "text")) { + if (!moodtext) /* only pick the first one */ + moodtext = xmlnode_get_data(moodinfo); + } else { + int i; + for (i = 0; moods[i].mood; ++i) { + /* verify that the mood is known (valid) */ + if (!strcmp(moodinfo->name, moods[i].mood)) { + newmood = moods[i].mood; + break; + } } } + if (newmood != NULL && moodtext != NULL) + break; } if (newmood != NULL && moodtext != NULL) break; } if (newmood != NULL) { - PurpleAccount *account; - const char *status_id; - JabberBuddyResource *resource = jabber_buddy_find_resource(buddy, NULL); - if (!resource) { /* huh? */ - g_free(moodtext); - return; - } - status_id = jabber_buddy_state_get_status_id(resource->state); - - account = purple_connection_get_account(js->gc); - purple_prpl_got_user_status(account, from, status_id, "mood", - _(newmood), "moodtext", - moodtext ? moodtext : "", NULL); + purple_prpl_got_user_status(js->gc->account, from, "mood", + PURPLE_MOOD_NAME, newmood, + PURPLE_MOOD_COMMENT, moodtext, + NULL); + } else { + purple_prpl_got_user_status_deactive(js->gc->account, from, "mood"); } g_free(moodtext); } @@ -175,6 +176,7 @@ static void do_mood_set_from_fields(PurpleConnection *gc, PurpleRequestFields *fields) { JabberStream *js; + const int max_mood_idx = sizeof(moods) / sizeof(moods[0]) - 1; int selected_mood = purple_request_fields_get_choice(fields, "mood"); if (!PURPLE_CONNECTION_IS_VALID(gc)) { @@ -184,12 +186,12 @@ js = gc->proto_data; - if (selected_mood < 0 || selected_mood >= G_N_ELEMENTS(moodstrings)) { + if (selected_mood < 0 || selected_mood >= max_mood_idx) { purple_debug_error("jabber", "Invalid mood index (%d) selected.\n", selected_mood); return; } - jabber_mood_set(js, moodstrings[selected_mood], purple_request_fields_get_string(fields, "text")); + jabber_mood_set(js, moods[selected_mood].mood, purple_request_fields_get_string(fields, "text")); } static void do_mood_set_mood(PurplePluginAction *action) { @@ -207,8 +209,8 @@ field = purple_request_field_choice_new("mood", _("Mood"), 0); - for(i = 0; i < G_N_ELEMENTS(moodstrings); ++i) - purple_request_field_choice_add(field, _(moodstrings[i])); + for(i = 0; moods[i].mood; ++i) + purple_request_field_choice_add(field, _(moods[i].description)); purple_request_field_set_required(field, TRUE); purple_request_field_group_add_field(group, field); @@ -237,13 +239,14 @@ void jabber_mood_set(JabberStream *js, const char *mood, const char *text) { xmlnode *publish, *moodnode; - g_return_if_fail(mood != NULL); - publish = xmlnode_new("publish"); xmlnode_set_attrib(publish,"node","http://jabber.org/protocol/mood"); moodnode = xmlnode_new_child(xmlnode_new_child(publish, "item"), "mood"); xmlnode_set_namespace(moodnode, "http://jabber.org/protocol/mood"); - xmlnode_new_child(moodnode, mood); + if (mood) { + /* if mood is NULL, set an empty mood node, meaning: unset mood */ + xmlnode_new_child(moodnode, mood); + } if (text && text[0] != '\0') { xmlnode *textnode = xmlnode_new_child(moodnode, "text"); @@ -254,3 +257,17 @@ /* publish is freed by jabber_pep_publish -> jabber_iq_send -> jabber_iq_free (yay for well-defined memory management rules) */ } + +PurpleMood *jabber_get_moods(PurpleAccount *account) +{ + PurpleConnection *gc = purple_account_get_connection(account); + JabberStream *js = (JabberStream *) gc->proto_data; + + if (js->pep) { + purple_debug_info("jabber", "get_moods: account supports PEP\n"); + return moods; + } else { + purple_debug_info("jabber", "get_moods: account doesn't support PEP\n"); + return empty_moods; + } +} \ No newline at end of file diff -r 221cebbc35d8 -r 6d3a90b49dba libpurple/protocols/jabber/usermood.h --- a/libpurple/protocols/jabber/usermood.h Thu Feb 18 22:28:41 2010 +0000 +++ b/libpurple/protocols/jabber/usermood.h Sun Feb 28 04:07:39 2010 +0000 @@ -36,4 +36,6 @@ const char *mood, /* must be one of the valid strings defined in the XEP */ const char *text /* might be NULL */); +PurpleMood *jabber_get_moods(PurpleAccount *account); + #endif /* PURPLE_JABBER_USERMOOD_H_ */ diff -r 221cebbc35d8 -r 6d3a90b49dba libpurple/protocols/jabber/xdata.c --- a/libpurple/protocols/jabber/xdata.c Thu Feb 18 22:28:41 2010 +0000 +++ b/libpurple/protocols/jabber/xdata.c Sun Feb 28 04:07:39 2010 +0000 @@ -305,7 +305,7 @@ data->values = g_slist_prepend(data->values, value); - purple_request_field_list_add(field, lbl, value); + purple_request_field_list_add_icon(field, lbl, NULL, value); if(g_list_find_custom(selected, value, (GCompareFunc)strcmp)) purple_request_field_list_add_selected(field, lbl); } diff -r 221cebbc35d8 -r 6d3a90b49dba libpurple/protocols/msn/msn.c --- a/libpurple/protocols/msn/msn.c Thu Feb 18 22:28:41 2010 +0000 +++ b/libpurple/protocols/msn/msn.c Sun Feb 28 04:07:39 2010 +0000 @@ -2732,7 +2732,8 @@ sizeof(PurplePluginProtocolInfo), /* struct_size */ msn_get_account_text_table, /* get_account_text_table */ NULL, /* initiate_media */ - NULL /* can_do_media */ + NULL, /* get_media_caps */ + NULL /* get_moods */ }; static PurplePluginInfo info = diff -r 221cebbc35d8 -r 6d3a90b49dba libpurple/protocols/msn/slp.c --- a/libpurple/protocols/msn/slp.c Thu Feb 18 22:28:41 2010 +0000 +++ b/libpurple/protocols/msn/slp.c Sun Feb 28 04:07:39 2010 +0000 @@ -308,8 +308,6 @@ return NULL; } -#define MAX_FILE_NAME_LEN 0x226 - static void got_sessionreq(MsnSlpCall *slpcall, const char *branch, const char *euf_guid, const char *context) @@ -382,7 +380,7 @@ /* File Transfer */ PurpleAccount *account; PurpleXfer *xfer; - char *bin; + MsnFileContext *header; gsize bin_len; guint32 file_size; char *file_name; @@ -396,16 +394,18 @@ xfer = purple_xfer_new(account, PURPLE_XFER_RECEIVE, slpcall->slplink->remote_user); - if (xfer) - { - bin = (char *)purple_base64_decode(context, &bin_len); - file_size = GUINT32_FROM_LE(*(gsize *)(bin + 8)); - file_name = g_convert(bin + 20, MAX_FILE_NAME_LEN, "UTF-8", "UTF-16LE", + header = (MsnFileContext *)purple_base64_decode(context, &bin_len); + if (bin_len >= sizeof(MsnFileContext) - 1 && + (header->version == 2 || + (header->version == 3 && header->length == sizeof(MsnFileContext) + 63))) { + file_size = GUINT64_FROM_LE(header->file_size); + + file_name = g_convert((const gchar *)&header->file_name, + MAX_FILE_NAME_LEN * 2, + "UTF-8", "UTF-16LE", NULL, NULL, NULL); - g_free(bin); - purple_xfer_set_filename(xfer, file_name ? file_name : ""); g_free(file_name); purple_xfer_set_size(xfer, file_size); @@ -424,6 +424,7 @@ purple_xfer_request(xfer); } + g_free(header); accepted = TRUE; diff -r 221cebbc35d8 -r 6d3a90b49dba libpurple/protocols/msn/slp.h --- a/libpurple/protocols/msn/slp.h Thu Feb 18 22:28:41 2010 +0000 +++ b/libpurple/protocols/msn/slp.h Sun Feb 28 04:07:39 2010 +0000 @@ -30,6 +30,25 @@ #include "session.h" #include "slpcall.h" +#define MAX_FILE_NAME_LEN 260 /* MAX_PATH in Windows */ + +/** + * The context data for a file transfer request + */ +#pragma pack(push,1) /* Couldn't they have made it the right size? */ +typedef struct +{ + guint32 length; /*< Length of header */ + guint32 version; /*< MSN version */ + guint64 file_size; /*< Size of file */ + guint32 type; /*< Transfer type */ + gunichar2 file_name[MAX_FILE_NAME_LEN]; /*< Self-explanatory */ + gchar unknown1[30]; /*< Used somehow for background sharing */ + guint32 unknown2; /*< Possibly for background sharing as well */ + gchar preview[1]; /*< File preview data, 96x96 PNG */ +} MsnFileContext; +#pragma pack(pop) + MsnSlpCall * msn_slp_sip_recv(MsnSlpLink *slplink, const char *body); diff -r 221cebbc35d8 -r 6d3a90b49dba libpurple/protocols/msn/slplink.c --- a/libpurple/protocols/msn/slplink.c Thu Feb 18 22:28:41 2010 +0000 +++ b/libpurple/protocols/msn/slplink.c Sun Feb 28 04:07:39 2010 +0000 @@ -658,74 +658,51 @@ } } -typedef struct -{ - guint32 length; - guint32 unk1; - guint32 file_size; - guint32 unk2; - guint32 unk3; -} MsnContextHeader; - -#define MAX_FILE_NAME_LEN 0x226 - static gchar * gen_context(PurpleXfer *xfer, const char *file_name, const char *file_path) { gsize size = 0; - MsnContextHeader header; + MsnFileContext header; gchar *u8 = NULL; - guchar *base; - guchar *n; gchar *ret; gunichar2 *uni = NULL; glong currentChar = 0; - glong uni_len = 0; - gsize len; + glong len = 0; size = purple_xfer_get_size(xfer); - if(!file_name) { + if (!file_name) { gchar *basename = g_path_get_basename(file_path); u8 = purple_utf8_try_convert(basename); g_free(basename); file_name = u8; } - uni = g_utf8_to_utf16(file_name, -1, NULL, &uni_len, NULL); + uni = g_utf8_to_utf16(file_name, -1, NULL, &len, NULL); - if(u8) { + if (u8) { g_free(u8); file_name = NULL; u8 = NULL; } - len = sizeof(MsnContextHeader) + MAX_FILE_NAME_LEN + 4; - - header.length = GUINT32_TO_LE(len); - header.unk1 = GUINT32_TO_LE(2); - header.file_size = GUINT32_TO_LE(size); - header.unk2 = GUINT32_TO_LE(0); - header.unk3 = GUINT32_TO_LE(0); - - base = g_malloc(len + 1); - n = base; + header.length = GUINT32_TO_LE(sizeof(MsnFileContext) - 1); + header.version = GUINT32_TO_LE(2); /* V.3 contains additional unnecessary data */ + header.file_size = GUINT64_TO_LE(size); + header.type = GUINT32_TO_LE(1); /* No file preview */ - memcpy(n, &header, sizeof(MsnContextHeader)); - n += sizeof(MsnContextHeader); + len = MIN(len, MAX_FILE_NAME_LEN); + for (currentChar = 0; currentChar < len; currentChar++) { + header.file_name[currentChar] = GUINT16_TO_LE(uni[currentChar]); + } + memset(&header.file_name[currentChar], 0x00, (MAX_FILE_NAME_LEN - currentChar) * 2); - memset(n, 0x00, MAX_FILE_NAME_LEN); - for(currentChar = 0; currentChar < uni_len; currentChar++) { - *((gunichar2 *)n + currentChar) = GUINT16_TO_LE(uni[currentChar]); - } - n += MAX_FILE_NAME_LEN; - - memset(n, 0xFF, 4); - n += 4; + memset(&header.unknown1, 0, sizeof(header.unknown1)); + header.unknown2 = GUINT32_TO_LE(0xffffffff); + header.preview[0] = '\0'; g_free(uni); - ret = purple_base64_encode(base, len); - g_free(base); + ret = purple_base64_encode((const guchar *)&header, sizeof(MsnFileContext)); return ret; } diff -r 221cebbc35d8 -r 6d3a90b49dba libpurple/protocols/mxit/mxit.c --- a/libpurple/protocols/mxit/mxit.c Thu Feb 18 22:28:41 2010 +0000 +++ b/libpurple/protocols/mxit/mxit.c Sun Feb 28 04:07:39 2010 +0000 @@ -633,8 +633,9 @@ NULL, /* attention_types */ sizeof( PurplePluginProtocolInfo ), /* struct_size */ mxit_get_text_table, /* get_account_text_table */ - NULL, - NULL + NULL, /* initiate_media */ + NULL, /* get_media_caps */ + NULL /* get_moods */ }; diff -r 221cebbc35d8 -r 6d3a90b49dba libpurple/protocols/myspace/myspace.c --- a/libpurple/protocols/myspace/myspace.c Thu Feb 18 22:28:41 2010 +0000 +++ b/libpurple/protocols/myspace/myspace.c Sun Feb 28 04:07:39 2010 +0000 @@ -3093,7 +3093,8 @@ sizeof(PurplePluginProtocolInfo), /* struct_size */ msim_get_account_text_table, /* get_account_text_table */ NULL, /* initiate_media */ - NULL /* can_do_media */ + NULL, /* get_media_caps */ + NULL /* get_moods */ }; /** diff -r 221cebbc35d8 -r 6d3a90b49dba libpurple/protocols/novell/novell.c --- a/libpurple/protocols/novell/novell.c Thu Feb 18 22:28:41 2010 +0000 +++ b/libpurple/protocols/novell/novell.c Sun Feb 28 04:07:39 2010 +0000 @@ -3529,7 +3529,8 @@ sizeof(PurplePluginProtocolInfo), /* struct_size */ NULL, /* get_account_text_table */ NULL, /* initiate_media */ - NULL /* can_do_media */ + NULL, /* get_media_caps */ + NULL /* get_moods */ }; static PurplePluginInfo info = { diff -r 221cebbc35d8 -r 6d3a90b49dba libpurple/protocols/oscar/clientlogin.c --- a/libpurple/protocols/oscar/clientlogin.c Thu Feb 18 22:28:41 2010 +0000 +++ b/libpurple/protocols/oscar/clientlogin.c Sun Feb 28 04:07:39 2010 +0000 @@ -43,7 +43,7 @@ #include "core.h" #define URL_CLIENT_LOGIN "https://api.screenname.aol.com/auth/clientLogin" -#define URL_START_OSCAR_SESSION "http://api.oscar.aol.com/aim/startOSCARSession" +#define URL_START_OSCAR_SESSION "https://api.oscar.aol.com/aim/startOSCARSession" /* * Using clientLogin requires a developer ID. This key is for libpurple. @@ -177,10 +177,23 @@ code = atoi(tmp); if (code != 200) { + xmlnode *status_detail_node; + guint status_detail = 0; + + status_detail_node = xmlnode_get_child(response_node, + "statusDetailCode"); + if (status_detail_node) { + gchar *data = xmlnode_get_data(status_detail_node); + if (data) { + status_detail = atoi(data); + g_free(data); + } + } + purple_debug_error("oscar", "startOSCARSession response statusCode " "was %s: %s\n", tmp, response); - if (code == 401 || code == 607) + if ((code == 401 && status_detail != 1014) || code == 607) purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR, _("You have been connecting and disconnecting too " @@ -293,7 +306,11 @@ static void send_start_oscar_session(OscarData *od, const char *token, const char *session_key, time_t hosttime) { char *query_string, *signature, *url; - gboolean use_tls = purple_account_get_bool(purple_connection_get_account(od->gc), "use_ssl", OSCAR_DEFAULT_USE_SSL); + PurpleAccount *account; + gboolean use_tls; + + account = purple_connection_get_account(od->gc); + use_tls = purple_account_get_bool(account, "use_ssl", OSCAR_DEFAULT_USE_SSL); /* * Construct the GET parameters. 0x00000611 is the distid given to @@ -317,7 +334,8 @@ g_free(signature); /* Make the request */ - od->url_data = purple_util_fetch_url(url, TRUE, NULL, FALSE, + od->url_data = purple_util_fetch_url_request_len_with_account(account, + url, TRUE, NULL, FALSE, NULL, FALSE, -1, start_oscar_session_cb, od); g_free(url); } @@ -573,8 +591,9 @@ g_string_free(body, TRUE); /* Send the POST request */ - od->url_data = purple_util_fetch_url_request(URL_CLIENT_LOGIN, - TRUE, NULL, FALSE, request->str, FALSE, + od->url_data = purple_util_fetch_url_request_len_with_account( + purple_connection_get_account(gc), URL_CLIENT_LOGIN, + TRUE, NULL, FALSE, request->str, FALSE, -1, client_login_cb, od); g_string_free(request, TRUE); } diff -r 221cebbc35d8 -r 6d3a90b49dba libpurple/protocols/oscar/family_buddy.c --- a/libpurple/protocols/oscar/family_buddy.c Thu Feb 18 22:28:41 2010 +0000 +++ b/libpurple/protocols/oscar/family_buddy.c Sun Feb 28 04:07:39 2010 +0000 @@ -221,6 +221,18 @@ if ((userfunc = aim_callhandler(od, snac->family, snac->subtype))) ret = userfunc(od, conn, frame, &userinfo); + if (snac->subtype == SNAC_SUBTYPE_BUDDY_ONCOMING && + userinfo.capabilities & OSCAR_CAPABILITY_XTRAZ) { + PurpleAccount *account = purple_connection_get_account(od->gc); + PurpleBuddy *buddy = purple_find_buddy(account, userinfo.bn); + + if (buddy) { + PurplePresence *presence = purple_buddy_get_presence(buddy); + + if (purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_MOOD)) + icq_im_xstatus_request(od, userinfo.bn); + } + } aim_info_free(&userinfo); return ret; diff -r 221cebbc35d8 -r 6d3a90b49dba libpurple/protocols/oscar/family_icbm.c --- a/libpurple/protocols/oscar/family_icbm.c Thu Feb 18 22:28:41 2010 +0000 +++ b/libpurple/protocols/oscar/family_icbm.c Sun Feb 28 04:07:39 2010 +0000 @@ -2624,6 +2624,15 @@ char *bn; guchar *cookie; guint8 bnlen; + char *xml = NULL; + int hdrlen; + int curpos; + int num1,num2; + char *desc, *title, *temp; + PurpleAccount *account; + PurpleBuddy *buddy; + PurplePresence *presence; + PurpleStatus *status; cookie = byte_stream_getraw(bs, 8); channel = byte_stream_get16(bs); @@ -2633,14 +2642,54 @@ if (channel == 0x0002) { - if (reason == 0x0003) /* channel-specific */ - /* parse status note text */ - parse_status_note_text(od, cookie, bn, bs); - - byte_stream_get16(bs); /* Unknown */ - byte_stream_get16(bs); /* Unknown */ - if ((userfunc = aim_callhandler(od, snac->family, snac->subtype))) - ret = userfunc(od, conn, frame, channel, bn, reason, cookie); + hdrlen = byte_stream_getle16(bs); + if ( ((hdrlen == 27 ) && (bs->len > (27 + 51)))) { + byte_stream_advance(bs, 51); + num1 = byte_stream_getle16(bs); + num2 = byte_stream_getle16(bs); + purple_debug_misc("oscar", "X-Status: Num1 %i, num2 %i\n",num1, num2); + + if(((num1 == 0x4f00)&&(num2 == 0x3b00))) { + byte_stream_advance(bs, 86); + curpos = byte_stream_curpos(bs); + xml = byte_stream_getstr(bs, bs->len - curpos); + purple_debug_misc("oscar", "X-Status: Received XML reply\n"); + if(xml) { + /* purple_debug_misc("oscar", "X-Status: XML reply: %s\n", (const char*) xml); */ + if ((desc=strstr(xml,"<desc>")) != NULL) { + temp=strstr(xml,"</desc>"); + temp[0]=0; + desc=desc+12; + } + if ((title=strstr(xml,"<title>")) != NULL) { + temp=strstr(xml,"</title>"); + temp[0]=0; + title=title+13; + } else { + title=""; + } + strcpy(xml,title); + if (desc) { + strcat(xml, " - "); + strcat(xml, desc); + } + purple_debug_misc("oscar", "X-Status reply: %s\n", (const char*)xml); + account = purple_connection_get_account(od->gc); + buddy = purple_find_buddy(account, bn); + presence = purple_buddy_get_presence(buddy); + status = purple_presence_get_active_status(presence); + purple_prpl_got_user_status(account, bn, + purple_status_get_id(status), "message", xml, NULL); + } else { + purple_debug_misc("oscar", "X-Status: Can't get XML reply string\n"); + } + } else { + purple_debug_misc("oscar", "X-Status: 0x0004, 0x000b not an xstatus reply\n" ); + /* if ((userfunc = aim_callhandler(od, snac->family, snac->subtype))) + ret = userfunc(od, conn, frame, channel, sn, reason); */ + } + + } } else if (channel == 0x0004) { /* ICQ message */ switch (reason) { @@ -2699,6 +2748,7 @@ g_free(cookie); g_free(bn); + g_free(xml); return ret; } @@ -2807,6 +2857,181 @@ } /* + * Subtype 0x0006 - Send eXtra Status request + */ +int icq_im_xstatus_request(OscarData *od, const char *sn) +{ + FlapConnection *conn; + aim_snacid_t snacid; + guchar cookie[8]; + GSList *outer_tlvlist = NULL, *inner_tlvlist = NULL; + ByteStream bs, header, plugindata; + PurpleAccount *account; + const char *fmt; + char *statxml; + int xmllen; + + static const guint8 pluginid[] = + { + 0x09, 0x46, 0x13, 0x49, 0x4C, 0x7F, 0x11, 0xD1, + 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00 + }; + + static const guint8 c_plugindata[] = + { + 0x1B, 0x00, 0x0A, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0xF9, 0xD1, 0x0E, 0x00, 0xF9, 0xD1, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x00, 0x4F, 0x00, 0x3B, 0x60, 0xB3, 0xEF, 0xD8, 0x2A, 0x6C, 0x45, 0xA4, 0xE0, 0x9C, + 0x5A, 0x5E, 0x67, 0xE8, 0x65, 0x08, 0x00, 0x2A, 0x00, 0x00, 0x00, 0x53, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x20, 0x50, 0x6C, 0x75, 0x67, 0x2D, 0x69, 0x6E, 0x3A, 0x20, 0x52, 0x65, 0x6D, 0x6F, 0x74, + 0x65, 0x20, 0x4E, 0x6F, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x41, + 0x72, 0x72, 0x69, 0x76, 0x65, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x14, 0x01, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00 + }; + + if (!od || !(conn = flap_connection_findbygroup(od, 0x0004))) + return -EINVAL; + + if (!sn) + return -EINVAL; + + fmt = "<Q><PluginID>srvMng</PluginID></Q><srv><id>cAwaySrv</id><req><id>AwayStat</id><trans>2</trans><senderId>%s</senderId></req></srv>\r\n"; + + account = purple_connection_get_account(od->gc); + xmllen = strlen(fmt) - 2 + strlen(account->username); + + statxml = (char*) g_malloc(xmllen); + snprintf(statxml, xmllen, fmt, account->username); + + aim_icbm_makecookie(cookie); + + byte_stream_new(&bs, 10 + 8 + 2 + 1 + strlen(sn) + 2 + + 2 + 2 + 8 + 16 + 2 + 2 + 2 + 2 + 2 + + 2 + 2 + sizeof(c_plugindata) + xmllen + + 2 + 2); + + snacid = aim_cachesnac(od, 0x0004, 0x0006, 0x0000, NULL, 0); + aim_im_puticbm(&bs, cookie, 0x0002, sn); + + byte_stream_new(&header, (7*2) + 16 + 8 + 2 + sizeof(c_plugindata) + xmllen); /* TLV 0x0005 Stream + Size */ + byte_stream_new(&plugindata, (sizeof(c_plugindata) + xmllen)); + + byte_stream_put16(&header, 0x0000); /* Message Type: Request */ + byte_stream_putraw(&header, cookie, sizeof(cookie)); /* Message ID */ + byte_stream_putraw(&header, pluginid, sizeof(pluginid)); /* Plugin ID */ + + aim_tlvlist_add_16(&inner_tlvlist, 0x000a, 0x0001); + aim_tlvlist_add_noval(&inner_tlvlist, 0x000f); + + /* Add Plugin Specific Data */ + byte_stream_putraw(&plugindata, c_plugindata, sizeof(c_plugindata)); /* Content of TLV 0x2711 */ + byte_stream_putstr(&plugindata, statxml); + + aim_tlvlist_add_raw(&inner_tlvlist, 0x2711, (sizeof(c_plugindata) + xmllen), plugindata.data); + + aim_tlvlist_write(&header, &inner_tlvlist); + + + aim_tlvlist_add_raw(&outer_tlvlist, 0x0005, byte_stream_curpos(&header), header.data); + aim_tlvlist_add_noval(&outer_tlvlist, 0x0003); /* Empty TLV 0x0003 */ + + aim_tlvlist_write(&bs, &outer_tlvlist); + + purple_debug_misc("oscar", "X-Status Request\n"); + flap_connection_send_snac_with_priority(od, conn, 0x0004, 0x0006, 0x0000, snacid, &bs, TRUE); + + aim_tlvlist_free(inner_tlvlist); + aim_tlvlist_free(outer_tlvlist); + byte_stream_destroy(&header); + byte_stream_destroy(&plugindata); + byte_stream_destroy(&bs); + g_free(statxml); + + return 0; +} + +int icq_relay_xstatus(OscarData *od, const char *sn, const guchar *cookie) +{ + FlapConnection *conn; + ByteStream bs; + aim_snacid_t snacid; + PurpleAccount *account; + PurpleStatus *status; + const char *fmt; + const char *formatted_msg; + char *msg; + char *statxml; + const char *title; + int len; + + static const guint8 plugindata[] = { + 0x1B, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0xF9, 0xD1, 0x0E, 0x00, 0xF9, 0xD1, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x4F, + 0x00, 0x3B, 0x60, 0xB3, 0xEF, 0xD8, 0x2A, 0x6C, 0x45, 0xA4, 0xE0, + 0x9C, 0x5A, 0x5E, 0x67, 0xE8, 0x65, 0x08, 0x00, 0x2A, 0x00, 0x00, + 0x00, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x20, 0x50, 0x6C, 0x75, + 0x67, 0x2D, 0x69, 0x6E, 0x3A, 0x20, 0x52, 0x65, 0x6D, 0x6F, 0x74, + 0x65, 0x20, 0x4E, 0x6F, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6F, 0x6E, 0x20, 0x41, 0x72, 0x72, 0x69, 0x76, 0x65, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xF3, 0x01, 0x00, 0x00, 0xEF, 0x01, 0x00, 0x00 + }; + + fmt = "<ret event='OnRemoteNotification'><srv><id>cAwaySrv</id><val srv_id='cAwaySrv'><Root><CASXtraSetAwayMessage></CASXtraSetAwayMessage>&l t;uin>%s</uin><index>1</index><title>%s</title><desc>%s</desc></Root></val></srv><srv><id>cRandomizerSrv</id><val srv_id='cRandomizerSrv'>undefined</val></srv></ret>\r\n"; + + + if (!od || !(conn = flap_connection_findbygroup(od, 0x0002))) + return -EINVAL; + + if (!sn) + return -EINVAL; + + account = purple_connection_get_account(od->gc); + if(!account) return -EINVAL; + +/* if (!strcmp(account->username, sn)) + icq_im_xstatus_request(od, sn); */ + + status = purple_presence_get_active_status(account->presence); + if (!status) return -EINVAL; + title = purple_status_get_name(status); + if (!title) return -EINVAL; + formatted_msg = purple_status_get_attr_string(status, "message"); + if (!formatted_msg) return -EINVAL; + msg = purple_markup_strip_html(formatted_msg); + if (!msg) return -EINVAL; + len = strlen(fmt)-6+strlen(account->username)+strlen(title)+strlen(msg); + statxml = (char*) g_malloc(len); + + snprintf(statxml, len, fmt, + account->username, title, msg); + + purple_debug_misc("oscar", "X-Status AutoReply: %s, %s\n", formatted_msg, msg); + + byte_stream_new(&bs, 10 + 8 + 2 + 1 + strlen(sn) + 2 + sizeof(plugindata) + strlen(statxml)); /* 16 extra */ + + snacid = aim_cachesnac(od, 0x0004, 0x000b, 0x0000, NULL, 0); + aim_im_puticbm(&bs, cookie, 0x0002, sn); + byte_stream_put16(&bs, 0x0003); + byte_stream_putraw(&bs, plugindata, sizeof(plugindata)); + byte_stream_putraw(&bs, (const guint8*)statxml, strlen(statxml)); + + flap_connection_send_snac_with_priority(od, conn, 0x0004, 0x000b, 0x0000, snacid, &bs, TRUE); + + g_free(statxml); + g_free(msg); + byte_stream_destroy(&bs); + + return 0; +} + +/* * Subtype 0x0014 - Receive a mini typing notification (mtn) packet. * * This is supported by winaim5 and newer, MacAIM bleh and newer, iChat bleh and newer, diff -r 221cebbc35d8 -r 6d3a90b49dba libpurple/protocols/oscar/family_locate.c --- a/libpurple/protocols/oscar/family_locate.c Thu Feb 18 22:28:41 2010 +0000 +++ b/libpurple/protocols/oscar/family_locate.c Sun Feb 28 04:07:39 2010 +0000 @@ -45,7 +45,7 @@ * But, eh. */ static const struct { - guint32 flag; + guint64 flag; guint8 data[16]; } aim_caps[] = { @@ -166,6 +166,16 @@ {0x09, 0x46, 0x13, 0x4a, 0x4c, 0x7f, 0x11, 0xd1, 0x22, 0x82, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}}, + /* New format of caps (xtraz icons) */ + {OSCAR_CAPABILITY_NEWCAPS, + {0x09, 0x46, 0x00, 0x00, 0x4c, 0x7f, 0x11, 0xd1, + 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}}, + + /* Support xtraz statuses */ + {OSCAR_CAPABILITY_XTRAZ, + {0x1a, 0x09, 0x3c, 0x6c, 0xd7, 0xFD, 0x4e, 0xc5, + 0x9d, 0x51, 0xa6, 0x47, 0x4e, 0x34, 0xf5, 0xa0}}, + {OSCAR_CAPABILITY_SENDBUDDYLIST, {0x09, 0x46, 0x13, 0x4b, 0x4c, 0x7f, 0x11, 0xd1, 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}}, @@ -240,6 +250,202 @@ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, }; +/* Keep this array synchronized with icq_purple_moods. */ +static const struct { + const char *mood; + guint8 data[16]; +} icq_custom_icons[] = { + + {"thinking", + {0x3f, 0xb0, 0xbd, 0x36, 0xaf, 0x3b, 0x4a, 0x60, + 0x9e, 0xef, 0xcf, 0x19, 0x0f, 0x6a, 0x5a, 0x7f}}, + + {"busy", + {0x48, 0x8e, 0x14, 0x89, 0x8a, 0xca, 0x4a, 0x08, + 0x82, 0xaa, 0x77, 0xce, 0x7a, 0x16, 0x52, 0x08}}, + + {"shopping", + {0x63, 0x62, 0x73, 0x37, 0xa0, 0x3f, 0x49, 0xff, + 0x80, 0xe5, 0xf7, 0x09, 0xcd, 0xe0, 0xa4, 0xee}}, + + /* This was in the original patch, but isn't what the official client + * (ICQ 6) sets when you choose its typewriter icon. */ + {"typing", + {0x63, 0x4f, 0x6b, 0xd8 ,0xad, 0xd2, 0x4a, 0xa1, + 0xaa, 0xb9, 0x11, 0x5b, 0xc2, 0x6d, 0x05, 0xa1}}, + + {"question", + {0x63, 0x14, 0x36, 0xff, 0x3f, 0x8a, 0x40, 0xd0, + 0xa5, 0xcb, 0x7b, 0x66, 0xe0, 0x51, 0xb3, 0x64}}, + + {"angry", + {0x01, 0xd8, 0xd7, 0xee, 0xac, 0x3b, 0x49, 0x2a, + 0xa5, 0x8d, 0xd3, 0xd8, 0x77, 0xe6, 0x6b, 0x92}}, + + {"plate", + {0xf8, 0xe8, 0xd7, 0xb2, 0x82, 0xc4, 0x41, 0x42, + 0x90, 0xf8, 0x10, 0xc6, 0xce, 0x0a, 0x89, 0xa6}}, + + {"cinema", + {0x10, 0x7a, 0x9a, 0x18, 0x12, 0x32, 0x4d, 0xa4, + 0xb6, 0xcd, 0x08, 0x79, 0xdb, 0x78, 0x0f, 0x09}}, + + {"sick", + {0x1f, 0x7a, 0x40, 0x71, 0xbf, 0x3b, 0x4e, 0x60, + 0xbc, 0x32, 0x4c, 0x57, 0x87, 0xb0, 0x4c, 0xf1}}, + + {"typing", + {0x2c, 0xe0, 0xe4, 0xe5, 0x7c, 0x64, 0x43, 0x70, + 0x9c, 0x3a, 0x7a, 0x1c, 0xe8, 0x78, 0xa7, 0xdc}}, + + {"suit", + {0xb7, 0x08, 0x67, 0xf5, 0x38, 0x25, 0x43, 0x27, + 0xa1, 0xff, 0xcf, 0x4c, 0xc1, 0x93, 0x97, 0x97}}, + + {"bathing", + {0x5a, 0x58, 0x1e, 0xa1, 0xe5, 0x80, 0x43, 0x0c, + 0xa0, 0x6f, 0x61, 0x22, 0x98, 0xb7, 0xe4, 0xc7}}, + + {"tv", + {0x80, 0x53, 0x7d, 0xe2, 0xa4, 0x67, 0x4a, 0x76, + 0xb3, 0x54, 0x6d, 0xfd, 0x07, 0x5f, 0x5e, 0xc6}}, + + {"excited", + {0x6f, 0x49, 0x30, 0x98, 0x4f, 0x7c, 0x4a, 0xff, + 0xa2, 0x76, 0x34, 0xa0, 0x3b, 0xce, 0xae, 0xa7}}, + + {"sleeping", + {0x78, 0x5e, 0x8c, 0x48, 0x40, 0xd3, 0x4c, 0x65, + 0x88, 0x6f, 0x04, 0xcf, 0x3f, 0x3f, 0x43, 0xdf}}, + + {"hiptop", + {0x10, 0x11, 0x17, 0xc9, 0xa3, 0xb0, 0x40, 0xf9, + 0x81, 0xac, 0x49, 0xe1, 0x59, 0xfb, 0xd5, 0xd4}}, + + {"in_love", + {0xdd, 0xcf, 0x0e, 0xa9, 0x71, 0x95, 0x40, 0x48, + 0xa9, 0xc6, 0x41, 0x32, 0x06, 0xd6, 0xf2, 0x80}}, + + {"sleepy", + {0x83, 0xc9, 0xb7, 0x8e, 0x77, 0xe7, 0x43, 0x78, + 0xb2, 0xc5, 0xfb, 0x6c, 0xfc, 0xc3, 0x5b, 0xec}}, + + {"meeting", + {0xf1, 0x8a, 0xb5, 0x2e, 0xdc, 0x57, 0x49, 0x1d, + 0x99, 0xdc, 0x64, 0x44, 0x50, 0x24, 0x57, 0xaf}}, + + {"phone", + {0x12, 0x92, 0xe5, 0x50, 0x1b, 0x64, 0x4f, 0x66, + 0xb2, 0x06, 0xb2, 0x9a, 0xf3, 0x78, 0xe4, 0x8d}}, + + {"surfing", + {0xa6, 0xed, 0x55, 0x7e, 0x6b, 0xf7, 0x44, 0xd4, + 0xa5, 0xd4, 0xd2, 0xe7, 0xd9, 0x5c, 0xe8, 0x1f}}, + + {"mobile", + {0x16, 0x0c, 0x60, 0xbb, 0xdd, 0x44, 0x43, 0xf3, + 0x91, 0x40, 0x05, 0x0f, 0x00, 0xe6, 0xc0, 0x09}}, + + {"search", + {0xd4, 0xe2, 0xb0, 0xba, 0x33, 0x4e, 0x4f, 0xa5, + 0x98, 0xd0, 0x11, 0x7d, 0xbf, 0x4d, 0x3c, 0xc8}}, + + {"party", + {0xe6, 0x01, 0xe4, 0x1c, 0x33, 0x73, 0x4b, 0xd1, + 0xbc, 0x06, 0x81, 0x1d, 0x6c, 0x32, 0x3d, 0x81}}, + + {"coffee", + {0x1b, 0x78, 0xae, 0x31, 0xfa, 0x0b, 0x4d, 0x38, + 0x93, 0xd1, 0x99, 0x7e, 0xee, 0xaf, 0xb2, 0x18}}, + + {"console", + {0xd4, 0xa6, 0x11, 0xd0, 0x8f, 0x01, 0x4e, 0xc0, + 0x92, 0x23, 0xc5, 0xb6, 0xbe, 0xc6, 0xcc, 0xf0}}, + + {"internet", + {0x12, 0xd0, 0x7e, 0x3e, 0xf8, 0x85, 0x48, 0x9e, + 0x8e, 0x97, 0xa7, 0x2a, 0x65, 0x51, 0xe5, 0x8d}}, + + {"cigarette", + {0x64, 0x43, 0xc6, 0xaf, 0x22, 0x60, 0x45, 0x17, + 0xb5, 0x8c, 0xd7, 0xdf, 0x8e, 0x29, 0x03, 0x52}}, + + {"writing", + {0x00, 0x72, 0xd9, 0x08, 0x4a, 0xd1, 0x43, 0xdd, + 0x91, 0x99, 0x6f, 0x02, 0x69, 0x66, 0x02, 0x6f}}, + + {"beer", + {0x8c, 0x50, 0xdb, 0xae, 0x81, 0xed, 0x47, 0x86, + 0xac, 0xca, 0x16, 0xcc, 0x32, 0x13, 0xc7, 0xb7}}, + + {"music", + {0x61, 0xbe, 0xe0, 0xdd, 0x8b, 0xdd, 0x47, 0x5d, + 0x8d, 0xee, 0x5f, 0x4b, 0xaa, 0xcf, 0x19, 0xa7}}, + + {"studying", + {0x60, 0x9d, 0x52, 0xf8, 0xa2, 0x9a, 0x49, 0xa6, + 0xb2, 0xa0, 0x25, 0x24, 0xc5, 0xe9, 0xd2, 0x60}}, + + {"working", + {0xba, 0x74, 0xdb, 0x3e, 0x9e, 0x24, 0x43, 0x4b, + 0x87, 0xb6, 0x2f, 0x6b, 0x8d, 0xfe, 0xe5, 0x0f}}, + + {"restroom", + {0x16, 0xf5, 0xb7, 0x6f, 0xa9, 0xd2, 0x40, 0x35, + 0x8c, 0xc5, 0xc0, 0x84, 0x70, 0x3c, 0x98, 0xfa}}, + + {NULL, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}} +}; + +/* Keep this array synchronized with icq_custom_icons. */ +static PurpleMood icq_purple_moods[] = { + {"thinking", N_("Thinking"), NULL}, + {"busy", N_("Busy"), NULL}, + {"shopping", N_("Shopping"), NULL}, + /* This was in the original patch, but isn't what the official client + * (ICQ 6) sets when you choose its typewriter icon. */ + {"typing", NULL, NULL}, + {"question", N_("Questioning"), NULL}, + {"angry", N_("Angry"), NULL}, + {"plate", N_("Eating"), NULL}, + {"cinema", N_("Watching a movie"), NULL}, + {"sick", N_("Sick"), NULL}, + {"typing", N_("Typing"), NULL}, + {"suit", N_("At the office"), NULL}, + {"bathing", N_("Taking a bath"), NULL}, + {"tv", N_("Watching TV"), NULL}, + {"excited", N_("Having fun"), NULL}, + {"sleeping", N_("Sleeping"), NULL}, + {"hiptop", N_("Using a PDA"), NULL}, + {"in_love", N_("In love"), NULL}, + /* Sleepy / Tired */ + {"sleepy", N_("Sleepy"), NULL}, + {"meeting", N_("Meeting friends"), NULL}, + {"phone", N_("On the phone"), NULL}, + {"surfing", N_("Surfing"), NULL}, + /* "I am mobile." / "John is mobile." */ + {"mobile", N_("Mobile"), NULL}, + {"search", N_("Searching the web"), NULL}, + {"party", N_("At a party"), NULL}, + {"coffee", N_("Having Coffee"), NULL}, + /* Playing video games */ + {"console", N_("Gaming"), NULL}, + {"internet", N_("Browsing the web"), NULL}, + {"cigarette", N_("Smoking"), NULL}, + {"writing", N_("Writing"), NULL}, + /* Drinking [Alcohol] */ + {"beer", N_("Drinking"), NULL}, + {"music", N_("Listening to music"), NULL}, + {"studying", N_("Studying"), NULL}, + {"working", N_("Working"), NULL}, + {"restroom", N_("In the restroom"), NULL}, + /* Mark the last record. */ + {NULL, NULL, NULL}, +}; + + /* * Add the userinfo to our linked list. If we already have userinfo * for this buddy, then just overwrite parts of the old data. @@ -274,6 +480,7 @@ cur->sessionlen = userinfo->sessionlen; if (userinfo->capabilities != 0) cur->capabilities = userinfo->capabilities; + cur->present |= userinfo->present; if (userinfo->iconcsumlen > 0) { @@ -398,13 +605,38 @@ cap[8], cap[9], cap[10], cap[11], cap[12], cap[13], cap[14], cap[15]); - g_free(cap); } return flags; } +static const char * +aim_receive_custom_icon(OscarData *od, ByteStream *bs, int len) +{ + int offset; + const char *result = NULL; + + for (offset = 0; byte_stream_empty(bs) && (offset < len); offset += 0x10) { + /* check wheather this capability is a custom user icon */ + guint8 *cap; + int i; + + cap = byte_stream_getraw(bs, 0x10); + + for (i = 0; icq_custom_icons[i].mood; i++) { + if (memcmp(&icq_custom_icons[i].data, cap, 0x10) == 0) { + purple_debug_misc("oscar", "Custom status icon: %s\n", icq_purple_moods[i].description); + result = icq_custom_icons[i].mood; + break; /* should only match once... */ + } + } + g_free(cap); + } + + return result; +} + guint32 aim_locate_getcaps_short(OscarData *od, ByteStream *bs, int len) { @@ -495,6 +727,38 @@ g_free(info->away_encoding); } +static const struct { + char *icqmood; + const char *mood; +} icqmoods[] = { + {"icqmood0", "shopping"}, + {"icqmood1", "bathing"}, + {"icqmood2", "sleepy"}, + {"icqmood3", "party"}, + {"icqmood4", "beer"}, + {"icqmood5", "thinking"}, + {"icqmood6", "plate"}, + {"icqmood7", "tv"}, + {"icqmood8", "meeting"}, + {"icqmood9", "coffee"}, + {"icqmood10", "music"}, + {"icqmood11", "suit"}, + {"icqmood12", "cinema"}, + {"icqmood13", "smile-big"}, + {"icqmood14", "phone"}, + {"icqmood15", "console"}, + {"icqmood16", "studying"}, + {"icqmood17", "sick"}, + {"icqmood18", "sleeping"}, + {"icqmood19", "surfing"}, + {"icqmood20", "internet"}, + {"icqmood21", "working"}, + {"icqmood22", "typing"}, + {"icqmood23", "angry"}, + {NULL, 0} + +}; + /* * AIM is fairly regular about providing user info. This is a generic * routine to extract it in its standard form. @@ -535,11 +799,12 @@ for (curtlv = 0; curtlv < tlvcnt; curtlv++) { guint16 type, length; int endpos; + int curpos; type = byte_stream_get16(bs); length = byte_stream_get16(bs); - - endpos = byte_stream_curpos(bs) + MIN(length, byte_stream_empty(bs)); + curpos = byte_stream_curpos(bs); + endpos = curpos + MIN(length, byte_stream_empty(bs)); if (type == 0x0001) { /* @@ -651,11 +916,23 @@ outinfo->present |= AIM_USERINFO_PRESENT_ICQDATA; } else if (type == 0x000d) { + PurpleAccount *account = purple_connection_get_account(od->gc); + const char *mood; + /* * OSCAR Capability information */ outinfo->capabilities |= aim_locate_getcaps(od, bs, length); outinfo->present |= AIM_USERINFO_PRESENT_CAPABILITIES; + byte_stream_setpos(bs, curpos); + + mood = aim_receive_custom_icon(od, bs, length); + if (mood) + purple_prpl_got_user_status(account, outinfo->bn, "mood", + PURPLE_MOOD_NAME, mood, + NULL); + else + purple_prpl_got_user_status_deactive(account, outinfo->bn, "mood"); } else if (type == 0x000e) { /* @@ -791,6 +1068,37 @@ outinfo->itmsurl_encoding = NULL; } } break; + + case 0x000e: { /* ICQ mood */ + PurpleAccount *account = purple_connection_get_account(od->gc); + char *icqmood; + gint32 i; + const char *mood = NULL; + + icqmood = byte_stream_getstr(bs, length2); + + /* icqmood = "" means X-Status + * with no mood icon. */ + if (*icqmood) { + for (i = 0; icqmoods[i].icqmood; i++) { + if (!strcmp(icqmood, icqmoods[i].icqmood)) { + mood = icqmoods[i].mood; + break; /* should only match once... */ + } + } + + if (!mood) + purple_debug_warning("oscar", "Unknown icqmood: %s\n", icqmood); + } + g_free(icqmood); + + if (mood) + purple_prpl_got_user_status(account, outinfo->bn, "mood", + PURPLE_MOOD_NAME, mood, + NULL); + else + purple_prpl_got_user_status_deactive(account, outinfo->bn, "mood"); + } break; } /* Save ourselves. */ @@ -857,6 +1165,10 @@ return 0; } +/* Apparently, this is never called. + * If you activate it, figure out a way to know what mood to pass to + * aim_tlvlist_add_caps() below. --rlaager */ +#if 0 /* * Inverse of aim_info_extract() */ @@ -892,8 +1204,9 @@ } #endif - if (info->present & AIM_USERINFO_PRESENT_CAPABILITIES) - aim_tlvlist_add_caps(&tlvlist, 0x000d, info->capabilities); + if (info->present & AIM_USERINFO_PRESENT_CAPABILITIES) { + aim_tlvlist_add_caps(&tlvlist, 0x000d, info->capabilities, NULL); + } if (info->present & AIM_USERINFO_PRESENT_SESSIONLEN) aim_tlvlist_add_32(&tlvlist, (guint16)((info->flags & AIM_FLAG_AOL) ? 0x0010 : 0x000f), info->sessionlen); @@ -904,6 +1217,7 @@ return 0; } +#endif /* * Subtype 0x0001 @@ -1089,6 +1403,10 @@ aim_locate_setcaps(OscarData *od, guint32 caps) { FlapConnection *conn; + PurpleAccount *account = purple_connection_get_account(od->gc); + PurplePresence *presence = purple_account_get_presence(account); + PurpleStatus *status = purple_presence_get_status(presence, "mood"); + const char *mood = purple_status_get_attr_string(status, PURPLE_MOOD_NAME); ByteStream bs; aim_snacid_t snacid; GSList *tlvlist = NULL; @@ -1096,7 +1414,7 @@ if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_LOCATE))) return -EINVAL; - aim_tlvlist_add_caps(&tlvlist, 0x0005, caps); + aim_tlvlist_add_caps(&tlvlist, 0x0005, caps, mood); byte_stream_new(&bs, aim_tlvlist_size(tlvlist)); @@ -1179,9 +1497,21 @@ /* Caps will be 5 */ if ((tlv = aim_tlv_gettlv(tlvlist, 0x0005, 1))) { ByteStream cbs; + PurpleAccount *account = purple_connection_get_account(od->gc); + const char *mood; + byte_stream_init(&cbs, tlv->value, tlv->length); userinfo->capabilities = aim_locate_getcaps(od, &cbs, tlv->length); + byte_stream_rewind(&cbs); userinfo->present = AIM_USERINFO_PRESENT_CAPABILITIES; + + mood = aim_receive_custom_icon(od, &cbs, tlv->length); + if (mood) + purple_prpl_got_user_status(account, userinfo->bn, "mood", + PURPLE_MOOD_NAME, mood, + NULL); + else + purple_prpl_got_user_status_deactive(account, userinfo->bn, "mood"); } aim_tlvlist_free(tlvlist); @@ -1399,3 +1729,57 @@ return 0; } + +#if 0 //rlaager +const char* aim_get_custom_icon_mood(gint32 no) +{ + if (no >= G_N_ELEMENTS(aim_custom_icons) || no < 1) + return NULL; + return aim_custom_icons[no].mood.mood; +} +#endif + +const char* +icq_get_custom_icon_description(const char *mood) +{ + int i; + + if (!(mood && *mood)) + return NULL; + + for (i = 0; icq_custom_icons[i].mood; i++) { + /* We check that description is not NULL to exclude + * duplicates, like the typing duplicate. */ + if (icq_purple_moods[i].description && + !strcmp(mood, icq_custom_icons[i].mood)) { + return icq_purple_moods[i].description; + } + } + + return NULL; +} + +guint8* +icq_get_custom_icon_data(const char *mood) +{ + int i; + + if (!(mood && *mood)) + return NULL; + + for (i = 0; icq_custom_icons[i].mood; i++) { + /* We check that description is not NULL to exclude + * duplicates, like the typing duplicate. */ + if (icq_purple_moods[i].description && + !strcmp(mood, icq_custom_icons[i].mood)) { + return (guint8 *)icq_custom_icons[i].data; + } + } + return NULL; +} + +PurpleMood* +icq_get_purple_moods(PurpleAccount *account) +{ + return icq_purple_moods; +} diff -r 221cebbc35d8 -r 6d3a90b49dba libpurple/protocols/oscar/flap_connection.c --- a/libpurple/protocols/oscar/flap_connection.c Thu Feb 18 22:28:41 2010 +0000 +++ b/libpurple/protocols/oscar/flap_connection.c Sun Feb 28 04:07:39 2010 +0000 @@ -364,6 +364,12 @@ conn->connect_data = NULL; } + if (conn->gsc != NULL && conn->gsc->connect_data != NULL) + { + purple_ssl_close(conn->gsc); + conn->gsc = NULL; + } + if (conn->new_conn_data != NULL) { if (conn->type == SNAC_FAMILY_CHAT) diff -r 221cebbc35d8 -r 6d3a90b49dba libpurple/protocols/oscar/libaim.c --- a/libpurple/protocols/oscar/libaim.c Thu Feb 18 22:28:41 2010 +0000 +++ b/libpurple/protocols/oscar/libaim.c Sun Feb 28 04:07:39 2010 +0000 @@ -97,7 +97,8 @@ sizeof(PurplePluginProtocolInfo), /* struct_size */ NULL, /* get_account_text_table */ NULL, /* initiate_media */ - NULL /* can_do_media */ + NULL, /* get_media_caps */ + NULL /* get_moods */ }; static PurplePluginInfo info = diff -r 221cebbc35d8 -r 6d3a90b49dba libpurple/protocols/oscar/libicq.c --- a/libpurple/protocols/oscar/libicq.c Thu Feb 18 22:28:41 2010 +0000 +++ b/libpurple/protocols/oscar/libicq.c Sun Feb 28 04:07:39 2010 +0000 @@ -108,7 +108,8 @@ sizeof(PurplePluginProtocolInfo), /* struct_size */ icq_get_account_text_table, /* get_account_text_table */ NULL, /* initiate_media */ - NULL /* can_do_media */ + NULL, /* can_do_media */ + oscar_get_purple_moods, /* get_moods */ }; static PurplePluginInfo info = diff -r 221cebbc35d8 -r 6d3a90b49dba libpurple/protocols/oscar/oscar.c --- a/libpurple/protocols/oscar/oscar.c Thu Feb 18 22:28:41 2010 +0000 +++ b/libpurple/protocols/oscar/oscar.c Sun Feb 28 04:07:39 2010 +0000 @@ -61,6 +61,11 @@ #define OSCAR_STATUS_ID_FREE4CHAT "free4chat" #define OSCAR_STATUS_ID_CUSTOM "custom" #define OSCAR_STATUS_ID_MOBILE "mobile" +#define OSCAR_STATUS_ID_EVIL "evil" +#define OSCAR_STATUS_ID_DEPRESSION "depression" +#define OSCAR_STATUS_ID_ATHOME "athome" +#define OSCAR_STATUS_ID_ATWORK "atwork" +#define OSCAR_STATUS_ID_LUNCH "lunch" #define AIMHASHDATA "http://pidgin.im/aim_data.php3" @@ -68,7 +73,7 @@ static OscarCapability purple_caps = (OSCAR_CAPABILITY_CHAT | OSCAR_CAPABILITY_BUDDYICON | OSCAR_CAPABILITY_DIRECTIM | OSCAR_CAPABILITY_SENDFILE | OSCAR_CAPABILITY_UNICODE | OSCAR_CAPABILITY_INTEROPERATE | - OSCAR_CAPABILITY_SHORTCAPS | OSCAR_CAPABILITY_TYPING); + OSCAR_CAPABILITY_SHORTCAPS | OSCAR_CAPABILITY_TYPING | OSCAR_CAPABILITY_ICQSERVERRELAY | OSCAR_CAPABILITY_NEWCAPS | OSCAR_CAPABILITY_XTRAZ); static guint8 features_aim[] = {0x01, 0x01, 0x01, 0x02}; static guint8 features_icq[] = {0x01, 0x06}; @@ -672,7 +677,7 @@ { GString *str; const gchar *tmp; - guint bit = 1; + guint64 bit = 1; str = g_string_new(""); @@ -703,6 +708,10 @@ case OSCAR_CAPABILITY_GAMES2: tmp = _("Games"); break; + case OSCAR_CAPABILITY_XTRAZ: + case OSCAR_CAPABILITY_NEWCAPS: + tmp = _("ICQ Xtraz"); + break; case OSCAR_CAPABILITY_ADDINS: tmp = _("Add-Ins"); break; @@ -784,6 +793,16 @@ return g_strdup(_("Web Aware")); else if (state & AIM_ICQ_STATE_INVISIBLE) return g_strdup(_("Invisible")); + else if (state & AIM_ICQ_STATE_EVIL) + return g_strdup(_("Evil")); + else if (state & AIM_ICQ_STATE_DEPRESSION) + return g_strdup(_("Depression")); + else if (state & AIM_ICQ_STATE_ATHOME) + return g_strdup(_("At home")); + else if (state & AIM_ICQ_STATE_ATWORK) + return g_strdup(_("At work")); + else if (state & AIM_ICQ_STATE_LUNCH) + return g_strdup(_("At lunch")); else return g_strdup(_("Online")); } @@ -961,6 +980,16 @@ } } + if (presence) { + const char *mood; + const char *description; + status = purple_presence_get_status(presence, "mood"); + mood = purple_status_get_attr_string(status, PURPLE_MOOD_NAME); + description = icq_get_custom_icon_description(mood); + if (description && *description) + purple_notify_user_info_add_pair(user_info, _("Mood"), _(description)); + } + purple_notify_user_info_add_pair(user_info, _("Status"), message); g_free(message); } @@ -2240,6 +2269,16 @@ status_id = OSCAR_STATUS_ID_AWAY; else if (type & AIM_ICQ_STATE_INVISIBLE) status_id = OSCAR_STATUS_ID_INVISIBLE; + else if (type & AIM_ICQ_STATE_EVIL) + status_id = OSCAR_STATUS_ID_EVIL; + else if (type & AIM_ICQ_STATE_DEPRESSION) + status_id = OSCAR_STATUS_ID_DEPRESSION; + else if (type & AIM_ICQ_STATE_ATHOME) + status_id = OSCAR_STATUS_ID_ATHOME; + else if (type & AIM_ICQ_STATE_ATWORK) + status_id = OSCAR_STATUS_ID_ATWORK; + else if (type & AIM_ICQ_STATE_LUNCH) + status_id = OSCAR_STATUS_ID_LUNCH; else status_id = OSCAR_STATUS_ID_AVAILABLE; } else { @@ -2552,7 +2591,9 @@ { PurpleConnection *gc; PurpleAccount *account; + PurpleMessageFlags flags = 0; char *message = NULL; + char *rtfmsg = NULL; g_return_val_if_fail(od != NULL, 0); g_return_val_if_fail(od->gc != NULL, 0); @@ -2582,6 +2623,20 @@ } } + if (args->info.rtfmsg.rtfmsg != NULL) + { + if (args->encoding != NULL) + { + char *encoding = NULL; + encoding = oscar_encoding_extract(args->encoding); + rtfmsg = oscar_encoding_to_utf8(account, encoding, args->info.rtfmsg.rtfmsg, + strlen(args->info.rtfmsg.rtfmsg)); + g_free(encoding); + } else { + if (g_utf8_validate(args->info.rtfmsg.rtfmsg, strlen(args->info.rtfmsg.rtfmsg), NULL)) + rtfmsg = g_strdup(args->info.rtfmsg.rtfmsg); + } + } if (args->type & OSCAR_CAPABILITY_CHAT) { char *encoding, *utf8name, *tmp; @@ -2667,10 +2722,28 @@ else if (args->type & OSCAR_CAPABILITY_ICQSERVERRELAY) { - purple_debug_error("oscar", "Got an ICQ Server Relay message of " + purple_debug_info("oscar", "Got an ICQ Server Relay message of " "type %d\n", args->info.rtfmsg.msgtype); - } - + purple_debug_info("oscar", "Sending X-Status Reply\n"); + + if(args->info.rtfmsg.msgtype == 26) + icq_relay_xstatus(od, userinfo->bn, args->cookie); + + if(args->info.rtfmsg.msgtype == 1) + { + if(rtfmsg) + { + serv_got_im(gc, userinfo->bn, rtfmsg, flags, + time(NULL)); + } + else + { + serv_got_im(gc, userinfo->bn, + args->info.rtfmsg.rtfmsg, flags, + time(NULL)); + } + } + } else { purple_debug_error("oscar", "Unknown request class %hu\n", @@ -3250,6 +3323,29 @@ } break; + case 0x0006: { /* Reply from an ICQ status message request */ + char *statusmsg, **splitmsg; + PurpleNotifyUserInfo *user_info; + + /* Split at (carriage return/newline)'s, then rejoin later with BRs between. */ + statusmsg = oscar_icqstatus(state); + splitmsg = g_strsplit(msg, "\r\n", 0); + + user_info = purple_notify_user_info_new(); + + purple_notify_user_info_add_pair(user_info, _("UIN"), who); + purple_notify_user_info_add_pair(user_info, _("Status"), statusmsg); + purple_notify_user_info_add_section_break(user_info); + purple_notify_user_info_add_pair(user_info, NULL, g_strjoinv("
", splitmsg)); + + g_free(statusmsg); + g_strfreev(splitmsg); + + purple_notify_userinfo(gc, who, user_info, NULL, NULL); + purple_notify_user_info_destroy(user_info); + + } break; + default: { purple_debug_warning("oscar", "Received an unknown client auto-response from %s. " @@ -4848,6 +4944,16 @@ data |= AIM_ICQ_STATE_CHAT; else if (!strcmp(status_id, OSCAR_STATUS_ID_INVISIBLE)) data |= AIM_ICQ_STATE_INVISIBLE; + else if (!strcmp(status_id, OSCAR_STATUS_ID_EVIL)) + data |= AIM_ICQ_STATE_EVIL; + else if (!strcmp(status_id, OSCAR_STATUS_ID_DEPRESSION)) + data |= AIM_ICQ_STATE_DEPRESSION; + else if (!strcmp(status_id, OSCAR_STATUS_ID_ATWORK)) + data |= AIM_ICQ_STATE_ATWORK; + else if (!strcmp(status_id, OSCAR_STATUS_ID_ATHOME)) + data |= AIM_ICQ_STATE_ATHOME; + else if (!strcmp(status_id, OSCAR_STATUS_ID_LUNCH)) + data |= AIM_ICQ_STATE_LUNCH; else if (!strcmp(status_id, OSCAR_STATUS_ID_CUSTOM)) data |= AIM_ICQ_STATE_OUT | AIM_ICQ_STATE_AWAY; @@ -5009,6 +5115,12 @@ pc = purple_account_get_connection(account); od = purple_connection_get_protocol_data(pc); + /* There's no need to do the stuff below for mood updates. */ + if (purple_status_type_get_primitive(purple_status_get_type(status)) == PURPLE_STATUS_MOOD) { + aim_locate_setcaps(od, purple_caps); + return; + } + /* Set the AIM-style away message for both AIM and ICQ accounts */ oscar_set_info_and_status(account, FALSE, NULL, TRUE, status); @@ -5961,6 +6073,11 @@ return 0; } +PurpleMood* oscar_get_purple_moods(PurpleAccount *account) +{ + return icq_get_purple_moods(account); +} + const char *oscar_list_icon_icq(PurpleAccount *a, PurpleBuddy *b) { const char *name = b ? purple_buddy_get_name(b) : NULL; @@ -6031,12 +6148,17 @@ return "admin"; if (userinfo->flags & AIM_FLAG_ACTIVEBUDDY) return "bot"; - if (userinfo->capabilities & OSCAR_CAPABILITY_HIPTOP) - return "hiptop"; if (userinfo->capabilities & OSCAR_CAPABILITY_SECUREIM) return "secure"; if (userinfo->icqinfo.status & AIM_ICQ_STATE_BIRTHDAY) return "birthday"; + + /* Make the mood icon override anything below this. */ + if (purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_MOOD)) + return NULL; + + if (userinfo->capabilities & OSCAR_CAPABILITY_HIPTOP) + return "hiptop"; } return NULL; } @@ -6259,9 +6381,53 @@ purple_value_new(PURPLE_TYPE_STRING), NULL); status_types = g_list_prepend(status_types, type); - type = purple_status_type_new_full(PURPLE_STATUS_AVAILABLE, + type = purple_status_type_new_with_attrs(PURPLE_STATUS_AVAILABLE, OSCAR_STATUS_ID_FREE4CHAT, - _("Free For Chat"), TRUE, is_icq, FALSE); + _("Free For Chat"), TRUE, is_icq, FALSE, + "message", _("Message"), + purple_value_new(PURPLE_TYPE_STRING), NULL); + + status_types = g_list_prepend(status_types, type); + + type = purple_status_type_new_with_attrs(PURPLE_STATUS_AVAILABLE, + OSCAR_STATUS_ID_EVIL, + _("Evil"), TRUE, is_icq, FALSE, + "message", _("Message"), + purple_value_new(PURPLE_TYPE_STRING), NULL); + status_types = g_list_prepend(status_types, type); + + + type = purple_status_type_new_with_attrs(PURPLE_STATUS_AVAILABLE, + OSCAR_STATUS_ID_DEPRESSION, + _("Depression"), TRUE, is_icq, FALSE, + "message", _("Message"), + purple_value_new(PURPLE_TYPE_STRING), NULL); + status_types = g_list_prepend(status_types, type); + + + type = purple_status_type_new_with_attrs(PURPLE_STATUS_AVAILABLE, + OSCAR_STATUS_ID_ATHOME, + _("At home"), TRUE, is_icq, FALSE, + "message", _("Message"), + purple_value_new(PURPLE_TYPE_STRING), NULL); + status_types = g_list_prepend(status_types, type); + + + type = purple_status_type_new_with_attrs(PURPLE_STATUS_AVAILABLE, + OSCAR_STATUS_ID_ATWORK, + _("At work"), TRUE, is_icq, FALSE, + "message", _("Message"), + purple_value_new(PURPLE_TYPE_STRING), NULL); + + status_types = g_list_prepend(status_types, type); + + + type = purple_status_type_new_with_attrs(PURPLE_STATUS_AVAILABLE, + OSCAR_STATUS_ID_LUNCH, + _("Lunch"), TRUE, is_icq, FALSE, + "message", _("Message"), + purple_value_new(PURPLE_TYPE_STRING), NULL); + status_types = g_list_prepend(status_types, type); type = purple_status_type_new_with_attrs(PURPLE_STATUS_AWAY, @@ -6271,9 +6437,12 @@ purple_value_new(PURPLE_TYPE_STRING), NULL); status_types = g_list_prepend(status_types, type); - type = purple_status_type_new_full(PURPLE_STATUS_INVISIBLE, + type = purple_status_type_new_with_attrs(PURPLE_STATUS_INVISIBLE, OSCAR_STATUS_ID_INVISIBLE, - NULL, TRUE, TRUE, FALSE); + NULL, TRUE, TRUE, FALSE, + "message", _("Message"), + purple_value_new(PURPLE_TYPE_STRING), NULL); + status_types = g_list_prepend(status_types, type); type = purple_status_type_new_full(PURPLE_STATUS_MOBILE, OSCAR_STATUS_ID_MOBILE, NULL, FALSE, FALSE, TRUE); @@ -6306,9 +6475,14 @@ NULL, TRUE, TRUE, FALSE); status_types = g_list_prepend(status_types, type); - status_types = g_list_reverse(status_types); - - return status_types; + type = purple_status_type_new_with_attrs(PURPLE_STATUS_MOOD, + "mood", NULL, TRUE, is_icq, TRUE, + PURPLE_MOOD_NAME, _("Mood Name"), purple_value_new(PURPLE_TYPE_STRING), + PURPLE_MOOD_COMMENT, _("Mood Comment"), purple_value_new(PURPLE_TYPE_STRING), + NULL); + status_types = g_list_prepend(status_types, type); + + return g_list_reverse(status_types); } static void oscar_ssi_editcomment(struct name_data *data, const char *text) { @@ -6480,6 +6654,23 @@ } } +static void oscar_get_icqxstatusmsg (PurpleBlistNode *node, gpointer ignore) +{ + PurpleBuddy *buddy; + PurpleConnection *gc; + PurpleAccount *account; + + + g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node)); + + buddy = (PurpleBuddy *)node; + gc = purple_account_get_connection(buddy->account); + account = purple_connection_get_account(gc); + purple_debug_info("oscar", "Manual X-Status Get From %s to %s:\n", purple_buddy_get_name(buddy), account->username); + + icq_im_xstatus_request(gc->proto_data, purple_buddy_get_name(buddy)); +} + static void oscar_get_aim_info_cb(PurpleBlistNode *node, gpointer ignore) { @@ -6529,15 +6720,13 @@ menu = g_list_prepend(menu, act); } -#if 0 if (od->icq) { - act = purple_menu_action_new(_("Get Status Msg"), - PURPLE_CALLBACK(oscar_get_icqstatusmsg), + act = purple_menu_action_new(_("Get X-Status Msg"), + PURPLE_CALLBACK(oscar_get_icqxstatusmsg), NULL, NULL); menu = g_list_prepend(menu, act); } -#endif if (userinfo && oscar_util_name_compare(purple_account_get_username(account), bname) && diff -r 221cebbc35d8 -r 6d3a90b49dba libpurple/protocols/oscar/oscar.h --- a/libpurple/protocols/oscar/oscar.h Thu Feb 18 22:28:41 2010 +0000 +++ b/libpurple/protocols/oscar/oscar.h Sun Feb 28 04:07:39 2010 +0000 @@ -375,8 +375,12 @@ OSCAR_CAPABILITY_CAMERA = 0x04000000, OSCAR_CAPABILITY_ICHAT_SCREENSHARE = 0x08000000, OSCAR_CAPABILITY_TYPING = 0x10000000, - OSCAR_CAPABILITY_GENERICUNKNOWN = 0x20000000, - OSCAR_CAPABILITY_LAST = 0x40000000 + OSCAR_CAPABILITY_NEWCAPS = 0x20000000, + OSCAR_CAPABILITY_XTRAZ = 0x40000000, + OSCAR_CAPABILITY_GENERICUNKNOWN = 0x80000000, +#warning Fix OSCAR_CAPABILITY_LAST situation + // TODO: We're out of bits. Rework things that depend on this or remove some capability. (Or, ensure this is a 64-bit type.) + OSCAR_CAPABILITY_LAST = 0x100000000 } OscarCapability; /* @@ -572,6 +576,12 @@ #define AIM_ICQ_STATE_BUSY 0x00000010 #define AIM_ICQ_STATE_CHAT 0x00000020 #define AIM_ICQ_STATE_INVISIBLE 0x00000100 +#define AIM_ICQ_STATE_EVIL 0x00003000 +#define AIM_ICQ_STATE_DEPRESSION 0x00004000 +#define AIM_ICQ_STATE_ATHOME 0x00005000 +#define AIM_ICQ_STATE_ATWORK 0x00006000 +#define AIM_ICQ_STATE_LUNCH 0x00002001 +#define AIM_ICQ_STATE_EVIL 0x00003000 #define AIM_ICQ_STATE_WEBAWARE 0x00010000 #define AIM_ICQ_STATE_HIDEIP 0x00020000 #define AIM_ICQ_STATE_BIRTHDAY 0x00080000 @@ -1012,7 +1022,8 @@ /* 0x0008 */ int aim_im_warn(OscarData *od, FlapConnection *conn, const char *destbn, guint32 flags); /* 0x000b */ int aim_im_denytransfer(OscarData *od, const char *bn, const guchar *cookie, guint16 code); /* 0x0010 */ int aim_im_reqofflinemsgs(OscarData *od); -/* 0x0014 */ int aim_im_sendmtn(OscarData *od, guint16 channel, const char *bn, guint16 event); +/* 0x0014 */ int aim_im_sendmtn(OscarData *od, guint16 type1, const char *bn, guint16 type2); +/* 0x000b */ int icq_relay_xstatus (OscarData *od, const char *sn, const guchar* cookie); void aim_icbm_makecookie(guchar* cookie); gchar *oscar_encoding_extract(const char *encoding); gchar *oscar_encoding_to_utf8(PurpleAccount *account, const char *encoding, const char *text, int textlen); @@ -1144,8 +1155,10 @@ void aim_info_free(aim_userinfo_t *); int aim_info_extract(OscarData *od, ByteStream *bs, aim_userinfo_t *); int aim_putuserinfo(ByteStream *bs, aim_userinfo_t *info); - - +PurpleMood* icq_get_purple_moods(PurpleAccount *account); +const char* icq_get_custom_icon_description(const char *mood); +guint8* icq_get_custom_icon_data(const char *mood); +int icq_im_xstatus_request(OscarData *od, const char *sn); /* 0x0003 - family_buddy.c */ /* 0x0002 */ void aim_buddylist_reqrights(OscarData *, FlapConnection *); @@ -1474,7 +1487,7 @@ int aim_tlvlist_add_16(GSList **list, const guint16 type, const guint16 value); int aim_tlvlist_add_32(GSList **list, const guint16 type, const guint32 value); int aim_tlvlist_add_str(GSList **list, const guint16 type, const char *value); -int aim_tlvlist_add_caps(GSList **list, const guint16 type, const guint32 caps); +int aim_tlvlist_add_caps(GSList **list, const guint16 type, const guint32 caps, const char *mood); int aim_tlvlist_add_userinfo(GSList **list, guint16 type, aim_userinfo_t *userinfo); int aim_tlvlist_add_chatroom(GSList **list, guint16 type, guint16 exchange, const char *roomname, guint16 instance); int aim_tlvlist_add_frozentlvlist(GSList **list, guint16 type, GSList **tl); diff -r 221cebbc35d8 -r 6d3a90b49dba libpurple/protocols/oscar/oscarcommon.h --- a/libpurple/protocols/oscar/oscarcommon.h Thu Feb 18 22:28:41 2010 +0000 +++ b/libpurple/protocols/oscar/oscarcommon.h Sun Feb 28 04:07:39 2010 +0000 @@ -30,6 +30,7 @@ #include "prpl.h" #include "version.h" #include "notify.h" +#include "status.h" #define OSCAR_DEFAULT_LOGIN_SERVER "login.messaging.aol.com" #define OSCAR_DEFAULT_LOGIN_PORT 5190 @@ -51,6 +52,7 @@ #ifdef _WIN32 const char *oscar_get_locale_charset(void); #endif +PurpleMood* oscar_get_purple_moods(PurpleAccount *account); const char *oscar_list_icon_icq(PurpleAccount *a, PurpleBuddy *b); const char *oscar_list_icon_aim(PurpleAccount *a, PurpleBuddy *b); const char* oscar_list_emblem(PurpleBuddy *b); diff -r 221cebbc35d8 -r 6d3a90b49dba libpurple/protocols/oscar/tlv.c --- a/libpurple/protocols/oscar/tlv.c Thu Feb 18 22:28:41 2010 +0000 +++ b/libpurple/protocols/oscar/tlv.c Sun Feb 28 04:07:39 2010 +0000 @@ -407,10 +407,11 @@ * @param caps Bitfield of capability flags to send * @return The size of the value added. */ -int aim_tlvlist_add_caps(GSList **list, const guint16 type, const guint32 caps) +int aim_tlvlist_add_caps(GSList **list, const guint16 type, const guint32 caps, const char *mood) { guint8 buf[256]; /* TODO: Don't use a fixed length buffer */ ByteStream bs; + guint8 *data; if (caps == 0) return 0; /* nothing there anyway */ @@ -418,6 +419,11 @@ byte_stream_init(&bs, buf, sizeof(buf)); byte_stream_putcaps(&bs, caps); + + /* adding of custom icon GUID */ + data = icq_get_custom_icon_data(mood); + if (data != NULL) + byte_stream_putraw(&bs, data, 16); return aim_tlvlist_add_raw(list, type, byte_stream_curpos(&bs), buf); } diff -r 221cebbc35d8 -r 6d3a90b49dba libpurple/protocols/qq/qq.c --- a/libpurple/protocols/qq/qq.c Thu Feb 18 22:28:41 2010 +0000 +++ b/libpurple/protocols/qq/qq.c Sun Feb 28 04:07:39 2010 +0000 @@ -1037,7 +1037,8 @@ sizeof(PurplePluginProtocolInfo), /* struct_size */ NULL, /* get_account_text_table */ NULL, /* initiate_media */ - NULL /* can_do_media */ + NULL, /* get_media_caps */ + NULL /* get_moods */ }; static PurplePluginInfo info = { diff -r 221cebbc35d8 -r 6d3a90b49dba libpurple/protocols/sametime/sametime.c --- a/libpurple/protocols/sametime/sametime.c Thu Feb 18 22:28:41 2010 +0000 +++ b/libpurple/protocols/sametime/sametime.c Sun Feb 28 04:07:39 2010 +0000 @@ -3527,10 +3527,10 @@ purple_request_field_list_set_multi_select(f, FALSE); for(; confs; confs = confs->next) { struct mwConference *c = confs->data; - purple_request_field_list_add(f, mwConference_getTitle(c), c); + purple_request_field_list_add_icon(f, mwConference_getTitle(c), NULL, c); } - purple_request_field_list_add(f, _("Create New Conference..."), - GINT_TO_POINTER(0x01)); + purple_request_field_list_add_icon(f, _("Create New Conference..."), + NULL, GINT_TO_POINTER(0x01)); purple_request_field_group_add_field(g, f); f = purple_request_field_string_new(CHAT_KEY_INVITE, "Message", NULL, FALSE); @@ -5458,7 +5458,7 @@ res->id = g_strdup(match->id); res->name = g_strdup(match->name); - purple_request_field_list_add(f, res->name, res); + purple_request_field_list_add_icon(f, res->name, NULL, res); } purple_request_field_group_add_field(g, f); diff -r 221cebbc35d8 -r 6d3a90b49dba libpurple/protocols/silc/buddy.c --- a/libpurple/protocols/silc/buddy.c Thu Feb 18 22:28:41 2010 +0000 +++ b/libpurple/protocols/silc/buddy.c Sun Feb 28 04:07:39 2010 +0000 @@ -1183,7 +1183,7 @@ client_entry->username, *client_entry->hostname ? client_entry->hostname : "", fingerprint ? tmp2 : ""); - purple_request_field_list_add(f, tmp, client_entry); + purple_request_field_list_add_icon(f, tmp, NULL, client_entry); silc_free(fingerprint); } diff -r 221cebbc35d8 -r 6d3a90b49dba libpurple/protocols/silc/chat.c --- a/libpurple/protocols/silc/chat.c Thu Feb 18 22:28:41 2010 +0000 +++ b/libpurple/protocols/silc/chat.c Sun Feb 28 04:07:39 2010 +0000 @@ -475,7 +475,7 @@ g_snprintf(tmp2, sizeof(tmp2), "%s\n %s\n %s", ident->realname ? ident->realname : ident->username ? ident->username : "", fingerprint, babbleprint); - purple_request_field_list_add(f, tmp2, public_key); + purple_request_field_list_add_icon(f, tmp2, NULL, public_key); silc_free(fingerprint); silc_free(babbleprint); diff -r 221cebbc35d8 -r 6d3a90b49dba libpurple/protocols/silc/silc.c --- a/libpurple/protocols/silc/silc.c Thu Feb 18 22:28:41 2010 +0000 +++ b/libpurple/protocols/silc/silc.c Sun Feb 28 04:07:39 2010 +0000 @@ -2116,7 +2116,8 @@ sizeof(PurplePluginProtocolInfo), /* struct_size */ NULL, /* get_account_text_table */ NULL, /* initiate_media */ - NULL /* can_do_media */ + NULL, /* get_media_caps */ + NULL /* get_moods */ }; static PurplePluginInfo info = diff -r 221cebbc35d8 -r 6d3a90b49dba libpurple/protocols/silc10/buddy.c --- a/libpurple/protocols/silc10/buddy.c Thu Feb 18 22:28:41 2010 +0000 +++ b/libpurple/protocols/silc10/buddy.c Sun Feb 28 04:07:39 2010 +0000 @@ -1176,7 +1176,7 @@ clients[i]->username, clients[i]->hostname ? clients[i]->hostname : "", fingerprint ? tmp2 : ""); - purple_request_field_list_add(f, tmp, clients[i]); + purple_request_field_list_add_icon(f, tmp, NULL, clients[i]); silc_free(fingerprint); } diff -r 221cebbc35d8 -r 6d3a90b49dba libpurple/protocols/silc10/chat.c --- a/libpurple/protocols/silc10/chat.c Thu Feb 18 22:28:41 2010 +0000 +++ b/libpurple/protocols/silc10/chat.c Sun Feb 28 04:07:39 2010 +0000 @@ -449,7 +449,7 @@ g_snprintf(tmp2, sizeof(tmp2), "%s\n %s\n %s", ident->realname ? ident->realname : ident->username ? ident->username : "", fingerprint, babbleprint); - purple_request_field_list_add(f, tmp2, pubkey); + purple_request_field_list_add_icon(f, tmp2, NULL, pubkey); silc_free(fingerprint); silc_free(babbleprint); diff -r 221cebbc35d8 -r 6d3a90b49dba libpurple/protocols/simple/simple.c --- a/libpurple/protocols/simple/simple.c Thu Feb 18 22:28:41 2010 +0000 +++ b/libpurple/protocols/simple/simple.c Sun Feb 28 04:07:39 2010 +0000 @@ -2086,7 +2086,8 @@ sizeof(PurplePluginProtocolInfo), /* struct_size */ NULL, /* get_account_text_table */ NULL, /* initiate_media */ - NULL /* can_do_media */ + NULL, /* get_media_caps */ + NULL /* get_moods */ }; diff -r 221cebbc35d8 -r 6d3a90b49dba libpurple/protocols/yahoo/libyahoo.c --- a/libpurple/protocols/yahoo/libyahoo.c Thu Feb 18 22:28:41 2010 +0000 +++ b/libpurple/protocols/yahoo/libyahoo.c Sun Feb 28 04:07:39 2010 +0000 @@ -264,7 +264,8 @@ sizeof(PurplePluginProtocolInfo), /* struct_size */ yahoo_get_account_text_table, /* get_account_text_table */ NULL, /* initiate_media */ - NULL /* can_do_media */ + NULL, /* get_media_caps */ + NULL /* get_moods */ }; static PurplePluginInfo info = diff -r 221cebbc35d8 -r 6d3a90b49dba libpurple/protocols/yahoo/libyahoojp.c --- a/libpurple/protocols/yahoo/libyahoojp.c Thu Feb 18 22:28:41 2010 +0000 +++ b/libpurple/protocols/yahoo/libyahoojp.c Sun Feb 28 04:07:39 2010 +0000 @@ -160,7 +160,8 @@ sizeof(PurplePluginProtocolInfo), /* struct_size */ yahoojp_get_account_text_table, /* get_account_text_table */ NULL, /* initiate_media */ - NULL /* can_do_media */ + NULL, /* get_media_caps */ + NULL /* get_moods */ }; static PurplePluginInfo info = diff -r 221cebbc35d8 -r 6d3a90b49dba libpurple/protocols/zephyr/zephyr.c --- a/libpurple/protocols/zephyr/zephyr.c Thu Feb 18 22:28:41 2010 +0000 +++ b/libpurple/protocols/zephyr/zephyr.c Sun Feb 28 04:07:39 2010 +0000 @@ -2908,7 +2908,8 @@ sizeof(PurplePluginProtocolInfo), /* struct_size */ NULL, /* get_account_text_table */ NULL, /* initate_media */ - NULL /* can_do_media */ + NULL, /* get_media_caps */ + NULL /* get_moods */ }; static PurplePluginInfo info = { diff -r 221cebbc35d8 -r 6d3a90b49dba libpurple/prpl.h --- a/libpurple/prpl.h Thu Feb 18 22:28:41 2010 +0000 +++ b/libpurple/prpl.h Sun Feb 28 04:07:39 2010 +0000 @@ -569,6 +569,12 @@ */ PurpleMediaCaps (*get_media_caps)(PurpleAccount *account, const char *who); + + /** + * Returns an array of "PurpleMood"s, with the last one having + * "mood" set to @c NULL. + */ + PurpleMood *(*get_moods)(PurpleAccount *account); }; #define PURPLE_PROTOCOL_PLUGIN_HAS_FUNC(prpl, member) \ diff -r 221cebbc35d8 -r 6d3a90b49dba libpurple/request.c --- a/libpurple/request.c Thu Feb 18 22:28:41 2010 +0000 +++ b/libpurple/request.c Sun Feb 28 04:07:39 2010 +0000 @@ -850,13 +850,40 @@ purple_request_field_list_add(PurpleRequestField *field, const char *item, void *data) { + purple_request_field_list_add_icon(field, item, NULL, data); +} + +void +purple_request_field_list_add_icon(PurpleRequestField *field, const char *item, const char* icon_path, + void *data) +{ g_return_if_fail(field != NULL); g_return_if_fail(item != NULL); g_return_if_fail(data != NULL); g_return_if_fail(field->type == PURPLE_REQUEST_FIELD_LIST); + if (icon_path) + { + if (field->u.list.icons == NULL) + { + GList *l; + for (l = field->u.list.items ; l != NULL ; l = l->next) + { + /* Order doesn't matter, because we're just + * filing in blank items. So, we use + * g_list_prepend() because it's faster. */ + field->u.list.icons = g_list_prepend(field->u.list.icons, NULL); + } + } + field->u.list.icons = g_list_append(field->u.list.icons, g_strdup(icon_path)); + } + else if (field->u.list.icons) + { + /* Keep this even with the items list. */ + field->u.list.icons = g_list_append(field->u.list.icons, NULL); + } + field->u.list.items = g_list_append(field->u.list.items, g_strdup(item)); - g_hash_table_insert(field->u.list.item_data, g_strdup(item), data); } @@ -962,6 +989,15 @@ return field->u.list.items; } +GList * +purple_request_field_list_get_icons(const PurpleRequestField *field) +{ + g_return_val_if_fail(field != NULL, NULL); + g_return_val_if_fail(field->type == PURPLE_REQUEST_FIELD_LIST, NULL); + + return field->u.list.icons; +} + PurpleRequestField * purple_request_field_label_new(const char *id, const char *text) { diff -r 221cebbc35d8 -r 6d3a90b49dba libpurple/request.h --- a/libpurple/request.h Thu Feb 18 22:28:41 2010 +0000 +++ b/libpurple/request.h Sun Feb 28 04:07:39 2010 +0000 @@ -150,6 +150,7 @@ struct { GList *items; + GList *icons; GHashTable *item_data; GList *selected; GHashTable *selected_table; @@ -961,11 +962,24 @@ * @param field The list field. * @param item The list item. * @param data The associated data. + * + * @deprecated Use purple_request_field_list_add_icon() instead. */ void purple_request_field_list_add(PurpleRequestField *field, const char *item, void *data); /** + * Adds an item to a list field. + * + * @param field The list field. + * @param item The list item. + * @param icon_path The path to icon file, or @c NULL for no icon. + * @param data The associated data. + */ +void purple_request_field_list_add_icon(PurpleRequestField *field, + const char *item, const char* icon_path, void* data); + +/** * Adds a selected item to the list field. * * @param field The field. @@ -1023,6 +1037,18 @@ */ GList *purple_request_field_list_get_items(const PurpleRequestField *field); +/** + * Returns a list of icons in a list field. + * + * The icons will correspond with the items, in order. + * + * @param field The field. + * + * @constreturn The list of icons or @c NULL (i.e. the empty GList) if no + * items have icons. + */ +GList *purple_request_field_list_get_icons(const PurpleRequestField *field); + /*@}*/ /**************************************************************************/ diff -r 221cebbc35d8 -r 6d3a90b49dba libpurple/status.c --- a/libpurple/status.c Thu Feb 18 22:28:41 2010 +0000 +++ b/libpurple/status.c Sun Feb 28 04:07:39 2010 +0000 @@ -137,6 +137,7 @@ -200, /* extended away */ -400, /* mobile */ 0, /* tune */ + 0, /* mood */ -10, /* idle, special case. */ -5, /* idle time, special case. */ 10 /* Offline messageable */ @@ -157,15 +158,16 @@ } const status_primitive_map[] = { - { PURPLE_STATUS_UNSET, "unset", N_("Unset") }, - { PURPLE_STATUS_OFFLINE, "offline", N_("Offline") }, - { PURPLE_STATUS_AVAILABLE, "available", N_("Available") }, - { PURPLE_STATUS_UNAVAILABLE, "unavailable", N_("Do not disturb") }, - { PURPLE_STATUS_INVISIBLE, "invisible", N_("Invisible") }, - { PURPLE_STATUS_AWAY, "away", N_("Away") }, - { PURPLE_STATUS_EXTENDED_AWAY, "extended_away", N_("Extended away") }, - { PURPLE_STATUS_MOBILE, "mobile", N_("Mobile") }, - { PURPLE_STATUS_TUNE, "tune", N_("Listening to music") } + { PURPLE_STATUS_UNSET, "unset", N_("Unset") }, + { PURPLE_STATUS_OFFLINE, "offline", N_("Offline") }, + { PURPLE_STATUS_AVAILABLE, "available", N_("Available") }, + { PURPLE_STATUS_UNAVAILABLE, "unavailable", N_("Do not disturb") }, + { PURPLE_STATUS_INVISIBLE, "invisible", N_("Invisible") }, + { PURPLE_STATUS_AWAY, "away", N_("Away") }, + { PURPLE_STATUS_EXTENDED_AWAY, "extended_away", N_("Extended away") }, + { PURPLE_STATUS_MOBILE, "mobile", N_("Mobile") }, + { PURPLE_STATUS_TUNE, "tune", N_("Listening to music"), }, + { PURPLE_STATUS_MOOD, "mood", N_("Feeling") }, }; const char * diff -r 221cebbc35d8 -r 6d3a90b49dba libpurple/status.h --- a/libpurple/status.h Thu Feb 18 22:28:41 2010 +0000 +++ b/libpurple/status.h Sun Feb 28 04:07:39 2010 +0000 @@ -87,6 +87,12 @@ typedef struct _PurplePresence PurplePresence; typedef struct _PurpleStatus PurpleStatus; +typedef struct _PurpleMood { + const char *mood; + const char *description; + gpointer *padding; +} PurpleMood; + /** * A context for a presence. * @@ -106,8 +112,7 @@ */ /* * If you add a value to this enum, make sure you update - * the status_primitive_map array in status.c and the special-cases for idle - * and offline-messagable just below it. + * the status_primitive_map and primitive_scores arrays in status.c. */ typedef enum { @@ -120,6 +125,7 @@ PURPLE_STATUS_EXTENDED_AWAY, PURPLE_STATUS_MOBILE, PURPLE_STATUS_TUNE, + PURPLE_STATUS_MOOD, PURPLE_STATUS_NUM_PRIMITIVES } PurpleStatusPrimitive; @@ -139,6 +145,9 @@ #define PURPLE_TUNE_URL "tune_url" #define PURPLE_TUNE_FULL "tune_full" +#define PURPLE_MOOD_NAME "mood" +#define PURPLE_MOOD_COMMENT "moodtext" + #ifdef __cplusplus extern "C" { #endif diff -r 221cebbc35d8 -r 6d3a90b49dba libpurple/win32/global.mak --- a/libpurple/win32/global.mak Thu Feb 18 22:28:41 2010 +0000 +++ b/libpurple/win32/global.mak Sun Feb 28 04:07:39 2010 +0000 @@ -15,7 +15,7 @@ GTK_TOP ?= $(WIN32_DEV_TOP)/gtk_2_0-2.14 GTK_BIN ?= $(GTK_TOP)/bin BONJOUR_TOP ?= $(WIN32_DEV_TOP)/Bonjour_SDK -LIBXML2_TOP ?= $(WIN32_DEV_TOP)/libxml2-2.6.30 +LIBXML2_TOP ?= $(WIN32_DEV_TOP)/libxml2-2.7.4 MEANWHILE_TOP ?= $(WIN32_DEV_TOP)/meanwhile-1.0.2_daa2 NSPR_TOP ?= $(WIN32_DEV_TOP)/nspr-4.6.4 NSS_TOP ?= $(WIN32_DEV_TOP)/nss-3.11.4 diff -r 221cebbc35d8 -r 6d3a90b49dba libpurple/win32/libc_interface.c --- a/libpurple/win32/libc_interface.c Thu Feb 18 22:28:41 2010 +0000 +++ b/libpurple/win32/libc_interface.c Sun Feb 28 04:07:39 2010 +0000 @@ -33,6 +33,7 @@ #include "libc_internal.h" #include +/** This is redefined here because we can't include internal.h */ #ifdef ENABLE_NLS # include # include @@ -1047,29 +1048,12 @@ return ""; } +int wpurple_g_access (const gchar *filename, int mode); /** - * g_access: - * @filename: a pathname in the GLib file name encoding (UTF-8 on Windows) - * @mode: as in access() - * - * A wrapper for the POSIX access() function. This function is used to - * test a pathname for one or several of read, write or execute - * permissions, or just existence. On Windows, the underlying access() - * function in the C library only checks the READONLY attribute, and - * does not look at the ACL at all. Software that needs to handle file - * permissions on Windows more exactly should use the Win32 API. - * - * See the C library manual for more details about access(). - * - * Returns: zero if the pathname refers to an existing file system - * object that has all the tested permissions, or -1 otherwise or on - * error. - * - * Since: 2.8 + * @deprecated - remove for 3.0.0 */ int -wpurple_g_access (const gchar *filename, - int mode) +wpurple_g_access (const gchar *filename, int mode) { return g_access(filename, mode); } diff -r 221cebbc35d8 -r 6d3a90b49dba libpurple/win32/libc_interface.h --- a/libpurple/win32/libc_interface.h Thu Feb 18 22:28:41 2010 +0000 +++ b/libpurple/win32/libc_interface.h Sun Feb 28 04:07:39 2010 +0000 @@ -129,19 +129,14 @@ wpurple_gettimeofday( timeval, timezone ) /* stdio.h */ +#undef snprintf #define snprintf _snprintf +#undef vsnprintf #define vsnprintf _vsnprintf #define rename( oldname, newname ) \ wpurple_rename( oldname, newname ) -#ifdef g_rename -# undef g_rename -#endif -/* This is necessary because we want rename on win32 to be able to overwrite an existing file, it is done in internal.h if GLib < 2.6*/ -#define g_rename(oldname, newname) \ -wpurple_rename(oldname, newname) - /* sys/stat.h */ #define fchmod(a,b) diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/Makefile.am --- a/pidgin/Makefile.am Thu Feb 18 22:28:41 2010 +0000 +++ b/pidgin/Makefile.am Sun Feb 28 04:07:39 2010 +0000 @@ -89,7 +89,6 @@ gtkdnd-hints.c \ gtkdocklet.c \ gtkdocklet-gtk.c \ - gtkdocklet-x11.c \ gtkeventloop.c \ gtkft.c \ gtkicon-theme.c \ diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/gtkblist.c --- a/pidgin/gtkblist.c Thu Feb 18 22:28:41 2010 +0000 +++ b/pidgin/gtkblist.c Sun Feb 28 04:07:39 2010 +0000 @@ -2660,39 +2660,30 @@ /* Altered from do_colorshift in gnome-panel */ static void -do_alphashift (GdkPixbuf *dest, GdkPixbuf *src, int shift) +do_alphashift(GdkPixbuf *pixbuf, int shift) { gint i, j; - gint width, height, has_alpha, srcrowstride, destrowstride; - guchar *target_pixels; - guchar *original_pixels; - guchar *pixsrc; - guchar *pixdest; + gint width, height, padding; + guchar *pixels; int val; - guchar a; - - has_alpha = gdk_pixbuf_get_has_alpha (src); - if (!has_alpha) + + if (!gdk_pixbuf_get_has_alpha(pixbuf)) return; - width = gdk_pixbuf_get_width (src); - height = gdk_pixbuf_get_height (src); - srcrowstride = gdk_pixbuf_get_rowstride (src); - destrowstride = gdk_pixbuf_get_rowstride (dest); - target_pixels = gdk_pixbuf_get_pixels (dest); - original_pixels = gdk_pixbuf_get_pixels (src); + width = gdk_pixbuf_get_width(pixbuf); + height = gdk_pixbuf_get_height(pixbuf); + padding = gdk_pixbuf_get_rowstride(pixbuf) - width * 4; + pixels = gdk_pixbuf_get_pixels(pixbuf); for (i = 0; i < height; i++) { - pixdest = target_pixels + i*destrowstride; - pixsrc = original_pixels + i*srcrowstride; for (j = 0; j < width; j++) { - *(pixdest++) = *(pixsrc++); - *(pixdest++) = *(pixsrc++); - *(pixdest++) = *(pixsrc++); - a = *(pixsrc++); - val = a - shift; - *(pixdest++) = CLAMP(val, 0, 255); - } + pixels++; + pixels++; + pixels++; + val = *pixels - shift; + *(pixels++) = CLAMP(val, 0, 255); + } + pixels += padding; } } @@ -3667,7 +3658,8 @@ /* Offline? */ - /* FIXME: Why is this status special-cased by the core? -- rlaager */ + /* FIXME: Why is this status special-cased by the core? --rlaager + * FIXME: Alternatively, why not have the core do all of them? --rlaager */ if (!PURPLE_BUDDY_IS_ONLINE(b)) { purple_notify_user_info_add_pair(user_info, _("Status"), _("Offline")); } @@ -3762,6 +3754,24 @@ return pb; } +static char *get_mood_icon_path(const char *mood) +{ + char *path; + + if (!strcmp(mood, "busy")) { + path = g_build_filename(DATADIR, "pixmaps", "pidgin", + "status", "16", "busy.png", NULL); + } else if (!strcmp(mood, "hiptop")) { + path = g_build_filename(DATADIR, "pixmaps", "pidgin", + "emblems", "16", "hiptop.png", NULL); + } else { + char *filename = g_strdup_printf("%s.png", mood); + path = g_build_filename(DATADIR, "pixmaps", "pidgin", + "emotes", "small", filename, NULL); + g_free(filename); + } + return path; +} GdkPixbuf * pidgin_blist_get_emblem(PurpleBlistNode *node) @@ -3773,7 +3783,7 @@ PurplePluginProtocolInfo *prpl_info; const char *name = NULL; char *filename, *path; - PurplePresence *p; + PurplePresence *p = NULL; PurpleStatus *tune; if(PURPLE_BLIST_NODE_IS_CONTACT(node)) { @@ -3786,14 +3796,17 @@ gtkbuddynode = node->ui_data; p = purple_buddy_get_presence(buddy); if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_MOBILE)) { - path = g_build_filename(DATADIR, "pixmaps", "pidgin", "emblems", - "16", "mobile.png", NULL); + /* This emblem comes from the small emoticon set now, + * to reduce duplication. */ + path = g_build_filename(DATADIR, "pixmaps", "pidgin", "emotes", + "small", "mobile.png", NULL); return _pidgin_blist_get_cached_emblem(path); } if (((struct _pidgin_blist_node*)(node->parent->ui_data))->contact_expanded) { - if (!purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/show_protocol_icons")) - return pidgin_create_prpl_icon(((PurpleBuddy*)node)->account, PIDGIN_PRPL_ICON_SMALL); + if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/show_protocol_icons")) + return NULL; + return pidgin_create_prpl_icon(((PurpleBuddy*)node)->account, PIDGIN_PRPL_ICON_SMALL); } } else { return NULL; @@ -3806,9 +3819,14 @@ return _pidgin_blist_get_cached_emblem(path); } - p = purple_buddy_get_presence(buddy); + /* If we came through the contact code flow above, we didn't need + * to get the presence until now. */ + if (p == NULL) + p = purple_buddy_get_presence(buddy); + if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_MOBILE)) { - path = g_build_filename(DATADIR, "pixmaps", "pidgin", "emblems", "16", "mobile.png", NULL); + /* This emblem comes from the small emoticon set now, to reduce duplication. */ + path = g_build_filename(DATADIR, "pixmaps", "pidgin", "emotes", "small", "mobile.png", NULL); return _pidgin_blist_get_cached_emblem(path); } @@ -3827,7 +3845,8 @@ return _pidgin_blist_get_cached_emblem(path); } /* Regular old "tune" is the only one in all protocols. */ - path = g_build_filename(DATADIR, "pixmaps", "pidgin", "emblems", "16", "music.png", NULL); + /* This emblem comes from the small emoticon set now, to reduce duplication. */ + path = g_build_filename(DATADIR, "pixmaps", "pidgin", "emotes", "small", "music.png", NULL); return _pidgin_blist_get_cached_emblem(path); } @@ -3839,13 +3858,24 @@ if (prpl_info && prpl_info->list_emblem) name = prpl_info->list_emblem(buddy); - if (name == NULL) - return NULL; - - filename = g_strdup_printf("%s.png", name); - - path = g_build_filename(DATADIR, "pixmaps", "pidgin", "emblems", "16", filename, NULL); - g_free(filename); + if (name == NULL) { + PurpleStatus *status; + + if (!purple_presence_is_status_primitive_active(p, PURPLE_STATUS_MOOD)) + return NULL; + + status = purple_presence_get_status(p, "mood"); + name = purple_status_get_attr_string(status, PURPLE_MOOD_NAME); + + if (!(name && *name)) + return NULL; + + path = get_mood_icon_path(name); + } else { + filename = g_strdup_printf("%s.png", name); + path = g_build_filename(DATADIR, "pixmaps", "pidgin", "emblems", "16", filename, NULL); + g_free(filename); + } /* _pidgin_blist_get_cached_emblem() assumes ownership of path */ return _pidgin_blist_get_cached_emblem(path); @@ -6328,7 +6358,7 @@ g_object_ref(G_OBJECT(gtkblist->empty_avatar)); avatar = gtkblist->empty_avatar; } else if ((!PURPLE_BUDDY_IS_ONLINE(buddy) || purple_presence_is_idle(presence))) { - do_alphashift(avatar, avatar, 77); + do_alphashift(avatar, 77); } emblem = pidgin_blist_get_emblem((PurpleBlistNode*) buddy); @@ -7785,6 +7815,93 @@ purple_account_set_enabled(account, PIDGIN_UI, FALSE); } +static void +edit_mood_cb(PurpleConnection *gc, PurpleRequestFields *fields) +{ + PurpleRequestField *f; + GList *l; + + f = purple_request_fields_get_field(fields, "mood"); + l = purple_request_field_list_get_selected(f); + + if (l) { + const char *mood = purple_request_field_list_get_data(f, l->data); + PurpleAccount *account = purple_connection_get_account(gc); + + if (mood != NULL && !purple_strequal(mood, "")) { + purple_account_set_status(account, "mood", TRUE, + PURPLE_MOOD_NAME, mood, + NULL); + } else { + purple_account_set_status(account, "mood", FALSE, NULL); + } + } +} + +static void +set_mood_cb(GtkWidget *widget, PurpleAccount *account) +{ + PurplePresence *presence = purple_account_get_presence(account); + PurpleStatus *status = purple_presence_get_status(presence, "mood"); + const char *current_mood; + PurpleRequestFields *fields; + PurpleRequestFieldGroup *g; + PurpleRequestField *f; + char* na_fn; + PurpleConnection *gc = purple_account_get_connection(account); + PurplePluginProtocolInfo *prpl_info; + PurpleMood *mood; + + g_return_if_fail(gc->prpl != NULL); + prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl); + + current_mood = purple_status_get_attr_string(status, PURPLE_MOOD_NAME); + + fields = purple_request_fields_new(); + g = purple_request_field_group_new(NULL); + f = purple_request_field_list_new("mood", _("Please select your mood from the list")); + + na_fn = g_build_filename("pixmaps", "pidgin", "emblems", "16", "not-authorized.png", NULL); + + purple_request_field_list_add_icon(f, _("None"), na_fn, NULL); + if (current_mood == NULL) + purple_request_field_list_add_selected(f, _("None")); + + g_free(na_fn); + + /* first item is an empty one for unsetting the mood */ + purple_request_field_list_add(f, "", ""); + if (purple_strequal(current_mood, "")) + purple_request_field_list_add_selected(f, ""); + + /* TODO: rlaager wants this sorted. */ + for (mood = prpl_info->get_moods(account); + mood->mood != NULL ; mood++) { + char *path; + + if (mood->mood == NULL || mood->description == NULL) + continue; + + path = get_mood_icon_path(mood->mood); + purple_request_field_list_add_icon(f, _(mood->description), + path, (gpointer)mood->mood); + g_free(path); + + if (current_mood && !strcmp(current_mood, mood->mood)) + purple_request_field_list_add_selected(f, _(mood->description)); + } + purple_request_field_group_add_field(g, f); + + purple_request_fields_add_group(fields, g); + + purple_request_fields(gc, _("Edit User Mood"), _("Edit User Mood"), + NULL, fields, + _("OK"), G_CALLBACK(edit_mood_cb), + _("Cancel"), NULL, + purple_connection_get_account(gc), + NULL, NULL, gc); +} + void pidgin_blist_update_accounts_menu(void) { @@ -7864,6 +7981,7 @@ PurpleAccount *account = NULL; GdkPixbuf *pixbuf = NULL; PurplePlugin *plugin = NULL; + PurplePluginProtocolInfo *prpl_info; account = accounts->data; @@ -7903,8 +8021,32 @@ gc = purple_account_get_connection(account); plugin = gc && PURPLE_CONNECTION_IS_CONNECTED(gc) ? gc->prpl : NULL; - if (plugin && PURPLE_PLUGIN_HAS_ACTIONS(plugin)) { - build_plugin_actions(submenu, plugin, gc); + prpl_info = plugin ? PURPLE_PLUGIN_PROTOCOL_INFO(plugin) : NULL; + + if (prpl_info && + (PURPLE_PROTOCOL_PLUGIN_HAS_FUNC(prpl_info, get_moods) || + PURPLE_PLUGIN_HAS_ACTIONS(plugin))) { + if (PURPLE_PROTOCOL_PLUGIN_HAS_FUNC(prpl_info, get_moods)) { + GList *types; + for (types = purple_account_get_status_types(account); + types != NULL ; types = types->next) { + PurpleStatusType *type = types->data; + + if (strcmp(purple_status_type_get_id(type), "mood") != 0) + continue; + + menuitem = gtk_menu_item_new_with_mnemonic(_("Set _Mood...")); + g_signal_connect(G_OBJECT(menuitem), "activate", + G_CALLBACK(set_mood_cb), account); + gtk_menu_shell_append(GTK_MENU_SHELL(submenu), menuitem); + + /* Be safe. It shouldn't match more than once anyway */ + break; + } + } + if (PURPLE_PLUGIN_HAS_ACTIONS(plugin)) { + build_plugin_actions(submenu, plugin, gc); + } } else { menuitem = gtk_menu_item_new_with_label(_("No actions available")); gtk_menu_shell_append(GTK_MENU_SHELL(submenu), menuitem); diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/gtkdebug.c --- a/pidgin/gtkdebug.c Thu Feb 18 22:28:41 2010 +0000 +++ b/pidgin/gtkdebug.c Sun Feb 28 04:07:39 2010 +0000 @@ -250,11 +250,11 @@ static void pause_cb(GtkWidget *w, DebugWindow *win) { - win->paused = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w)); + win->paused = gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(w)); #ifdef HAVE_REGEX_H if(!win->paused) { - if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(win->filter))) + if(gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(win->filter))) regex_filter_all(win); else regex_show_all(win); @@ -445,7 +445,7 @@ /* we check if the filter is on in case it was only of the options that * got changed, and not the expression. */ - if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(win->filter))) + if(gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(win->filter))) regex_filter_all(win); } @@ -459,9 +459,9 @@ if(!win || !win->window) return; - current = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(win->filter)); + current = gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(win->filter)); if(active != current) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(win->filter), active); + gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(win->filter), active); } static void @@ -483,7 +483,7 @@ win->invert = active; - if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(win->filter))) + if(gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(win->filter))) regex_filter_all(win); } @@ -496,7 +496,7 @@ win->highlight = active; - if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(win->filter))) + if(gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(win->filter))) regex_filter_all(win); } @@ -522,7 +522,7 @@ gtk_tree_model_get(model, iter, 0, &text, 1, &level, -1); if (level >= purple_prefs_get_int(PIDGIN_PREFS_ROOT "/debug/filterlevel")) { - if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(win->filter))) { + if(gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(win->filter))) { regex_match(win, text); } else { gtk_imhtml_append_text(GTK_IMHTML(win->text), text, 0); @@ -546,8 +546,8 @@ static void regex_changed_cb(GtkWidget *w, DebugWindow *win) { - if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(win->filter))) { - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(win->filter), + if(gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(win->filter))) { + gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(win->filter), FALSE); } @@ -561,9 +561,9 @@ regex_key_release_cb(GtkWidget *w, GdkEventKey *e, DebugWindow *win) { if(e->keyval == GDK_Return && GTK_WIDGET_IS_SENSITIVE(win->filter) && - !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(win->filter))) + !gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(win->filter))) { - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(win->filter), TRUE); + gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(win->filter), TRUE); } } @@ -588,10 +588,10 @@ } static void -regex_filter_toggled_cb(GtkToggleButton *button, DebugWindow *win) { +regex_filter_toggled_cb(GtkToggleToolButton *button, DebugWindow *win) { gboolean active; - active = gtk_toggle_button_get_active(button); + active = gtk_toggle_tool_button_get_active(button); purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/debug/filter", active); @@ -611,7 +611,7 @@ if (GPOINTER_TO_INT(value) != gtk_combo_box_get_active(GTK_COMBO_BOX(win->filterlevel))) gtk_combo_box_set_active(GTK_COMBO_BOX(win->filterlevel), GPOINTER_TO_INT(value)); - if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(win->filter))) + if(gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(win->filter))) regex_filter_all(win); else regex_show_all(win); @@ -677,9 +677,12 @@ GtkWidget *vbox; GtkWidget *toolbar; GtkWidget *frame; - GtkWidget *image; gint width, height; void *handle; + GtkToolItem *item; +#if !GTK_CHECK_VERSION(2,12,0) + GtkTooltips *tooltips; +#endif win = g_new0(DebugWindow, 1); @@ -720,7 +723,12 @@ if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/debug/toolbar")) { /* Setup our top button bar thingie. */ toolbar = gtk_toolbar_new(); +#if !GTK_CHECK_VERSION(2,12,0) + tooltips = gtk_tooltips_new(); +#endif +#if !GTK_CHECK_VERSION(2,14,0) gtk_toolbar_set_tooltips(GTK_TOOLBAR(toolbar), TRUE); +#endif gtk_toolbar_set_show_arrow(GTK_TOOLBAR(toolbar), TRUE); g_signal_connect(G_OBJECT(toolbar), "button-press-event", G_CALLBACK(toolbar_context), win); @@ -735,61 +743,93 @@ #ifndef HAVE_REGEX_H /* Find button */ - gtk_toolbar_insert_stock(GTK_TOOLBAR(toolbar), GTK_STOCK_FIND, - _("Find"), NULL, G_CALLBACK(find_cb), - win, -1); + item = gtk_tool_button_new_from_stock(GTK_STOCK_FIND); + gtk_tool_item_set_is_important(item, TRUE); +#if GTK_CHECK_VERSION(2,12,0) + gtk_tool_item_set_tooltip_text(item, _("Find")); +#else + gtk_tool_item_set_tooltip(item, tooltips, _("Find"), NULL); +#endif + g_signal_connect(G_OBJECT(item), "clicked", G_CALLBACK(find_cb), win); + gtk_container_add(GTK_CONTAINER(toolbar), GTK_WIDGET(item)); #endif /* HAVE_REGEX_H */ /* Save */ - gtk_toolbar_insert_stock(GTK_TOOLBAR(toolbar), GTK_STOCK_SAVE, - _("Save"), NULL, G_CALLBACK(save_cb), - win, -1); + item = gtk_tool_button_new_from_stock(GTK_STOCK_SAVE); + gtk_tool_item_set_is_important(item, TRUE); +#if GTK_CHECK_VERSION(2,12,0) + gtk_tool_item_set_tooltip_text(item, _("Save")); +#else + gtk_tool_item_set_tooltip(item, tooltips, _("Save"), NULL); +#endif + g_signal_connect(G_OBJECT(item), "clicked", G_CALLBACK(save_cb), win); + gtk_container_add(GTK_CONTAINER(toolbar), GTK_WIDGET(item)); /* Clear button */ - gtk_toolbar_insert_stock(GTK_TOOLBAR(toolbar), GTK_STOCK_CLEAR, - _("Clear"), NULL, G_CALLBACK(clear_cb), - win, -1); + item = gtk_tool_button_new_from_stock(GTK_STOCK_CLEAR); + gtk_tool_item_set_is_important(item, TRUE); +#if GTK_CHECK_VERSION(2,12,0) + gtk_tool_item_set_tooltip_text(item, _("Clear")); +#else + gtk_tool_item_set_tooltip(item, tooltips, _("Clear"), NULL); +#endif + g_signal_connect(G_OBJECT(item), "clicked", G_CALLBACK(clear_cb), win); + gtk_container_add(GTK_CONTAINER(toolbar), GTK_WIDGET(item)); - gtk_toolbar_insert_space(GTK_TOOLBAR(toolbar), -1); + item = gtk_separator_tool_item_new(); + gtk_container_add(GTK_CONTAINER(toolbar), GTK_WIDGET(item)); /* Pause */ - image = gtk_image_new_from_stock(PIDGIN_STOCK_PAUSE, GTK_ICON_SIZE_MENU); - gtk_toolbar_append_element(GTK_TOOLBAR(toolbar), - GTK_TOOLBAR_CHILD_TOGGLEBUTTON, - NULL, _("Pause"), _("Pause"), - NULL, image, - G_CALLBACK(pause_cb), win); + item = gtk_toggle_tool_button_new_from_stock(PIDGIN_STOCK_PAUSE); + gtk_tool_item_set_is_important(item, TRUE); +#if GTK_CHECK_VERSION(2,12,0) + gtk_tool_item_set_tooltip_text(item, _("Pause")); +#else + gtk_tool_item_set_tooltip(item, tooltips, _("Pause"), NULL); +#endif + g_signal_connect(G_OBJECT(item), "clicked", G_CALLBACK(pause_cb), win); + gtk_container_add(GTK_CONTAINER(toolbar), GTK_WIDGET(item)); #ifdef HAVE_REGEX_H /* regex stuff */ - gtk_toolbar_insert_space(GTK_TOOLBAR(toolbar), -1); + item = gtk_separator_tool_item_new(); + gtk_container_add(GTK_CONTAINER(toolbar), GTK_WIDGET(item)); /* regex toggle button */ - image = gtk_image_new_from_stock(GTK_STOCK_FIND, GTK_ICON_SIZE_MENU); - win->filter = - gtk_toolbar_append_element(GTK_TOOLBAR(toolbar), - GTK_TOOLBAR_CHILD_TOGGLEBUTTON, - NULL, _("Filter"), _("Filter"), - NULL, image, - G_CALLBACK(regex_filter_toggled_cb), - win); + item = gtk_toggle_tool_button_new_from_stock(GTK_STOCK_FIND); + gtk_tool_item_set_is_important(item, TRUE); + win->filter = GTK_WIDGET(item); + gtk_tool_button_set_label(GTK_TOOL_BUTTON(win->filter), _("Filter")); +#if GTK_CHECK_VERSION(2,12,0) + gtk_tool_item_set_tooltip_text(GTK_TOOL_ITEM(win->filter), _("Filter")); +#else + gtk_tooltips_set_tip(tooltips, win->filter, _("Filter"), NULL); +#endif + g_signal_connect(G_OBJECT(win->filter), "clicked", G_CALLBACK(regex_filter_toggled_cb), win); + gtk_container_add(GTK_CONTAINER(toolbar), GTK_WIDGET(win->filter)); + /* we purposely disable the toggle button here in case * /purple/gtk/debug/expression has an empty string. If it does not have * an empty string, the change signal will get called and make the * toggle button sensitive. */ gtk_widget_set_sensitive(win->filter, FALSE); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(win->filter), + gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(win->filter), purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/debug/filter")); purple_prefs_connect_callback(handle, PIDGIN_PREFS_ROOT "/debug/filter", regex_pref_filter_cb, win); /* regex entry */ win->expression = gtk_entry_new(); - gtk_toolbar_append_element(GTK_TOOLBAR(toolbar), - GTK_TOOLBAR_CHILD_WIDGET, win->expression, - NULL, _("Right click for more options."), - NULL, NULL, NULL, NULL); + item = gtk_tool_item_new(); +#if GTK_CHECK_VERSION(2,12,0) + gtk_widget_set_tooltip_text(win->expression, _("Right click for more options.")); +#else + gtk_tooltips_set_tip(tooltips, win->expression, _("Right click for more options."), NULL); +#endif + gtk_container_add(GTK_CONTAINER(item), GTK_WIDGET(win->expression)); + gtk_container_add(GTK_CONTAINER(toolbar), GTK_WIDGET(item)); + /* this needs to be before the text is set from the pref if we want it * to colorize a stored expression. */ @@ -815,18 +855,23 @@ #endif /* HAVE_REGEX_H */ - gtk_toolbar_insert_space(GTK_TOOLBAR(toolbar), -1); + item = gtk_separator_tool_item_new(); + gtk_container_add(GTK_CONTAINER(toolbar), GTK_WIDGET(item)); - gtk_toolbar_append_element(GTK_TOOLBAR(toolbar), - GTK_TOOLBAR_CHILD_WIDGET, gtk_label_new(_("Level ")), - NULL, _("Select the debug filter level."), - NULL, NULL, NULL, NULL); + item = gtk_tool_item_new(); + gtk_container_add(GTK_CONTAINER(item), gtk_label_new(_("Level "))); + gtk_container_add(GTK_CONTAINER(toolbar), GTK_WIDGET(item)); win->filterlevel = gtk_combo_box_new_text(); - gtk_toolbar_append_element(GTK_TOOLBAR(toolbar), - GTK_TOOLBAR_CHILD_WIDGET, win->filterlevel, - NULL, _("Select the debug filter level."), - NULL, NULL, NULL, NULL); + item = gtk_tool_item_new(); +#if GTK_CHECK_VERSION(2,12,0) + gtk_widget_set_tooltip_text(win->filterlevel, _("Select the debug filter level.")); +#else + gtk_tooltips_set_tip(tooltips, win->filterlevel, _("Select the debug filter level."), NULL); +#endif + gtk_container_add(GTK_CONTAINER(item), win->filterlevel); + gtk_container_add(GTK_CONTAINER(toolbar), GTK_WIDGET(item)); + gtk_combo_box_append_text(GTK_COMBO_BOX(win->filterlevel), _("All")); gtk_combo_box_append_text(GTK_COMBO_BOX(win->filterlevel), _("Misc")); gtk_combo_box_append_text(GTK_COMBO_BOX(win->filterlevel), _("Info")); diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/gtkdocklet-gtk.c --- a/pidgin/gtkdocklet-gtk.c Thu Feb 18 22:28:41 2010 +0000 +++ b/pidgin/gtkdocklet-gtk.c Sun Feb 28 04:07:39 2010 +0000 @@ -26,8 +26,6 @@ #include "pidginstock.h" #include "gtkdocklet.h" -#if GTK_CHECK_VERSION(2,10,0) - /* globals */ GtkStatusIcon *docklet = NULL; @@ -155,6 +153,3 @@ gtk_icon_theme_append_search_path(gtk_icon_theme_get_default(), DATADIR G_DIR_SEPARATOR_S "pixmaps" G_DIR_SEPARATOR_S "pidgin" G_DIR_SEPARATOR_S "tray"); } - -#endif /* GTK_CHECK_VERSION(2,10,0) */ - diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/gtkdocklet-x11.c --- a/pidgin/gtkdocklet-x11.c Thu Feb 18 22:28:41 2010 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,359 +0,0 @@ -/* - * System tray icon (aka docklet) plugin for Purple - * - * Copyright (C) 2002-3 Robert McQueen - * Copyright (C) 2003 Herman Bloggs - * Inspired by a similar plugin by: - * John (J5) Palmieri - * - * 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 "pidgin.h" -#include "debug.h" -#include "prefs.h" -#include "pidginstock.h" - -#include "gtkdialogs.h" - -#include "eggtrayicon.h" -#include "gtkdocklet.h" -#include - -#if !GTK_CHECK_VERSION(2,10,0) - -#define SHORT_EMBED_TIMEOUT 5000 -#define LONG_EMBED_TIMEOUT 15000 - -/* globals */ -static EggTrayIcon *docklet = NULL; -static GtkWidget *image = NULL; -static GtkTooltips *tooltips = NULL; -static GdkPixbuf *blank_icon = NULL; -static int embed_timeout = 0; -static int docklet_height = 0; - -/* protos */ -static void docklet_x11_create(gboolean); - -static gboolean -docklet_x11_recreate_cb(gpointer data) -{ - docklet_x11_create(TRUE); - - return FALSE; /* for when we're called by the glib idle handler */ -} - -static void -docklet_x11_embedded_cb(GtkWidget *widget, void *data) -{ - purple_debug(PURPLE_DEBUG_INFO, "docklet", "X11 embedded\n"); - - g_source_remove(embed_timeout); - embed_timeout = 0; - pidgin_docklet_embedded(); - purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/docklet/x11/embedded", FALSE); -} - -static void -docklet_x11_destroyed_cb(GtkWidget *widget, void *data) -{ - purple_debug(PURPLE_DEBUG_INFO, "docklet", "X11 destroyed\n"); - - pidgin_docklet_remove(); - - g_object_unref(G_OBJECT(docklet)); - docklet = NULL; - - g_idle_add(docklet_x11_recreate_cb, NULL); -} - -static gboolean -docklet_x11_clicked_cb(GtkWidget *button, GdkEventButton *event, void *data) -{ - if (event->type != GDK_BUTTON_PRESS) - return FALSE; - - pidgin_docklet_clicked(event->button); - return TRUE; -} - -static gboolean -docklet_x11_pressed_cb(GtkWidget *button, GdkEventKey *event) -{ - guint state, keyval; - - state = event->state & gtk_accelerator_get_default_mod_mask(); - keyval = event->keyval; - if (state == 0 && - (keyval == GDK_Return || - keyval == GDK_KP_Enter || - keyval == GDK_ISO_Enter || - keyval == GDK_space || - keyval == GDK_KP_Space)) - { - pidgin_docklet_clicked(1); - return TRUE; - } - - return FALSE; -} - -static void -docklet_x11_popup_cb(GtkWidget *button) -{ - pidgin_docklet_clicked(3); -} - -static void -docklet_x11_update_icon(PurpleStatusPrimitive status, gboolean connecting, gboolean pending) -{ - const gchar *icon_name = NULL; - - g_return_if_fail(image != NULL); - - switch (status) { - case PURPLE_STATUS_OFFLINE: - icon_name = PIDGIN_STOCK_TRAY_OFFLINE; - break; - case PURPLE_STATUS_AWAY: - icon_name = PIDGIN_STOCK_TRAY_AWAY; - break; - case PURPLE_STATUS_UNAVAILABLE: - icon_name = PIDGIN_STOCK_TRAY_BUSY; - break; - case PURPLE_STATUS_EXTENDED_AWAY: - icon_name = PIDGIN_STOCK_TRAY_XA; - break; - case PURPLE_STATUS_INVISIBLE: - icon_name = PIDGIN_STOCK_TRAY_INVISIBLE; - break; - default: - icon_name = PIDGIN_STOCK_TRAY_AVAILABLE; - break; - } - - if (pending) - icon_name = PIDGIN_STOCK_TRAY_PENDING; - if (connecting) - icon_name = PIDGIN_STOCK_TRAY_CONNECT; - - if(icon_name) { - int icon_size; - if (docklet_height < 22) - icon_size = gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_EXTRA_SMALL); - else if (docklet_height < 32) - icon_size = gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_SMALL); - else if (docklet_height < 48) - icon_size = gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_MEDIUM); - else - icon_size = gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_LARGE); - - gtk_image_set_from_stock(GTK_IMAGE(image), icon_name, icon_size); - } -} - -static void -docklet_x11_resize_icon(GtkWidget *widget) -{ - if (docklet_height == MIN(widget->allocation.height, widget->allocation.width)) - return; - docklet_height = MIN(widget->allocation.height, widget->allocation.width); - pidgin_docklet_update_icon(); -} - -static void -docklet_x11_blank_icon(void) -{ - if (!blank_icon) { - GtkIconSize size = GTK_ICON_SIZE_LARGE_TOOLBAR; - gint width, height; - g_object_get(G_OBJECT(image), "icon-size", &size, NULL); - gtk_icon_size_lookup(size, &width, &height); - blank_icon = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, width, height); - gdk_pixbuf_fill(blank_icon, 0); - } - - gtk_image_set_from_pixbuf(GTK_IMAGE(image), blank_icon); -} - -static void -docklet_x11_set_tooltip(gchar *tooltip) -{ - if (!tooltips) - tooltips = gtk_tooltips_new(); - - /* image->parent is a GtkEventBox */ - if (tooltip) { - gtk_tooltips_enable(tooltips); - gtk_tooltips_set_tip(tooltips, image->parent, tooltip, NULL); - } else { - gtk_tooltips_set_tip(tooltips, image->parent, "", NULL); - gtk_tooltips_disable(tooltips); - } -} - -static void -docklet_x11_position_menu(GtkMenu *menu, int *x, int *y, gboolean *push_in, - gpointer user_data) -{ - GtkWidget *widget = GTK_WIDGET(docklet); - GtkRequisition req; - gint menu_xpos, menu_ypos; - - gtk_widget_size_request(GTK_WIDGET(menu), &req); - gdk_window_get_origin(widget->window, &menu_xpos, &menu_ypos); - - menu_xpos += widget->allocation.x; - menu_ypos += widget->allocation.y; - - if (menu_ypos > gdk_screen_get_height(gtk_widget_get_screen(widget)) / 2) - menu_ypos -= req.height; - else - menu_ypos += widget->allocation.height; - - *x = menu_xpos; - *y = menu_ypos; - - *push_in = TRUE; -} - -static void -docklet_x11_destroy(void) -{ - g_return_if_fail(docklet != NULL); - - if (embed_timeout) - g_source_remove(embed_timeout); - - pidgin_docklet_remove(); - - g_signal_handlers_disconnect_by_func(G_OBJECT(docklet), G_CALLBACK(docklet_x11_destroyed_cb), NULL); - gtk_widget_destroy(GTK_WIDGET(docklet)); - - g_object_unref(G_OBJECT(docklet)); - docklet = NULL; - - if (blank_icon) - g_object_unref(G_OBJECT(blank_icon)); - blank_icon = NULL; - - image = NULL; - - purple_debug(PURPLE_DEBUG_INFO, "docklet", "X11 destroyed\n"); -} - -static gboolean -docklet_x11_embed_timeout_cb(gpointer data) -{ - /* The docklet was not embedded within the timeout. - * Remove it as a visibility manager, but leave the plugin - * loaded so that it can embed automatically if/when a notification - * area becomes available. - */ - purple_debug_info("docklet", "X11 failed to embed within timeout\n"); - pidgin_docklet_remove(); - - return FALSE; -} - -static void -docklet_x11_create(gboolean recreate) -{ - GtkWidget *box; - - if (docklet) { - /* if this is being called when a tray icon exists, it's because - something messed up. try destroying it before we proceed, - although docklet_refcount may be all hosed. hopefully won't happen. */ - purple_debug(PURPLE_DEBUG_WARNING, "docklet", "trying to create icon but it already exists?\n"); - docklet_x11_destroy(); - } - - docklet = egg_tray_icon_new(PIDGIN_NAME); - box = gtk_event_box_new(); - image = gtk_image_new(); - GTK_WIDGET_SET_FLAGS (image, GTK_CAN_FOCUS); - - g_signal_connect(G_OBJECT(docklet), "embedded", G_CALLBACK(docklet_x11_embedded_cb), NULL); - g_signal_connect(G_OBJECT(docklet), "destroy", G_CALLBACK(docklet_x11_destroyed_cb), NULL); - g_signal_connect(G_OBJECT(docklet), "size-allocate", G_CALLBACK(docklet_x11_resize_icon), NULL); - g_signal_connect(G_OBJECT(box), "button-press-event", G_CALLBACK(docklet_x11_clicked_cb), NULL); - g_signal_connect(G_OBJECT(box), "key-press-event", G_CALLBACK(docklet_x11_pressed_cb), NULL); - g_signal_connect(G_OBJECT(box), "popup-menu", G_CALLBACK(docklet_x11_popup_cb), NULL); - gtk_container_add(GTK_CONTAINER(box), image); - gtk_container_add(GTK_CONTAINER(docklet), box); - - if (!gtk_check_version(2,4,0)) - g_object_set(G_OBJECT(box), "visible-window", FALSE, NULL); - - gtk_widget_show_all(GTK_WIDGET(docklet)); - - /* ref the docklet before we bandy it about the place */ - g_object_ref(G_OBJECT(docklet)); - - /* This is a hack to avoid a race condition between the docklet getting - * embedded in the notification area and the gtkblist restoring its - * previous visibility state. If the docklet does not get embedded within - * the timeout, it will be removed as a visibility manager until it does - * get embedded. Ideally, we would only call docklet_embedded() when the - * icon was actually embedded. This only happens when the docklet is first - * created, not when being recreated. - * - * The x11 docklet tracks whether it successfully embedded in a pref and - * allows for a longer timeout period if it successfully embedded the last - * time it was run. This should hopefully solve problems with the buddy - * list not properly starting hidden when Pidgin is started on login. - */ - if(!recreate) { - pidgin_docklet_embedded(); - if(purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/docklet/x11/embedded")) { - embed_timeout = g_timeout_add(LONG_EMBED_TIMEOUT, docklet_x11_embed_timeout_cb, NULL); - } else { - embed_timeout = g_timeout_add(SHORT_EMBED_TIMEOUT, docklet_x11_embed_timeout_cb, NULL); - } - } - - purple_debug(PURPLE_DEBUG_INFO, "docklet", "X11 created\n"); -} - -static void -docklet_x11_create_ui_op(void) -{ - docklet_x11_create(FALSE); -} - -static struct docklet_ui_ops ui_ops = -{ - docklet_x11_create_ui_op, - docklet_x11_destroy, - docklet_x11_update_icon, - docklet_x11_blank_icon, - docklet_x11_set_tooltip, - docklet_x11_position_menu -}; - -void -docklet_ui_init() -{ - pidgin_docklet_set_ui_ops(&ui_ops); - purple_prefs_add_none(PIDGIN_PREFS_ROOT "/docklet/x11"); - purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/docklet/x11/embedded", FALSE); -} - -#endif /* !GTK_CHECK_VERSION(2,10,0) */ - diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/gtkft.c --- a/pidgin/gtkft.c Thu Feb 18 22:28:41 2010 +0000 +++ b/pidgin/gtkft.c Sun Feb 28 04:07:39 2010 +0000 @@ -578,7 +578,7 @@ /* Build the tree model */ /* Transfer type, Progress Bar, Filename, Size, Remaining */ - model = gtk_list_store_new(NUM_COLUMNS, GDK_TYPE_PIXBUF, G_TYPE_DOUBLE, + model = gtk_list_store_new(NUM_COLUMNS, GDK_TYPE_PIXBUF, G_TYPE_INT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER); dialog->model = model; @@ -612,7 +612,7 @@ /* Progress bar column */ renderer = gtk_cell_renderer_progress_new(); column = gtk_tree_view_column_new_with_attributes(_("Progress"), renderer, - "percentage", COLUMN_PROGRESS, NULL); + "value", COLUMN_PROGRESS, NULL); gtk_tree_view_column_set_resizable(GTK_TREE_VIEW_COLUMN(column), TRUE); gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column); @@ -909,7 +909,7 @@ lfilename = utf8; gtk_list_store_set(dialog->model, &data->iter, COLUMN_STATUS, pixbuf, - COLUMN_PROGRESS, 0.0, + COLUMN_PROGRESS, 0, COLUMN_FILENAME, (type == PURPLE_XFER_RECEIVE) ? purple_xfer_get_filename(xfer) : lfilename, @@ -1042,7 +1042,7 @@ remaining_str = purple_str_size_to_units(purple_xfer_get_bytes_remaining(xfer)); gtk_list_store_set(xfer_dialog->model, &data->iter, - COLUMN_PROGRESS, purple_xfer_get_progress(xfer), + COLUMN_PROGRESS, (gint)(purple_xfer_get_progress(xfer) * 100), COLUMN_SIZE, size_str, COLUMN_REMAINING, remaining_str, -1); diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/gtkprefs.c --- a/pidgin/gtkprefs.c Thu Feb 18 22:28:41 2010 +0000 +++ b/pidgin/gtkprefs.c Sun Feb 28 04:07:39 2010 +0000 @@ -902,9 +902,7 @@ cell_rend = gtk_cell_renderer_text_new(); gtk_cell_layout_pack_start(GTK_CELL_LAYOUT (combo_box), cell_rend, TRUE); gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combo_box), cell_rend, "markup", 1, NULL); -#if GTK_CHECK_VERSION(2,6,0) g_object_set(cell_rend, "ellipsize", PANGO_ELLIPSIZE_END, NULL); -#endif gtk_drag_dest_set(combo_box, GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_HIGHLIGHT | GTK_DEST_DEFAULT_DROP, te, sizeof(te) / sizeof(GtkTargetEntry) , GDK_ACTION_COPY | GDK_ACTION_MOVE); diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/gtkprivacy.c --- a/pidgin/gtkprivacy.c Thu Feb 18 22:28:41 2010 +0000 +++ b/pidgin/gtkprivacy.c Sun Feb 28 04:07:39 2010 +0000 @@ -220,7 +220,7 @@ for (i = 0; i < menu_entry_count; i++) { if (menu_entries[i].num == account->perm_deny) { - gtk_option_menu_set_history(GTK_OPTION_MENU(dialog->type_menu), i); + gtk_combo_box_set_active(GTK_COMBO_BOX(dialog->type_menu), i); break; } } @@ -234,9 +234,9 @@ * Even better: the privacy API needs to not suck. */ static void -type_changed_cb(GtkOptionMenu *optmenu, PidginPrivacyDialog *dialog) +type_changed_cb(GtkComboBox *combo, PidginPrivacyDialog *dialog) { - int new_type = menu_entries[gtk_option_menu_get_history(optmenu)].num; + int new_type = menu_entries[gtk_combo_box_get_active(combo)].num; dialog->account->perm_deny = new_type; serv_set_permit_deny(purple_account_get_connection(dialog->account)); @@ -343,8 +343,7 @@ GtkWidget *button; GtkWidget *dropdown; GtkWidget *label; - GtkWidget *menu; - int selected = 0; + int selected = -1; int i; dialog = g_new0(PidginPrivacyDialog, 1); @@ -372,22 +371,19 @@ dialog->account = pidgin_account_option_menu_get_selected(dropdown); /* Add the drop-down list with the allow/block types. */ - dialog->type_menu = gtk_option_menu_new(); + dialog->type_menu = gtk_combo_box_new_text(); gtk_box_pack_start(GTK_BOX(vbox), dialog->type_menu, FALSE, FALSE, 0); gtk_widget_show(dialog->type_menu); - /* Build the menu for that. */ - menu = gtk_menu_new(); - for (i = 0; i < menu_entry_count; i++) { - pidgin_new_item(menu, _(menu_entries[i].text)); + gtk_combo_box_append_text(GTK_COMBO_BOX(dialog->type_menu), + _(menu_entries[i].text)); if (menu_entries[i].num == dialog->account->perm_deny) selected = i; } - gtk_option_menu_set_menu(GTK_OPTION_MENU(dialog->type_menu), menu); - gtk_option_menu_set_history(GTK_OPTION_MENU(dialog->type_menu), selected); + gtk_combo_box_set_active(GTK_COMBO_BOX(dialog->type_menu), selected); g_signal_connect(G_OBJECT(dialog->type_menu), "changed", G_CALLBACK(type_changed_cb), dialog); @@ -421,7 +417,7 @@ button = pidgin_dialog_add_button(GTK_DIALOG(dialog->win), GTK_STOCK_CLOSE, G_CALLBACK(close_cb), dialog); dialog->close_button = button; - type_changed_cb(GTK_OPTION_MENU(dialog->type_menu), dialog); + type_changed_cb(GTK_COMBO_BOX(dialog->type_menu), dialog); #if 0 if (dialog->account->perm_deny == PURPLE_PRIVACY_ALLOW_USERS) { gtk_widget_show(dialog->allow_widget); diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/gtkrequest.c --- a/pidgin/gtkrequest.c Thu Feb 18 22:28:41 2010 +0000 +++ b/pidgin/gtkrequest.c Sun Feb 28 04:07:39 2010 +0000 @@ -231,10 +231,10 @@ } static void -field_choice_menu_cb(GtkOptionMenu *menu, PurpleRequestField *field) +field_choice_menu_cb(GtkComboBox *menu, PurpleRequestField *field) { purple_request_field_choice_set_value(field, - gtk_option_menu_get_history(menu)); + gtk_combo_box_get_active(menu)); } static void @@ -958,26 +958,15 @@ if (num_labels > 5) { - GtkWidget *menu; - GtkWidget *item; - - widget = gtk_option_menu_new(); - - menu = gtk_menu_new(); + widget = gtk_combo_box_new_text(); for (l = labels; l != NULL; l = l->next) { const char *text = l->data; - - item = gtk_menu_item_new_with_label(text); - gtk_widget_show(item); - - gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); + gtk_combo_box_append_text(GTK_COMBO_BOX(widget), text); } - gtk_widget_show(menu); - gtk_option_menu_set_menu(GTK_OPTION_MENU(widget), menu); - gtk_option_menu_set_history(GTK_OPTION_MENU(widget), + gtk_combo_box_set_active(GTK_COMBO_BOX(widget), purple_request_field_choice_get_default_value(field)); g_signal_connect(G_OBJECT(widget), "changed", @@ -1094,6 +1083,9 @@ GtkTreeViewColumn *column; GtkTreeIter iter; GList *l; + GList *icons = NULL; + + icons = purple_request_field_list_get_icons(field); /* Create the scrolled window */ sw = gtk_scrolled_window_new(NULL, NULL); @@ -1105,7 +1097,10 @@ gtk_widget_show(sw); /* Create the list store */ - store = gtk_list_store_new(2, G_TYPE_POINTER, G_TYPE_STRING); + if (icons) + store = gtk_list_store_new(3, G_TYPE_POINTER, G_TYPE_STRING, GDK_TYPE_PIXBUF); + else + store = gtk_list_store_new(2, G_TYPE_POINTER, G_TYPE_STRING); /* Create the tree view */ treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); @@ -1124,13 +1119,38 @@ gtk_tree_view_column_pack_start(column, renderer, TRUE); gtk_tree_view_column_add_attribute(column, renderer, "text", 1); + if (icons) + { + renderer = gtk_cell_renderer_pixbuf_new(); + gtk_tree_view_column_pack_start(column, renderer, TRUE); + gtk_tree_view_column_add_attribute(column, renderer, "pixbuf", 2); + + gtk_widget_set_size_request(treeview, 200, 400); + } + for (l = purple_request_field_list_get_items(field); l != NULL; l = l->next) { const char *text = (const char *)l->data; gtk_list_store_append(store, &iter); - gtk_list_store_set(store, &iter, + if (icons) + { + const char *icon_path = (const char *)icons->data; + GdkPixbuf* pixbuf = NULL; + + if (icon_path) + pixbuf = gdk_pixbuf_new_from_file(icon_path, NULL); + + gtk_list_store_set(store, &iter, + 0, purple_request_field_list_get_data(field, text), + 1, text, + 2, pixbuf, + -1); + icons = icons->next; + } + else + gtk_list_store_set(store, &iter, 0, purple_request_field_list_get_data(field, text), 1, text, -1); diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/gtksavedstatuses.c --- a/pidgin/gtksavedstatuses.c Thu Feb 18 22:28:41 2010 +0000 +++ b/pidgin/gtksavedstatuses.c Sun Feb 28 04:07:39 2010 +0000 @@ -85,17 +85,16 @@ }; /** - * These are used in the GtkComboBox to select the specific - * PurpleStatusType when setting a substatus for a particular saved - * status. + * These are used in the GtkComboBox to select the specific PurpleStatusType + * when setting a (sub)status for a particular saved status. */ enum { - SUBSTATUS_COLUMN_ICON, + STATUS_COLUMN_ICON, /** A hidden column containing the ID of this PurpleStatusType. */ - SUBSTATUS_COLUMN_STATUS_ID, - SUBSTATUS_COLUMN_STATUS_NAME, - SUBSTATUS_NUM_COLUMNS + STATUS_COLUMN_STATUS_ID, + STATUS_COLUMN_STATUS_NAME, + STATUS_NUM_COLUMNS }; typedef struct @@ -118,7 +117,7 @@ gchar *original_title; GtkEntry *title; - GtkOptionMenu *type; + GtkComboBox *type; GtkIMHtml *message; } StatusEditor; @@ -742,7 +741,7 @@ return; } - type = gtk_option_menu_get_history(dialog->type) + (PURPLE_STATUS_UNSET + 1); + type = gtk_combo_box_get_active(dialog->type) + (PURPLE_STATUS_UNSET + 1); message = gtk_imhtml_get_markup(dialog->message); unformatted = purple_markup_strip_html(message); @@ -837,53 +836,56 @@ } static GtkWidget * -create_stock_item(const gchar *str, const gchar *icon) -{ - GtkWidget *menuitem = gtk_menu_item_new(); - GtkWidget *label = gtk_label_new_with_mnemonic(str); - GtkWidget *hbox = gtk_hbox_new(FALSE, 4); - GtkIconSize icon_size = gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_EXTRA_SMALL); - GtkWidget *image = gtk_image_new_from_stock(icon, icon_size);; - - gtk_widget_show(label); - gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT); - gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); - gtk_box_pack_start(GTK_BOX(hbox), image, FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0); - - gtk_container_add(GTK_CONTAINER(menuitem), hbox); - - return menuitem; -} - -static GtkWidget * create_status_type_menu(PurpleStatusPrimitive type) { int i; GtkWidget *dropdown; - GtkWidget *menu; - GtkWidget *item; + GtkListStore *store; + GtkTreeIter iter; + GtkCellRenderer *renderer; - dropdown = gtk_option_menu_new(); - menu = gtk_menu_new(); + store = gtk_list_store_new(STATUS_NUM_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING); for (i = PURPLE_STATUS_UNSET + 1; i < PURPLE_STATUS_NUM_PRIMITIVES; i++) { - if (i == PURPLE_STATUS_MOBILE || i == PURPLE_STATUS_TUNE) + /* Someone should fix this for 3.0.0. The independent boolean + * should probably be set on the status type, not the status. + * I guess that would prevent third party plugins from creating + * independent statuses? + */ + if (i == PURPLE_STATUS_MOBILE || + i == PURPLE_STATUS_MOOD || + i == PURPLE_STATUS_TUNE) /* * Special-case these. They're intended to be independent * status types, so don't show them in the list. */ continue; - item = create_stock_item(purple_primitive_get_name_from_type(i), - get_stock_icon_from_primitive(i)); - gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); + gtk_list_store_append(store, &iter); + gtk_list_store_set(store, &iter, + STATUS_COLUMN_ICON, get_stock_icon_from_primitive(i), + STATUS_COLUMN_STATUS_ID, purple_primitive_get_id_from_type(i), + STATUS_COLUMN_STATUS_NAME, purple_primitive_get_name_from_type(i), + -1); } - gtk_menu_set_active(GTK_MENU(menu), type - (PURPLE_STATUS_UNSET + 1)); - gtk_option_menu_set_menu(GTK_OPTION_MENU(dropdown), menu); - gtk_widget_show_all(menu); + dropdown = gtk_combo_box_new_with_model(GTK_TREE_MODEL(store)); + + renderer = gtk_cell_renderer_pixbuf_new(); + gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(dropdown), renderer, FALSE); + gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(dropdown), renderer, + "stock-id", STATUS_COLUMN_ICON, + NULL); + + renderer = gtk_cell_renderer_text_new(); + gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(dropdown), renderer, TRUE); + gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(dropdown), renderer, + "text", STATUS_COLUMN_STATUS_NAME, + NULL); + + gtk_combo_box_set_active(GTK_COMBO_BOX(dropdown), + type - (PURPLE_STATUS_UNSET + 1)); return dropdown; } @@ -1153,7 +1155,7 @@ dropdown = create_status_type_menu(purple_savedstatus_get_type(saved_status)); else dropdown = create_status_type_menu(PURPLE_STATUS_AWAY); - dialog->type = GTK_OPTION_MENU(dropdown); + dialog->type = GTK_COMBO_BOX(dropdown); pidgin_add_widget_to_vbox(GTK_BOX(vbox), _("_Status:"), sg, dropdown, TRUE, NULL); /* Status message */ @@ -1268,7 +1270,7 @@ if (!gtk_combo_box_get_active_iter(box, &iter)) return; gtk_tree_model_get(GTK_TREE_MODEL(select->model), &iter, - SUBSTATUS_COLUMN_STATUS_ID, &id, + STATUS_COLUMN_STATUS_ID, &id, -1); type = purple_account_get_status_type(select->account, id); g_free(id); @@ -1359,7 +1361,7 @@ } gtk_tree_model_get(GTK_TREE_MODEL(dialog->model), &iter, - SUBSTATUS_COLUMN_STATUS_ID, &id, + STATUS_COLUMN_STATUS_ID, &id, -1); type = purple_account_get_status_type(dialog->account, id); if (purple_status_type_get_attr(type, "message") != NULL) @@ -1449,7 +1451,7 @@ gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); gtk_size_group_add_widget(sg, label); - dialog->model = gtk_list_store_new(SUBSTATUS_NUM_COLUMNS, + dialog->model = gtk_list_store_new(STATUS_NUM_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING); @@ -1462,12 +1464,12 @@ NULL); gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo), rend, FALSE); gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combo), rend, - "stock-id", SUBSTATUS_COLUMN_ICON, NULL); + "stock-id", STATUS_COLUMN_ICON, NULL); rend = GTK_CELL_RENDERER(gtk_cell_renderer_text_new()); gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo), rend, TRUE); gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combo), rend, - "text", SUBSTATUS_COLUMN_STATUS_NAME, NULL); + "text", STATUS_COLUMN_STATUS_NAME, NULL); g_signal_connect(G_OBJECT(combo), "changed", G_CALLBACK(substatus_selection_changed_cb), dialog); @@ -1543,9 +1545,9 @@ gtk_list_store_append(dialog->model, &iter); gtk_list_store_set(dialog->model, &iter, - SUBSTATUS_COLUMN_ICON, pidgin_stock_id_from_status_primitive(prim), - SUBSTATUS_COLUMN_STATUS_ID, id, - SUBSTATUS_COLUMN_STATUS_NAME, name, + STATUS_COLUMN_ICON, pidgin_stock_id_from_status_primitive(prim), + STATUS_COLUMN_STATUS_ID, id, + STATUS_COLUMN_STATUS_NAME, name, -1); if ((status_id != NULL) && !strcmp(status_id, id)) { diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/gtkutils.c --- a/pidgin/gtkutils.c Thu Feb 18 22:28:41 2010 +0000 +++ b/pidgin/gtkutils.c Sun Feb 28 04:07:39 2010 +0000 @@ -406,13 +406,13 @@ gtk_container_add(GTK_CONTAINER(button), bbox); if (icon) { - gtk_box_pack_start_defaults(GTK_BOX(bbox), ibox); + gtk_box_pack_start(GTK_BOX(bbox), ibox, TRUE, TRUE, 0); image = gtk_image_new_from_stock(icon, GTK_ICON_SIZE_BUTTON); gtk_box_pack_end(GTK_BOX(ibox), image, FALSE, TRUE, 0); } if (text) { - gtk_box_pack_start_defaults(GTK_BOX(bbox), lbox); + gtk_box_pack_start(GTK_BOX(bbox), lbox, TRUE, TRUE, 0); label = gtk_label_new(NULL); gtk_label_set_text_with_mnemonic(GTK_LABEL(label), text); gtk_label_set_mnemonic_widget(GTK_LABEL(label), button); diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/pidginstock.c --- a/pidgin/pidginstock.c Thu Feb 18 22:28:41 2010 +0000 +++ b/pidgin/pidginstock.c Sun Feb 28 04:07:39 2010 +0000 @@ -270,37 +270,30 @@ /* Altered from do_colorshift in gnome-panel */ static void -do_alphashift(GdkPixbuf *dest, GdkPixbuf *src) +do_alphashift(GdkPixbuf *pixbuf) { gint i, j; - gint width, height, has_alpha, srcrowstride, destrowstride; - guchar *target_pixels; - guchar *original_pixels; - guchar *pixsrc; - guchar *pixdest; + gint width, height, padding; + guchar *pixels; guchar a; - has_alpha = gdk_pixbuf_get_has_alpha (src); - if (!has_alpha) + if (!gdk_pixbuf_get_has_alpha(pixbuf)) return; - width = gdk_pixbuf_get_width (src); - height = gdk_pixbuf_get_height (src); - srcrowstride = gdk_pixbuf_get_rowstride (src); - destrowstride = gdk_pixbuf_get_rowstride (dest); - target_pixels = gdk_pixbuf_get_pixels (dest); - original_pixels = gdk_pixbuf_get_pixels (src); + width = gdk_pixbuf_get_width(pixbuf); + height = gdk_pixbuf_get_height(pixbuf); + padding = gdk_pixbuf_get_rowstride(pixbuf) - width * 4; + pixels = gdk_pixbuf_get_pixels(pixbuf); for (i = 0; i < height; i++) { - pixdest = target_pixels + i*destrowstride; - pixsrc = original_pixels + i*srcrowstride; for (j = 0; j < width; j++) { - *(pixdest++) = *(pixsrc++); - *(pixdest++) = *(pixsrc++); - *(pixdest++) = *(pixsrc++); - a = *(pixsrc++); - *(pixdest++) = a / 2; + pixels++; + pixels++; + pixels++; + a = *(pixels); + *(pixels++) = a / 2; } + pixels += padding; } } @@ -348,7 +341,7 @@ g_return_if_fail(filename != NULL); pixbuf = gdk_pixbuf_new_from_file(filename, NULL); if (translucent) - do_alphashift(pixbuf, pixbuf); + do_alphashift(pixbuf); source = gtk_icon_source_new(); gtk_icon_source_set_pixbuf(source, pixbuf); @@ -378,7 +371,7 @@ g_return_if_fail(filename != NULL); pixbuf = gdk_pixbuf_new_from_file(filename, NULL); if (translucent) - do_alphashift(pixbuf, pixbuf); + do_alphashift(pixbuf); source = gtk_icon_source_new(); gtk_icon_source_set_pixbuf(source, pixbuf); diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/pixmaps/Makefile.am --- a/pidgin/pixmaps/Makefile.am Thu Feb 18 22:28:41 2010 +0000 +++ b/pidgin/pixmaps/Makefile.am Sun Feb 28 04:07:39 2010 +0000 @@ -101,8 +101,6 @@ emblems/16/half-operator.png \ emblems/16/hiptop.png \ emblems/16/male.png \ - emblems/16/mobile.png \ - emblems/16/music.png \ emblems/16/not-authorized.png \ emblems/16/operator.png \ emblems/16/qq-member.png \ @@ -120,8 +118,6 @@ emblems/scalable/free-for-chat.svg \ emblems/scalable/game.svg \ emblems/scalable/male.svg \ - emblems/scalable/mobile.svg \ - emblems/scalable/music.svg \ emblems/scalable/not-authorized.svg \ emblems/scalable/qq-member.svg \ emblems/scalable/secure.svg \ @@ -207,6 +203,7 @@ emotes/default/24/scalable/yin-yang.svg EMOTES_SMALL_16_SCALABLE = \ + emotes/small/16/scalable/mobile.svg \ emotes/small/16/scalable/pidgin-emotes.svg PROTOCOLS_16_SCALABLE = \ diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/pixmaps/emblems/16/mobile.png Binary file pidgin/pixmaps/emblems/16/mobile.png has changed diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/pixmaps/emblems/16/music.png Binary file pidgin/pixmaps/emblems/16/music.png has changed diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/pixmaps/emblems/scalable/mobile.svg --- a/pidgin/pixmaps/emblems/scalable/mobile.svg Thu Feb 18 22:28:41 2010 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,264 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/pixmaps/emblems/scalable/music.svg --- a/pidgin/pixmaps/emblems/scalable/music.svg Thu Feb 18 22:28:41 2010 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,189 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/pixmaps/emotes/default/24/Makefile.am --- a/pidgin/pixmaps/emotes/default/24/Makefile.am Thu Feb 18 22:28:41 2010 +0000 +++ b/pidgin/pixmaps/emotes/default/24/Makefile.am Sun Feb 28 04:07:39 2010 +0000 @@ -2,6 +2,7 @@ act-up.png \ airplane.png \ alien.png \ + amorous.png \ angel.png \ angry.png \ arrogant.png \ @@ -56,8 +57,9 @@ dont-know.png \ drink.png \ drool.png \ - eat.png \ + hungry.png \ embarrassed.png \ + excited.png \ excruciating.png \ eyeroll.png \ female-fighter.png \ @@ -81,7 +83,7 @@ hug-left.png \ hug-right.png \ hypnotized.png \ - in-love.png \ + in_love.png \ island.png \ jump.png \ kissed.png \ @@ -94,7 +96,6 @@ liquor.png \ loser.png \ love-over.png \ - love.png \ lying.png \ mad-tongue.png \ mail.png \ @@ -114,7 +115,7 @@ msn.png \ musical-note.png \ music.png \ - nailbiting.png \ + nervous.png \ neutral.png \ on-the-phone.png \ party.png \ @@ -144,7 +145,7 @@ secret.png \ shame.png \ sheep.png \ - shock.png \ + shocked.png \ shout.png \ shut-mouth.png \ sick.png \ @@ -153,9 +154,9 @@ sinister.png \ skeleton.png \ skywalker.png \ + sleeping.png \ sleepy.png \ - smile-big.png \ - smile.png \ + happy.png \ smirk.png \ snail.png \ snicker.png \ @@ -167,7 +168,7 @@ stop.png \ struggle.png \ sun.png \ - sweat.png \ + hot.png \ talktohand.png \ teeth.png \ terror.png \ @@ -175,7 +176,7 @@ thunder.png \ time-out.png \ tongue.png \ - tremble.png \ + afraid.png \ turtle.png \ tv.png \ umbrella.png \ @@ -188,7 +189,6 @@ wilt.png \ wink.png \ worship.png \ - yawn.png \ yin-yang.png diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/pixmaps/emotes/default/24/afraid.png Binary file pidgin/pixmaps/emotes/default/24/afraid.png has changed diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/pixmaps/emotes/default/24/amorous.png Binary file pidgin/pixmaps/emotes/default/24/amorous.png has changed diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/pixmaps/emotes/default/24/default.theme.in --- a/pidgin/pixmaps/emotes/default/24/default.theme.in Thu Feb 18 22:28:41 2010 +0000 +++ b/pidgin/pixmaps/emotes/default/24/default.theme.in Sun Feb 28 04:07:39 2010 +0000 @@ -6,16 +6,16 @@ # Default smileys [default] -smile.png :) :-) -smile-big.png :-D :-d :D :d +happy.png :) :-) +excited.png :-D :-d :D :d sad.png :-( :( wink.png ;-) ;) -tongue.png :P :-P :-p :p -shock.png =-O =-o +tongue.png :P :p :-P :-p +shocked.png =-O =-o kiss.png :-* glasses-cool.png 8-) embarrassed.png :-[ -crying.png :'( +crying.png :'( :'-( thinking.png :-/ :-\\ angel.png O:-) o:-) shut-mouth.png :-X @@ -23,20 +23,70 @@ foot-in-mouth.png :-! shout.png >:o >:O ! skywalker.png C:-) c:-) C:) c:) -! monkey.png :-(|) :(|) 8-|) -! cyclops.png O-) o-) +! monkey.png :-(|) :(|) 8-|) +! cyclops.png O-) o-) + + +[XMPP] +# Following XEP-0038 + GTalk + our default set, in default set order +# The GTalk strings come from ticket #3307. +happy.png :) :-) =) +excited.png :-D :-d :D :d =D =d +sad.png :-( :( +wink.png ;-) ;) ;^) +tongue.png :P :p :-P :-p +shocked.png =-O =-o :-O :-o +kiss.png :kiss: :-* +glasses-cool.png 8-) B-) +embarrassed.png :-[ +crying.png :'-( :'( +thinking.png :-/ :-\\ +angel.png O:-) o:-) +shut-mouth.png :-X +moneymouth.png :-$ +foot-in-mouth.png :-! +shout.png >:o >:O + +# Following XEP-0038 + GTalk +angry.png >:-( >:( X-( x-( +good.png :yes: +bad.png :no: +stop.png :wait: +rose.png @->-- :rose: +phone.png :telephone: +mail.png :email: +lamp.png :jabber: +cake.png :cake: +in_love.png :heart: :love: <3 +love-over.png :brokenheart: +musical-note.png :music: +beer.png :beer: +coffee.png :coffee: +coins.png :money: +moon.png :moon: +sun.png :sun: +star.png :star: + +# Others +neutral.png :| :-| +victory.png \\m/ + +# Hidden icons from the default set. +! skywalker.png C:-) c:-) C:) c:) +! monkey.png :-(|) :(|) 8-|) +! cyclops.png O-) o-) # Following AIM 6.1 [AIM] -smile.png :-) :) +happy.png :-) :) wink.png ;-) ;) sad.png :-( :( -tongue.png :-P :P :-p :p -shock.png =-O +tongue.png :P :p :-P :-p +shocked.png =-O kiss.png :-* shout.png >:o -smile-big.png :-D :D +excited.png :-D :D moneymouth.png :-$ foot-in-mouth.png :-! embarrassed.png :-[ @@ -46,26 +96,27 @@ shut-mouth.png :-X glasses-cool.png 8-) ! skywalker.png C:-) c:-) C:) c:) -! monkey.png :-(|) :(|) +! monkey.png :-(|) :(|) 8-|) +! cyclops.png O-) o-) # Following Windows Live Messenger 8.1 [MSN] -smile.png :) :-) -smile-big.png :D :d :-D :-d +happy.png :) :-) +excited.png :D :d :-D :-d wink.png ;) ;-) -shock.png :-O :-o :O :o -tongue.png :P :p :-P :-p +shocked.png :-O :-o :O :o +tongue.png :-P :P :-p :p glasses-cool.png (H) (h) angry.png :@ :-@ embarrassed.png :$ :-$ -confused.png :S :s :-S :-s +confused.png :S :s :-S :-s sad.png :( :-( crying.png :'( neutral.png :| :-| devil.png (6) angel.png (A) (a) -love.png (L) (l) +in_love.png (L) (l) love-over.png (U) (u) msn.png (M) (m) cat.png (@) @@ -125,10 +176,11 @@ thunder.png (li) party.png <:o) eyeroll.png 8-) -yawn.png |-) +sleepy.png |-) bunny.png ('.') ! skywalker.png C:-) c:-) C:) c:) -! monkey.png :-(|) :(|) +! monkey.png :-(|) :(|) 8-|) +! cyclops.png O-) o-) # Hidden MSN emotes cigarette.png (ci) (CI) @@ -139,7 +191,7 @@ # Following QQ 2006 [QQ] -shock.png /:O /jy /surprised +shocked.png /:O /jy /surprised curl-lip.png /:~ /pz /curl_lip desire.png /:* /se /desire dazed.png /:| /dazed @@ -147,13 +199,13 @@ crying.png /:< /ll /cry bashful.png /:$ /hx /bashful shut-mouth.png /:X /bz /shut_mouth -sleepy.png /:Z /shui /sleep +sleeping.png /:Z /shui /sleep weep.png /:'( /dk /weep embarrassed.png /:-| /gg /embarassed pissed-off.png /:@ /fn /pissed_off act-up.png /:P /tp /act_up -smile-big.png /:D /cy /toothy_smile -smile.png /:) /wx /small_smile +excited.png /:D /cy /toothy_smile +happy.png /:) /wx /small_smile sad.png /:( /ng /sad glasses-cool.png /:+ /kuk /cool doctor.png /:# /feid /SARS @@ -164,9 +216,9 @@ disdain.png /;d /by /disdain arrogant.png /;o /am /arrogant starving.png /:g /jie /starving -yawn.png /|-) /kun /sleepy +sleepy.png /|-) /kun /sleepy terror.png /:! /jk /terror -sweat.png /:L /sweat +hot.png /:L /sweat smirk.png /:> /hanx /smirk soldier.png /:; /db /soldier struggle.png /;f /fendou /struggle @@ -180,8 +232,8 @@ hammer.png /xx /qiao /hammer bye.png /bye /zj /bye go-away.png /go /shan /go -tremble.png /shake /fad /shake -in-love.png /love /aiq /love +afraid.png /shake /fad /shake +amorous.png /love /aiq /love jump.png /jump /tiao /jump search.png /find /zhao /search lashes.png /& /mm /beautiful_eyebrows @@ -200,12 +252,12 @@ musical-note.png /music /yy /music poop.png /shit /bb /shit coffee.png /coffee /kf /coffee -eat.png /eat /fan /eat +hungry.png /eat /fan /eat pill.png /pill /yw /pill rose.png /rose /mg /rose wilt.png /fade /dx /wilt kiss.png /kiss /wen /kiss -love.png /heart /xin /heart +in_love.png /heart /xin /heart love-over.png /break /xs /broken_heart meeting.png /meeting /hy /meeting present.png /gift /lw /gift @@ -233,20 +285,21 @@ girl.png /<00> /nv /woman boy.png /<11> /nan /man ! skywalker.png C:-) c:-) C:) c:) -! monkey.png :-(|) :(|) +! monkey.png :-(|) :(|) 8-|) +! cyclops.png O-) o-) # Following ICQ 6.0 [ICQ] -smile.png :-) :) +happy.png :-) :) neutral.png :-$ sad.png :-( :( -shock.png =-O +shocked.png =-O wink.png ;-) ;) tongue.png :-P :P :-p :p music.png [:-} laugh.png *JOKINGLY* -sleepy.png *TIRED* +sleeping.png *TIRED* crying.png :'( :'-( sick.png :-! kissed.png *KISSED* @@ -265,26 +318,27 @@ good.png *THUMBS\ UP* shout.png >:o >:O :-@ beer.png *DRINK* -smile-big.png :-D :D +excited.png :-D :D glasses-cool.png 8-) -in-love.png *IN\ LOVE* +amorous.png *IN\ LOVE* ! skywalker.png C:-) c:-) C:) c:) -! monkey.png :-(|) :(|) +! monkey.png :-(|) :(|) 8-|) +! cyclops.png O-) o-) # Following Yahoo! Messenger 8.1 [Yahoo] -smile.png :) :-) +happy.png :) :-) question.png :-/ :-\\ -shock.png :-O :O :-o :o +shocked.png :-O :O :-o :o devil.png >:) angel.png O:-) o:-) 0:-) sick.png :-& -yawn.png (:| +sleepy.png (:| hypnotized.png @-) on-the-phone.png :)] sad.png :( :-( -in-love.png :x :-x :X :-X +amorous.png :x :-x :X :-X angry.png X-( x-( X( x( crying.png :(( glasses-nerdy.png :-B :-b @@ -301,11 +355,11 @@ thinking.png :-? waiting.png :-w :-W at-wits-end.png ~x( ~X( -smile-big.png :D :-D :d :-d +excited.png :D :-D :d :-d tongue.png :-P :P :-p :p glasses-cool.png B-) b-) neutral.png :| :-| -sleepy.png I-) i-) |-) +sleeping.png I-) i-) |-) clown.png :o) :O) doh.png #-o #-O weep.png :-< @@ -321,107 +375,16 @@ time-out.png :-t :-T hug-left.png >:D< >:d< love-over.png =(( -sweat.png #:-S #:-s +hot.png #:-S #:-s rotfl.png =)) :-j :-J loser.png L-) l-) party.png <:-P <:-p -nailbiting.png :-SS :-Ss :-sS :-ss +nervous.png :-SS :-Ss :-sS :-ss cowboy.png <):) desire.png 8-> ! skywalker.png C:-) c:-) C:) c:) -! monkey.png :-(|) :(|) - -# Hidden Yahoo emotes -alien.png =:) >-) -beat-up.png b-( B-( -chicken.png ~:> -coffee.png ~o) ~O) -cow.png 3:-O 3:-o -dance.png \\:D/ \\:d/ -rose.png @};- -dont-know.png :-L :-l -skeleton.png 8-X 8-x -lamp.png *-:) -monkey.png :(|) -coins.png $-) -peace.png :)>- -pig.png :@) -pray.png [-o< [-O< -pumpkin.png (~~) -shame.png [-X [-x -flag.png **== -clover.png %%- -musical-note.png :-" -giggle.png ;)) -worship.png ^:)^ -star.png (*) -waving.png >:/ -talktohand.png :-@ - -# Only available after activating the Yahoo! Fighter IMVironment -male-fighter1.png o-> O-> -male-fighter2.png o=> O=> -female-fighter.png o-+ O-+ -yin-yang.png (%) - -# Following Yahoo! Messenger 8.1 -[Yahoo JAPAN] -smile.png :) :-) -question.png :-/ :-\\ -shock.png :-O :O :-o :o -devil.png >:) -angel.png O:-) o:-) 0:-) -sick.png :-& -yawn.png (:| -hypnotized.png @-) -on-the-phone.png :)] -sad.png :( :-( -in-love.png :x :-x :X :-X -angry.png X-( x-( X( x( -crying.png :(( -glasses-nerdy.png :-B :-b -quiet.png :-$ -drool.png =P~ =p~ -lying.png :^O :^o -call-me.png :-c -wink.png ;) ;-) -embarrassed.png :"> -mean.png :-> :> -laugh.png :)) :-)) -bye.png =; -arrogant.png [-( -thinking.png :-? -waiting.png :-w :-W -at-wits-end.png ~x( ~X( -smile-big.png :D :-D :d :-d -tongue.png :-P :P :-p :p -glasses-cool.png B-) b-) -neutral.png :| :-| -sleepy.png I-) i-) |-) -clown.png :o) :O) -doh.png #-o #-O -weep.png :-< -go-away.png :-h -lashes.png ;;) -kiss.png :-* :* -confused.png :-S :-s -sarcastic.png /:) -eyeroll.png 8-| -silly.png 8-} -clap.png =D> =d> -mad-tongue.png >:P >:p -time-out.png :-t :-T -hug-left.png >:D< >:d< -love-over.png =(( -sweat.png #:-S #:-s -rotfl.png =)) :-j :-J -loser.png L-) l-) -party.png <:-P <:-p -nailbiting.png :-SS :-Ss :-sS :-ss -cowboy.png <):) -desire.png 8-> -! skywalker.png C:-) c:-) C:) c:) -! monkey.png :-(|) :(|) +! monkey.png :-(|) :(|) 8-|) +! cyclops.png O-) o-) # Hidden Yahoo emotes alien.png =:) >-) @@ -459,14 +422,14 @@ # Following MySpaceIM Beta 1.0.697.0 [MySpaceIM] -smile-big.png :D :-D +excited.png :D :-D devil.png }:) confused.png :Z glasses-nerdy.png B) bulgy-eyes.png %) freaked-out.png :E smile.png :) :-) -in-love.png :X +amorous.png :X laugh.png :)) mohawk.png -: mad-tongue.png X( @@ -474,7 +437,7 @@ glasses-nerdy.png Q) doh.png :G pirate.png P) -shock.png :O +shocked.png :O sidefrown.png :{ sinister.png :B smirk.png :, @@ -484,23 +447,7 @@ wink.png ;-) ;) sad.png :[ kiss.png :x +! skywalker.png C:-) c:-) C:) c:) +! monkey.png :-(|) :(|) 8-|) +! cyclops.png O-) o-) -[XMPP] -# XMPP emoticons -smile.png :) :-) =) -smile-big.png :D :-D =D -wink.png ;) ;-) ;^) -shock.png :-o -tongue.png :P :-P :-p :p -glasses-cool.png B-) -angry.png X-( -sad.png :( :-( =( -crying.png :'( -neutral.png :-| -thinking.png :-/ -love.png <3 -monkey.png :(|) -victory.png \\m/ -! skywalker.png C:-) c:-) C:) c:) -! monkey.png :-(|) :(|) 8-|) -! cyclops.png O-) o-) diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/pixmaps/emotes/default/24/eat.png Binary file pidgin/pixmaps/emotes/default/24/eat.png has changed diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/pixmaps/emotes/default/24/excited.png Binary file pidgin/pixmaps/emotes/default/24/excited.png has changed diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/pixmaps/emotes/default/24/happy.png Binary file pidgin/pixmaps/emotes/default/24/happy.png has changed diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/pixmaps/emotes/default/24/hot.png Binary file pidgin/pixmaps/emotes/default/24/hot.png has changed diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/pixmaps/emotes/default/24/hungry.png Binary file pidgin/pixmaps/emotes/default/24/hungry.png has changed diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/pixmaps/emotes/default/24/in-love.png Binary file pidgin/pixmaps/emotes/default/24/in-love.png has changed diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/pixmaps/emotes/default/24/in_love.png Binary file pidgin/pixmaps/emotes/default/24/in_love.png has changed diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/pixmaps/emotes/default/24/love.png Binary file pidgin/pixmaps/emotes/default/24/love.png has changed diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/pixmaps/emotes/default/24/nailbiting.png Binary file pidgin/pixmaps/emotes/default/24/nailbiting.png has changed diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/pixmaps/emotes/default/24/nervous.png Binary file pidgin/pixmaps/emotes/default/24/nervous.png has changed diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/pixmaps/emotes/default/24/shock.png Binary file pidgin/pixmaps/emotes/default/24/shock.png has changed diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/pixmaps/emotes/default/24/shocked.png Binary file pidgin/pixmaps/emotes/default/24/shocked.png has changed diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/pixmaps/emotes/default/24/sleeping.png Binary file pidgin/pixmaps/emotes/default/24/sleeping.png has changed diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/pixmaps/emotes/default/24/sleepy.png Binary file pidgin/pixmaps/emotes/default/24/sleepy.png has changed diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/pixmaps/emotes/default/24/smile-big.png Binary file pidgin/pixmaps/emotes/default/24/smile-big.png has changed diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/pixmaps/emotes/default/24/smile.png Binary file pidgin/pixmaps/emotes/default/24/smile.png has changed diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/pixmaps/emotes/default/24/sweat.png Binary file pidgin/pixmaps/emotes/default/24/sweat.png has changed diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/pixmaps/emotes/default/24/tremble.png Binary file pidgin/pixmaps/emotes/default/24/tremble.png has changed diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/pixmaps/emotes/default/24/yawn.png Binary file pidgin/pixmaps/emotes/default/24/yawn.png has changed diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/pixmaps/emotes/small/16/Makefile.am --- a/pidgin/pixmaps/emotes/small/16/Makefile.am Thu Feb 18 22:28:41 2010 +0000 +++ b/pidgin/pixmaps/emotes/small/16/Makefile.am Sun Feb 28 04:07:39 2010 +0000 @@ -1,4 +1,24 @@ +# These are mood images that are NOT also used in the smiley theme. +MOODS = \ + afraid.png \ + bathing.png \ + cinema.png \ + disappointed.png \ + embarrassed.png \ + internet.png \ + music.png \ + restroom.png \ + search.png \ + shopping.png \ + studying.png \ + suit.png \ + surfing.png \ + typing.png \ + working.png \ + writing.png + SMILEYS = \ + amorous.png \ angel.png \ angry.png \ beer.png \ @@ -12,12 +32,15 @@ crying.png \ devil.png \ dont-know.png \ + excited.png \ grin.png \ + happy.png \ hug-left.png \ hug-right.png \ + in_love.png \ kiss.png \ - love.png \ meeting.png \ + mobile.png \ musical-note.png \ nerdy.png \ neutral.png \ @@ -27,18 +50,16 @@ question.png \ sad.png \ shame.png \ - shock.png \ + shocked.png \ sick.png \ silent.png \ + sleeping.png \ sleepy.png \ - smile-big.png \ - smile.png \ thinking.png \ tongue.png \ tv.png \ uhm-yeah.png \ - wink.png \ - yawn.png + wink.png pidginsmileypix_in_files = small.theme.in @@ -46,6 +67,7 @@ if INSTALL_PIXMAPS pidginsmileypixdir = $(datadir)/pixmaps/pidgin/emotes/small pidginsmileypix_DATA = \ + $(MOODS) \ $(SMILEYS) \ theme @@ -56,4 +78,4 @@ $< > $@ endif -EXTRA_DIST = $(SMILEYS) $(pidginsmileypix_in_files) theme +EXTRA_DIST = $(MOODS) $(SMILEYS) $(pidginsmileypix_in_files) theme diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/pixmaps/emotes/small/16/TODO --- a/pidgin/pixmaps/emotes/small/16/TODO Thu Feb 18 22:28:41 2010 +0000 +++ b/pidgin/pixmaps/emotes/small/16/TODO Sun Feb 28 04:07:39 2010 +0000 @@ -1,7 +1,18 @@ The following icons where just scaled down from the 24x24 and may need work: + afraid.png + amorous.png + disappointed.png + embarrassed.png + happy.png + hot.png + hungry.png + mean.png meeting.png + nervous.png question.png + sarcastic.png search.png + shocked.png sleepy.png smile-big.png tv.png @@ -13,7 +24,7 @@ cigarette.png coffee.png console.png - love.png + in_love.png musical-note.png party.png phone.png diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/pixmaps/emotes/small/16/afraid.png Binary file pidgin/pixmaps/emotes/small/16/afraid.png has changed diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/pixmaps/emotes/small/16/amorous.png Binary file pidgin/pixmaps/emotes/small/16/amorous.png has changed diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/pixmaps/emotes/small/16/bathing.png Binary file pidgin/pixmaps/emotes/small/16/bathing.png has changed diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/pixmaps/emotes/small/16/cinema.png Binary file pidgin/pixmaps/emotes/small/16/cinema.png has changed diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/pixmaps/emotes/small/16/disappointed.png Binary file pidgin/pixmaps/emotes/small/16/disappointed.png has changed diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/pixmaps/emotes/small/16/embarrassed.png Binary file pidgin/pixmaps/emotes/small/16/embarrassed.png has changed diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/pixmaps/emotes/small/16/excited.png Binary file pidgin/pixmaps/emotes/small/16/excited.png has changed diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/pixmaps/emotes/small/16/happy.png Binary file pidgin/pixmaps/emotes/small/16/happy.png has changed diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/pixmaps/emotes/small/16/hot.png Binary file pidgin/pixmaps/emotes/small/16/hot.png has changed diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/pixmaps/emotes/small/16/hungry.png Binary file pidgin/pixmaps/emotes/small/16/hungry.png has changed diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/pixmaps/emotes/small/16/in_love.png Binary file pidgin/pixmaps/emotes/small/16/in_love.png has changed diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/pixmaps/emotes/small/16/internet.png Binary file pidgin/pixmaps/emotes/small/16/internet.png has changed diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/pixmaps/emotes/small/16/love.png Binary file pidgin/pixmaps/emotes/small/16/love.png has changed diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/pixmaps/emotes/small/16/mean.png Binary file pidgin/pixmaps/emotes/small/16/mean.png has changed diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/pixmaps/emotes/small/16/mobile.png Binary file pidgin/pixmaps/emotes/small/16/mobile.png has changed diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/pixmaps/emotes/small/16/music.png Binary file pidgin/pixmaps/emotes/small/16/music.png has changed diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/pixmaps/emotes/small/16/nervous.png Binary file pidgin/pixmaps/emotes/small/16/nervous.png has changed diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/pixmaps/emotes/small/16/restroom.png Binary file pidgin/pixmaps/emotes/small/16/restroom.png has changed diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/pixmaps/emotes/small/16/sarcastic.png Binary file pidgin/pixmaps/emotes/small/16/sarcastic.png has changed diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/pixmaps/emotes/small/16/scalable/mobile.svg --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pidgin/pixmaps/emotes/small/16/scalable/mobile.svg Sun Feb 28 04:07:39 2010 +0000 @@ -0,0 +1,264 @@ + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/pixmaps/emotes/small/16/scalable/music.svg --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pidgin/pixmaps/emotes/small/16/scalable/music.svg Sun Feb 28 04:07:39 2010 +0000 @@ -0,0 +1,189 @@ + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/pixmaps/emotes/small/16/shock.png Binary file pidgin/pixmaps/emotes/small/16/shock.png has changed diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/pixmaps/emotes/small/16/shocked.png Binary file pidgin/pixmaps/emotes/small/16/shocked.png has changed diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/pixmaps/emotes/small/16/shopping.png Binary file pidgin/pixmaps/emotes/small/16/shopping.png has changed diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/pixmaps/emotes/small/16/sleeping.png Binary file pidgin/pixmaps/emotes/small/16/sleeping.png has changed diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/pixmaps/emotes/small/16/sleepy.png Binary file pidgin/pixmaps/emotes/small/16/sleepy.png has changed diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/pixmaps/emotes/small/16/small.theme.in --- a/pidgin/pixmaps/emotes/small/16/small.theme.in Thu Feb 18 22:28:41 2010 +0000 +++ b/pidgin/pixmaps/emotes/small/16/small.theme.in Sun Feb 28 04:07:39 2010 +0000 @@ -6,27 +6,58 @@ # Default smileys [default] -smile.png :) :-) -smile-big.png :-D :-d :D :d +happy.png :) :-) +excited.png :-D :-d :D :d sad.png :-( :( wink.png ;-) ;) -tongue.png :P :-P :-p :p -shock.png =-O =-o +tongue.png :P :p :-P :-p +shocked.png =-O =-o kiss.png :-* -crying.png :'( +embarrassed.png :-[ +crying.png :'( :'-( thinking.png :-/ :-\\ angel.png O:-) o:-) +[XMPP] +# Following XEP-0038 + GTalk + our default set, in default set order +# The GTalk strings come from ticket #3307. +happy.png :) :-) =) +excited.png :-D :-d :D :d =D =d +sad.png :-( :( +wink.png ;-) ;) ;^) +tongue.png :P :p :-P :-p +shocked.png =-O =-o :-O :-o +kiss.png :kiss: :-* +embarrassed.png :-[ +crying.png :'-( :'( +thinking.png :-/ :-\\ +angel.png O:-) o:-) + +# Following XEP-0038 + GTalk +angry.png >:-( >:( X-( x-( +phone.png :telephone: +in_love.png :heart: :love: <3 +musical-note.png :music: +beer.png :beer: +coffee.png :coffee: + +# Others +neutral.png :| :-| + +# Hidden icons from the default set. + + # Following AIM 6.1 [AIM] -smile.png :-) :) +happy.png :-) :) wink.png ;-) ;) sad.png :-( :( -tongue.png :-P :P :-p :p -shock.png =-O +tongue.png :P :p :-P :-p +shocked.png =-O kiss.png :-* -smile-big.png :-D :D +excited.png :-D :D +embarrassed.png :-[ angel.png O:-) thinking.png :-\\ :-/ crying.png :'( @@ -34,19 +65,20 @@ # Following Windows Live Messenger 8.1 [MSN] -smile.png :) :-) -smile-big.png :D :d :-D :-d +happy.png :) :-) +excited.png :D :d :-D :-d wink.png ;) ;-) -shock.png :-O :-o :O :o -tongue.png :P :p :-P :-p +shocked.png :-O :-o :O :o +tongue.png :-P :P :-p :p angry.png :@ :-@ -confused.png :S :s :-S :-s +embarrassed.png :$ :-$ +confused.png :S :s :-S :-s sad.png :( :-( crying.png :'( neutral.png :| :-| devil.png (6) angel.png (A) (a) -love.png (L) (l) +in_love.png (L) (l) musical-note.png (8) kiss.png (K) (k) camera.png (P) (p) @@ -55,12 +87,14 @@ hug-left.png ({) hug-right.png (}) beer.png (B) (b) +sarcastic.png ^o) sick.png +o( plate.png (pl) +mobile.png (mp) dont-know.png :^) thinking.png *-) party.png <:o) -yawn.png |-) +sleepy.png |-) # Hidden MSN emotes cigarette.png (ci) (CI) @@ -69,22 +103,27 @@ # Following QQ 2006 [QQ] -shock.png /:O /jy /surprised +shocked.png /:O /jy /surprised party.png /8-) /dy /revel crying.png /:< /ll /cry -sleepy.png /:Z /shui /sleep -smile-big.png /:D /cy /toothy_smile -smile.png /:) /wx /small_smile +sleeping.png /:Z /shui /sleep +embarrassed.png /:-| /gg /embarassed +excited.png /:D /cy /toothy_smile +happy.png /:) /wx /small_smile sad.png /:( /ng /sad sick.png /:T /tu /vomit -yawn.png /|-) /kun /sleepy +sleepy.png /|-) /kun /sleepy +hot.png /:L /sweat question.png /? /yiw /question +afraid.png /shake /fad /shake +amorous.png /love /aiq /love search.png /find /zhao /search hug-left.png /hug /yb /hug musical-note.png /music /yy /music coffee.png /coffee /kf /coffee +hungry.png /eat /fan /eat kiss.png /kiss /wen /kiss -love.png /heart /xin /heart +in_love.png /heart /xin /heart meeting.png /meeting /hy /meeting phone.png /phone /dh /phone tv.png /TV /ds /TV @@ -93,45 +132,54 @@ # Following ICQ 6.0 [ICQ] -smile.png :-) :) +happy.png :-) :) neutral.png :-$ sad.png :-( :( -shock.png =-O +shocked.png =-O wink.png ;-) ;) tongue.png :-P :P :-p :p -sleepy.png *TIRED* +music.png [:-} +sleeping.png *TIRED* crying.png :'( :'-( sick.png :-! kiss.png :-{} :-* +embarrassed.png :-[ devil.png ]:-> angel.png O:-) thinking.png :-\\ :-/ beer.png *DRINK* -smile-big.png :-D :D +excited.png :-D :D +amorous.png *IN\ LOVE* # Following Yahoo! Messenger 8.1 [Yahoo] -smile.png :) :-) +happy.png :) :-) question.png :-/ :-\\ -shock.png :-O :O :-o :o +shocked.png :-O :O :-o :o devil.png >:) angel.png O:-) o:-) 0:-) sick.png :-& -yawn.png (:| +sleepy.png (:| sad.png :( :-( +amorous.png :x :-x :X :-X angry.png X-( x-( X( x( crying.png :(( wink.png ;) ;-) +embarrassed.png :"> +mean.png :-> :> thinking.png :-? -smile-big.png :D :-D :d :-d +excited.png :D :-D :d :-d tongue.png :-P :P :-p :p neutral.png :| :-| -sleepy.png I-) i-) |-) +sleeping.png I-) i-) |-) kiss.png :-* :* confused.png :-S :-s +sarcastic.png /:) hug-left.png >:D< >:d< +hot.png #:-S #:-s party.png <:-P <:-p +nervous.png :-SS :-Ss :-sS :-ss # Hidden Yahoo emotes coffee.png ~o) ~O) @@ -171,30 +219,14 @@ # Following MySpaceIM Beta 1.0.697.0 [MySpaceIM] -smile-big.png :D :-D +excited.png :D :-D devil.png }:) confused.png :Z -smile.png :) :-) -shock.png :O +amorous.png :X +shocked.png :O neutral.png :| tongue.png :P :p wink.png ;-) ;) sad.png :[ kiss.png :x -[XMPP] -# XMPP emoticons -smile.png :) :-) =) -smile-big.png :D :-D =D -wink.png ;) ;-) ;^) -shock.png :-o -tongue.png :P :-P :-p :p -glasses-cool.png B-) -angry.png X-( -sad.png :( :-( =( -crying.png :'( -neutral.png :-| -thinking.png :-/ -love.png <3 -monkey.png :(|) -victory.png \\m/ diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/pixmaps/emotes/small/16/smile-big.png Binary file pidgin/pixmaps/emotes/small/16/smile-big.png has changed diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/pixmaps/emotes/small/16/smile.png Binary file pidgin/pixmaps/emotes/small/16/smile.png has changed diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/pixmaps/emotes/small/16/studying.png Binary file pidgin/pixmaps/emotes/small/16/studying.png has changed diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/pixmaps/emotes/small/16/suit.png Binary file pidgin/pixmaps/emotes/small/16/suit.png has changed diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/pixmaps/emotes/small/16/surfing.png Binary file pidgin/pixmaps/emotes/small/16/surfing.png has changed diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/pixmaps/emotes/small/16/typing.png Binary file pidgin/pixmaps/emotes/small/16/typing.png has changed diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/pixmaps/emotes/small/16/working.png Binary file pidgin/pixmaps/emotes/small/16/working.png has changed diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/pixmaps/emotes/small/16/writing.png Binary file pidgin/pixmaps/emotes/small/16/writing.png has changed diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/pixmaps/emotes/small/16/yawn.png Binary file pidgin/pixmaps/emotes/small/16/yawn.png has changed diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/plugins/gestures/gestures.c --- a/pidgin/plugins/gestures/gestures.c Thu Feb 18 22:28:41 2010 +0000 +++ b/pidgin/plugins/gestures/gestures.c Sun Feb 28 04:07:39 2010 +0000 @@ -145,6 +145,15 @@ } #if 0 +#if GTK_CHECK_VERSION(2,4,0) +static void +mouse_button_menu_cb(GtkComboBox *opt, gpointer data) +{ + int button = gtk_combo_box_get_active(opt); + + gstroke_set_mouse_button(button + 2); +} +#else static void mouse_button_menu_cb(GtkMenuItem *item, gpointer data) { @@ -153,6 +162,7 @@ gstroke_set_mouse_button(button + 2); } #endif +#endif static void toggle_draw_cb(GtkToggleButton *toggle, gpointer data) @@ -220,8 +230,10 @@ GtkWidget *toggle; #if 0 GtkWidget *opt; +#if GTK_CHECK_VERSION(2,4,0) GtkWidget *menu, *item; #endif +#endif /* Outside container */ ret = gtk_vbox_new(FALSE, 18); @@ -231,6 +243,19 @@ vbox = pidgin_make_frame(ret, _("Mouse Gestures Configuration")); #if 0 +#if GTK_CHECK_VERSION(2,4,0) + /* Mouse button drop-down menu */ + opt = gtk_combo_box_new_text(); + + gtk_combo_box_append_text(_("Middle mouse button")); + gtk_combo_box_append_text(_("Right mouse button")); + g_signal_connect(G_OBJECT(opt), "changed", + G_CALLBACK(mouse_button_menu_cb), NULL); + + gtk_box_pack_start(GTK_BOX(vbox), opt, FALSE, FALSE, 0); + gtk_combo_box_set_active(GTK_COMBO_BOX(opt), + gstroke_get_mouse_button() - 2); +#else /* Mouse button drop-down menu */ menu = gtk_menu_new(); opt = gtk_option_menu_new(); @@ -250,6 +275,7 @@ gtk_option_menu_set_history(GTK_OPTION_MENU(opt), gstroke_get_mouse_button() - 2); #endif +#endif /* "Visual gesture display" checkbox */ toggle = gtk_check_button_new_with_mnemonic(_("_Visual gesture display")); diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/plugins/gevolution/assoc-buddy.c --- a/pidgin/plugins/gevolution/assoc-buddy.c Thu Feb 18 22:28:41 2010 +0000 +++ b/pidgin/plugins/gevolution/assoc-buddy.c Sun Feb 28 04:07:39 2010 +0000 @@ -20,7 +20,6 @@ */ #include "internal.h" #include "gtkblist.h" -#include "gtkexpander.h" #include "pidgin.h" #include "gtkutils.h" #include "gtkimhtml.h" diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/plugins/gtkbuddynote.c --- a/pidgin/plugins/gtkbuddynote.c Thu Feb 18 22:28:41 2010 +0000 +++ b/pidgin/plugins/gtkbuddynote.c Sun Feb 28 04:07:39 2010 +0000 @@ -31,11 +31,13 @@ const gchar *note = purple_blist_node_get_string(node, "notes"); if ((note != NULL) && (*note != '\0')) { - char *tmp; + char *tmp, *esc; purple_markup_html_to_xhtml(note, NULL, &tmp); + esc = g_markup_escape_text(tmp, -1); + g_free(tmp); g_string_append_printf(text, _("\nBuddy Note: %s"), - tmp); - g_free(tmp); + esc); + g_free(esc); } } } diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/plugins/win32/transparency/win2ktrans.c --- a/pidgin/plugins/win32/transparency/win2ktrans.c Thu Feb 18 22:28:41 2010 +0000 +++ b/pidgin/plugins/win32/transparency/win2ktrans.c Sun Feb 28 04:07:39 2010 +0000 @@ -72,8 +72,6 @@ static const char *OPT_WINTRANS_BL_ONTOP = "/plugins/gtk/win32/wintrans/bl_always_on_top"; static GSList *window_list = NULL; -static BOOL (*MySetLayeredWindowAttributes)(HWND hwnd, COLORREF crKey, BYTE bAlpha, DWORD dwFlags) = NULL; - /* * CODE */ @@ -81,31 +79,31 @@ /* Set window transparency level */ static void set_wintrans(GtkWidget *window, int alpha, gboolean enabled, gboolean always_on_top) { - if (MySetLayeredWindowAttributes) { - HWND hWnd = GDK_WINDOW_HWND(window->window); - LONG style = GetWindowLong(hWnd, GWL_EXSTYLE); - if (enabled) { - style |= WS_EX_LAYERED; - } else { - style &= ~WS_EX_LAYERED; - } - SetWindowLong(hWnd, GWL_EXSTYLE, style); + + HWND hWnd = GDK_WINDOW_HWND(window->window); + LONG style = GetWindowLong(hWnd, GWL_EXSTYLE); + if (enabled) { + style |= WS_EX_LAYERED; + } else { + style &= ~WS_EX_LAYERED; + } + SetWindowLong(hWnd, GWL_EXSTYLE, style); - if (enabled) { - SetWindowPos(hWnd, - always_on_top ? HWND_TOPMOST : HWND_NOTOPMOST, - 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); - MySetLayeredWindowAttributes(hWnd, 0, alpha, LWA_ALPHA); - } else { - /* Ask the window and its children to repaint */ - SetWindowPos(hWnd, HWND_NOTOPMOST, 0, 0, 0, 0, - SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); + if (enabled) { + SetWindowPos(hWnd, + always_on_top ? HWND_TOPMOST : HWND_NOTOPMOST, + 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); + SetLayeredWindowAttributes(hWnd, 0, alpha, LWA_ALPHA); + } else { + /* Ask the window and its children to repaint */ + SetWindowPos(hWnd, HWND_NOTOPMOST, 0, 0, 0, 0, + SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); - RedrawWindow(hWnd, NULL, NULL, - RDW_ERASE | RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN); - } + RedrawWindow(hWnd, NULL, NULL, + RDW_ERASE | RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN); } + } /* When a conv window is focused, if we're only transparent when unfocused, @@ -491,14 +489,6 @@ * EXPORTED FUNCTIONS */ static gboolean plugin_load(PurplePlugin *plugin) { - MySetLayeredWindowAttributes = (void*) wpurple_find_and_loadproc( - "user32.dll", "SetLayeredWindowAttributes"); - - if (!MySetLayeredWindowAttributes) { - purple_debug_error(WINTRANS_PLUGIN_ID, - "SetLayeredWindowAttributes API not found (Required W2K+)\n"); - return FALSE; - } purple_signal_connect(purple_conversations_get_handle(), "conversation-created", plugin, diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/win32/gtkwin32dep.c --- a/pidgin/win32/gtkwin32dep.c Thu Feb 18 22:28:41 2010 +0000 +++ b/pidgin/win32/gtkwin32dep.c Sun Feb 28 04:07:39 2010 +0000 @@ -47,8 +47,6 @@ #include "zlib.h" #include "untar.h" -#include - #include "gtkwin32dep.h" #include "win32dep.h" #include "gtkconv.h" @@ -64,8 +62,6 @@ HWND messagewin_hwnd; static int gtkwin32_handle; -typedef BOOL (CALLBACK* LPFNFLASHWINDOWEX)(PFLASHWINFO); -static LPFNFLASHWINDOWEX MyFlashWindowEx = NULL; static gboolean pwm_handles_connections = TRUE; @@ -308,6 +304,7 @@ void winpidgin_window_flash(GtkWindow *window, gboolean flash) { GdkWindow * gdkwin; + FLASHWINFO info; g_return_if_fail(window != NULL); @@ -319,25 +316,19 @@ if(GDK_WINDOW_DESTROYED(gdkwin)) return; - if(MyFlashWindowEx) { - FLASHWINFO info; + memset(&info, 0, sizeof(FLASHWINFO)); + info.cbSize = sizeof(FLASHWINFO); + info.hwnd = GDK_WINDOW_HWND(gdkwin); + if (flash) { + DWORD flashCount; + info.uCount = 3; + if (SystemParametersInfo(SPI_GETFOREGROUNDFLASHCOUNT, 0, &flashCount, 0)) + info.uCount = flashCount; + info.dwFlags = FLASHW_ALL | FLASHW_TIMER; + } else + info.dwFlags = FLASHW_STOP; + info.dwTimeout = 0; - memset(&info, 0, sizeof(FLASHWINFO)); - info.cbSize = sizeof(FLASHWINFO); - info.hwnd = GDK_WINDOW_HWND(gdkwin); - if (flash) { - DWORD flashCount; - info.uCount = 3; - if (SystemParametersInfo(SPI_GETFOREGROUNDFLASHCOUNT, 0, &flashCount, 0)) - info.uCount = flashCount; - info.dwFlags = FLASHW_ALL | FLASHW_TIMER; - } else - info.dwFlags = FLASHW_STOP; - info.dwTimeout = 0; - - MyFlashWindowEx(&info); - } else - FlashWindow(GDK_WINDOW_HWND(gdkwin), flash); } void @@ -384,11 +375,27 @@ } void winpidgin_init(HINSTANCE hint) { + FARPROC proc; purple_debug_info("winpidgin", "winpidgin_init start\n"); exe_hInstance = hint; + proc = wpurple_find_and_loadproc("exchndl.dll", "SetLogFile"); + if (proc) { + gchar *debug_dir, *locale_debug_dir; + + debug_dir = g_build_filename(purple_user_dir(), "pidgin.RPT", NULL); + locale_debug_dir = g_locale_from_utf8(debug_dir, -1, NULL, NULL, NULL); + + purple_debug_info("winpidgin", "Setting exchndl.dll LogFile to %s\n", debug_dir); + + (proc)(locale_debug_dir); + + g_free(debug_dir); + g_free(locale_debug_dir); + } + /* IdleTracker Initialization */ if(!winpidgin_set_idlehooks()) purple_debug_error("winpidgin", "Failed to initialize idle tracker\n"); @@ -399,8 +406,6 @@ messagewin_hwnd = winpidgin_message_window_init(); - MyFlashWindowEx = (LPFNFLASHWINDOWEX) wpurple_find_and_loadproc("user32.dll", "FlashWindowEx"); - purple_debug_info("winpidgin", "winpidgin_init end\n"); } @@ -436,36 +441,16 @@ return TRUE; } -typedef HMONITOR WINAPI _MonitorFromWindow(HWND, DWORD); -typedef BOOL WINAPI _GetMonitorInfo(HMONITOR, LPMONITORINFO); - static gboolean get_WorkingAreaRectForWindow(HWND hwnd, RECT *workingAreaRc) { - static _MonitorFromWindow *the_MonitorFromWindow; - static _GetMonitorInfo *the_GetMonitorInfo; - static gboolean initialized = FALSE; HMONITOR monitor; MONITORINFO info; - if(!initialized) { - the_MonitorFromWindow = (_MonitorFromWindow*) - wpurple_find_and_loadproc("user32", "MonitorFromWindow"); - the_GetMonitorInfo = (_GetMonitorInfo*) - wpurple_find_and_loadproc("user32", "GetMonitorInfoA"); - initialized = TRUE; - } - - if(!the_MonitorFromWindow) - return FALSE; - - if(!the_GetMonitorInfo) - return FALSE; - - monitor = the_MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY); + monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY); info.cbSize = sizeof(info); - if(!the_GetMonitorInfo(monitor, &info)) + if(!GetMonitorInfo(monitor, &info)) return FALSE; CopyRect(workingAreaRc, &(info.rcWork)); diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/win32/nsis/langmacros.nsh --- a/pidgin/win32/nsis/langmacros.nsh Thu Feb 18 22:28:41 2010 +0000 +++ b/pidgin/win32/nsis/langmacros.nsh Sun Feb 28 04:07:39 2010 +0000 @@ -91,8 +91,10 @@ !insertmacro PIDGIN_MACRO_LANGSTRING_INSERT PIDGIN_SPELLCHECK_SWEDISH ${CUR_LANG} !insertmacro PIDGIN_MACRO_LANGSTRING_INSERT PIDGIN_SPELLCHECK_UKRAINIAN ${CUR_LANG} - !insertmacro PIDGIN_MACRO_LANGSTRING_INSERT PIDGIN_DEBUGSYMBOLS_ERROR ${CUR_LANG} - !insertmacro PIDGIN_MACRO_LANGSTRING_INSERT PIDGIN_GTK_DOWNLOAD_ERROR ${CUR_LANG} + !insertmacro PIDGIN_MACRO_LANGSTRING_INSERT PIDGIN_DEBUGSYMBOLS_ERROR ${CUR_LANG} + !insertmacro PIDGIN_MACRO_LANGSTRING_INSERT PIDGIN_GTK_DOWNLOAD_ERROR ${CUR_LANG} + + !insertmacro PIDGIN_MACRO_LANGSTRING_INSERT TRANSLATIONS_SECTION_TITLE ${CUR_LANG} !undef CUR_LANG !macroend diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/win32/nsis/pidgin-installer.nsi --- a/pidgin/win32/nsis/pidgin-installer.nsi Thu Feb 18 22:28:41 2010 +0000 +++ b/pidgin/win32/nsis/pidgin-installer.nsi Sun Feb 28 04:07:39 2010 +0000 @@ -53,7 +53,7 @@ ;Defines !define PIDGIN_NSIS_INCLUDE_PATH "." -!define PIDGIN_INSTALLER_DEPS "..\..\..\..\win32-dev\pidgin-inst-deps-0.2" +!define PIDGIN_INSTALLER_DEPS "..\..\..\..\win32-dev\pidgin-inst-deps-20100223" ; Remove these and the stuff that uses them at some point !define OLD_GAIM_REG_KEY "SOFTWARE\gaim" @@ -352,12 +352,11 @@ Pop $R0 StrCmp $R0 "cancel" done StrCmp $R0 "success" +2 - MessageBox MB_RETRYCANCEL "$(PIDGIN_GTK_DOWNLOAD_ERROR) : $R1" /SD IDCANCEL IDRETRY retry IDCANCEL done + MessageBox MB_RETRYCANCEL "$(PIDGIN_GTK_DOWNLOAD_ERROR) : $R2" /SD IDCANCEL IDRETRY retry IDCANCEL done !endif SetOutPath "$INSTDIR" - nsisunz::UnzipToLog $R1 "$INSTDIR" Pop $R0 StrCmp $R0 "success" +2 @@ -610,17 +609,17 @@ SectionGroupEnd Section /o $(DEBUG_SYMBOLS_SECTION_TITLE) SecDebugSymbols + InitPluginsDir - - ; We need to download and extract the debug symbols - StrCpy $R1 "$PLUGINSDIR\pidgin-${PIDGIN_VERSION}-dbgsym.zip" + StrCpy $R1 "$PLUGINSDIR\dbgsym.zip" !ifdef OFFLINE_INSTALLER SetOutPath $PLUGINSDIR - File /oname=pidgin-${PIDGIN_VERSION}-dbgsym.zip "..\..\..\..\gtk_installer\gtk-runtime-${GTK_INSTALL_VERSION}.zip" + File /oname=dbgsym.zip "..\..\..\pidgin-${PIDGIN_VERSION}-dbgsym.zip" !else + ; We need to download the debug symbols retry: StrCpy $R2 "${DOWNLOADER_URL}?version=${PIDGIN_VERSION}&dl_pkg=dbgsym" DetailPrint "Downloading Debug Symbols... ($R2)" @@ -632,6 +631,7 @@ !endif + SetOutPath "$INSTDIR" nsisunz::UnzipToLog $R1 "$INSTDIR" Pop $R0 StrCmp $R0 "success" +2 @@ -779,7 +779,7 @@ Delete "$INSTDIR\libsasl.dll" Delete "$INSTDIR\libsilc-1-1-2.dll" Delete "$INSTDIR\libsilcclient-1-1-2.dll" - Delete "$INSTDIR\libxml2.dll" + Delete "$INSTDIR\libxml2-2.dll" Delete "$INSTDIR\libymsg.dll" Delete "$INSTDIR\nspr4.dll" Delete "$INSTDIR\nss3.dll" @@ -801,7 +801,7 @@ ; Remove the local GTK+ copy (if we're not just upgrading) ${GetParameters} $R0 ClearErrors - ${GetOptions} "$R3" "/KEEPGTK=" $R1 + ${GetOptions} "$R0" "/KEEPGTK=" $R1 IfErrors +2 StrCmp $R1 "1" +2 RMDir /r "$INSTDIR\Gtk" @@ -1368,6 +1368,10 @@ Push $R0 Push $R1 +!ifdef OFFLINE_INSTALLER + !insertmacro SelectSection ${SecDebugSymbols} +!endif + Call DoWeNeedGtk Pop $R0 IntCmp $R0 1 done gtk_not_mandatory diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/win32/nsis/translations/english.nsh --- a/pidgin/win32/nsis/translations/english.nsh Thu Feb 18 22:28:41 2010 +0000 +++ b/pidgin/win32/nsis/translations/english.nsh Sun Feb 28 04:07:39 2010 +0000 @@ -25,13 +25,14 @@ !insertmacro PIDGIN_MACRO_DEFAULT_STRING PIDGIN_SHORTCUTS_SECTION_TITLE "Shortcuts" !insertmacro PIDGIN_MACRO_DEFAULT_STRING PIDGIN_DESKTOP_SHORTCUT_SECTION_TITLE "Desktop" !insertmacro PIDGIN_MACRO_DEFAULT_STRING PIDGIN_STARTMENU_SHORTCUT_SECTION_TITLE "Start Menu" +!insertmacro PIDGIN_MACRO_DEFAULT_STRING TRANSLATIONS_SECTION_TITLE "Localizations" !insertmacro PIDGIN_MACRO_DEFAULT_STRING PIDGIN_SECTION_DESCRIPTION "Core Pidgin files and dlls" !insertmacro PIDGIN_MACRO_DEFAULT_STRING GTK_SECTION_DESCRIPTION "A multi-platform GUI toolkit, used by Pidgin" !insertmacro PIDGIN_MACRO_DEFAULT_STRING PIDGIN_SHORTCUTS_SECTION_DESCRIPTION "Shortcuts for starting Pidgin" !insertmacro PIDGIN_MACRO_DEFAULT_STRING PIDGIN_DESKTOP_SHORTCUT_DESC "Create a shortcut to Pidgin on the Desktop" !insertmacro PIDGIN_MACRO_DEFAULT_STRING PIDGIN_STARTMENU_SHORTCUT_DESC "Create a Start Menu entry for Pidgin" -!insertmacro PIDGIN_MACRO_DEFAULT_STRING DEBUG_SYMBOLS_SECTION_TITLE "Debug Symbols (for reporting crashes)" +!insertmacro PIDGIN_MACRO_DEFAULT_STRING DEBUG_SYMBOLS_SECTION_TITLE "Debug Symbols (for reporting crashes)" ; GTK+ Directory Page @@ -79,6 +80,7 @@ !insertmacro PIDGIN_MACRO_DEFAULT_STRING PIDGIN_SPELLCHECK_SWEDISH "Swedish" !insertmacro PIDGIN_MACRO_DEFAULT_STRING PIDGIN_SPELLCHECK_UKRAINIAN "Ukrainian" -!insertmacro PIDGIN_MACRO_DEFAULT_STRING PIDGIN_DEBUGSYMBOLS_ERROR "Error Installing Debug Symbols" +!insertmacro PIDGIN_MACRO_DEFAULT_STRING PIDGIN_DEBUGSYMBOLS_ERROR "Error Installing Debug Symbols" -!insertmacro PIDGIN_MACRO_DEFAULT_STRING PIDGIN_GTK_DOWNLOAD_ERROR "Error Downloading the GTK+ Runtime" +!insertmacro PIDGIN_MACRO_DEFAULT_STRING PIDGIN_GTK_DOWNLOAD_ERROR "Error Downloading the GTK+ Runtime" + diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/win32/nsis/translations/norwegian_nynorsk.nsh --- a/pidgin/win32/nsis/translations/norwegian_nynorsk.nsh Thu Feb 18 22:28:41 2010 +0000 +++ b/pidgin/win32/nsis/translations/norwegian_nynorsk.nsh Sun Feb 28 04:07:39 2010 +0000 @@ -9,7 +9,6 @@ ; Startup Checks !define INSTALLER_IS_RUNNING "Installasjonsprogrammet kjører allereie." !define PIDGIN_IS_RUNNING "Pidgin kjører no. Lukk programmet og prøv igjen." -!define GTK_INSTALLER_NEEDED "GTK+-kjøremiljøet manglar eller treng å bli oppdatert.$\rInstaller v${GTK_MIN_VERSION} eller nyare av GTK+-kjøremiljøet" ; License Page !define PIDGIN_LICENSE_BUTTON "Neste >" @@ -28,20 +27,12 @@ !define PIDGIN_DESKTOP_SHORTCUT_DESC "Lag ein snarveg til Pidgin på skrivebordet" !define PIDGIN_STARTMENU_SHORTCUT_DESC "Lag ein snarveg til Pidgin på startmenyen" -; GTK+ Directory Page -!define GTK_UPGRADE_PROMPT "Fann ei gammal utgåve av GTK+-kjøremiljøet. Vil du oppdatera ho?$\rMerk: $(^Name) vil kanskje ikkje fungera om du ikkje oppdaterer." -!define GTK_WINDOWS_INCOMPATIBLE "Windows 95/98/Me er ikkje kompatibelt med GTK+ 2.8.0 eller nyare. GTK+ ${GTK_INSTALL_VERSION} kjem ikkje til å bli installert.$\rInstallasjonen vil bli abvroten om ikkje GTK+ ${GTK_MIN_VERSION} eller nyare allereie er installert." - ; Installer Finish Page !define PIDGIN_FINISH_VISIT_WEB_SITE "Besøk Pidgin si nettside" ; Pidgin Section Prompts and Texts !define PIDGIN_PROMPT_CONTINUE_WITHOUT_UNINSTALL "Klarte ikkje å avinstallera Pidgin-utgåva som er i bruk. Den nye utgåva kjem til å bli installert utan å ta vekk den gjeldande." -; GTK+ Section Prompts -!define GTK_INSTALL_ERROR "Klarte ikkje å installera GTK+-kjøremiljøet." -!define GTK_BAD_INSTALL_PATH "Klarer ikkje å laga eller få tilgang til bana du skreiv." - ; URL Handler section !define URI_HANDLERS_SECTION_TITLE "URI-referanse" diff -r 221cebbc35d8 -r 6d3a90b49dba pidgin/win32/nsis/translations/polish.nsh --- a/pidgin/win32/nsis/translations/polish.nsh Thu Feb 18 22:28:41 2010 +0000 +++ b/pidgin/win32/nsis/translations/polish.nsh Sun Feb 28 04:07:39 2010 +0000 @@ -25,17 +25,9 @@ !define PIDGIN_DESKTOP_SHORTCUT_DESC "Utworzenie skrótu do programu Pidgin na pulpicie" !define PIDGIN_STARTMENU_SHORTCUT_DESC "Utworzenie wpisu w menu Start dla programu Pidgin" -; GTK+ Directory Page -!define GTK_UPGRADE_PROMPT "Odnaleziono star¹ wersjê biblioteki GTK+. Zaktualizowaæ j¹?$\rUwaga: program $(^Name) mo¿e bez tego nie dzia³aæ." -!define GTK_WINDOWS_INCOMPATIBLE "Systemy Windows 95/98/Me s¹ niezgodne z bibliotek¹ GTK+ 2.8.0 lub nowsz¹. Biblioteka GTK+ ${GTK_INSTALL_VERSION} nie zostanie zainstalowana.$\rJeœli brak zainstalowanej biblioteki GTK+ ${GTK_MIN_VERSION} lub nowszej, instalacja zostanie przerwana." - ; Installer Finish Page !define PIDGIN_FINISH_VISIT_WEB_SITE "OdwiedŸ stronê WWW programu Pidgin" -; GTK+ Section Prompts -!define GTK_INSTALL_ERROR "B³¹d podczas instalowania biblioteki GTK+." -!define GTK_BAD_INSTALL_PATH "Nie mo¿na uzyskaæ dostêpu do podanej œcie¿ki lub jej utworzyæ." - ; Uninstall Section Prompts !define un.PIDGIN_UNINSTALL_ERROR_1 "Instalator nie mo¿e odnaleŸæ wpisów w rejestrze dla programu Pidgin.$\rMo¿liwe, ¿e inny u¿ytkownik zainstalowa³ ten program." -!define un.PIDGIN_UNINSTALL_ERROR_2 "Brak uprawnieñ do odinstalowania tego programu." \ No newline at end of file +!define un.PIDGIN_UNINSTALL_ERROR_2 "Brak uprawnieñ do odinstalowania tego programu." diff -r 221cebbc35d8 -r 6d3a90b49dba po/POTFILES.in --- a/po/POTFILES.in Thu Feb 18 22:28:41 2010 +0000 +++ b/po/POTFILES.in Sun Feb 28 04:07:39 2010 +0000 @@ -145,6 +145,7 @@ libpurple/protocols/novell/novell.c libpurple/protocols/oscar/clientlogin.c libpurple/protocols/oscar/family_chatnav.c +libpurple/protocols/oscar/family_locate.c libpurple/protocols/oscar/flap_connection.c libpurple/protocols/oscar/libaim.c libpurple/protocols/oscar/libicq.c @@ -213,14 +214,12 @@ pidgin/gtkaccount.c pidgin/gtkblist-theme.c pidgin/gtkblist.c -pidgin/gtkcellview.c pidgin/gtkcertmgr.c pidgin/gtkconn.c pidgin/gtkconv.c pidgin/gtkdebug.c pidgin/gtkdialogs.c pidgin/gtkdocklet.c -pidgin/gtkexpander.c pidgin/gtkft.c pidgin/gtkimhtml.c pidgin/gtkimhtmltoolbar.c @@ -241,7 +240,6 @@ pidgin/gtkutils.c pidgin/gtkwhiteboard.c pidgin/pidgin.h -pidgin/pidgincombobox.c pidgin/pidginstock.c pidgin/pidgintooltip.c pidgin/pixmaps/emotes/default/24/default.theme.in