Mon, 18 Jun 2007 01:48:35 +0000
explicit merge of '87854ccfae544467c988edbac854c1ae2018eed4'
and '4fe92c2fa5afd77565c3b27aba6c2b9674a88322'
| COPYRIGHT | file | annotate | diff | comparison | revisions | |
| configure.ac | file | annotate | diff | comparison | revisions | |
| libpurple/cipher.c | file | annotate | diff | comparison | revisions | |
| libpurple/protocols/bonjour/dns_sd.c | file | annotate | diff | comparison | revisions | |
| libpurple/protocols/bonjour/dns_sd.h | file | annotate | diff | comparison | revisions | |
| libpurple/protocols/bonjour/mdns_howl.c | file | annotate | diff | comparison | revisions | |
| libpurple/protocols/bonjour/mdns_howl.h | file | annotate | diff | comparison | revisions | |
| pidgin/pixmaps/emotes/default/22/default.theme.in | file | annotate | diff | comparison | revisions | |
| pidgin/pixmaps/emotes/default/22/theme | file | annotate | diff | comparison | revisions | |
| pidgin/pixmaps/emotes/none/none.theme.in | file | annotate | diff | comparison | revisions | |
| pidgin/pixmaps/emotes/none/theme | file | annotate | diff | comparison | revisions | |
| po/POTFILES.in | file | annotate | diff | comparison | revisions |
--- a/.mtn-ignore Thu Jun 14 19:48:48 2007 +0000 +++ b/.mtn-ignore Mon Jun 18 01:48:35 2007 +0000 @@ -5,12 +5,14 @@ .*/perl/common/blib.* .*/perl/common/pm_to_blib$ .*\.bs$ +.*\.def$ .*\.dll$ .*\.exe$ intltool-.* Doxyfile$ aclocal.m4 compile +config.cache config.guess config.h$ config.h.in @@ -30,7 +32,9 @@ pidgin.spec$ pidgin-.*.tar.gz pidgin-.*.tar.bz2 -pidgin/pidgin +pidgin/pidgin$ +pidgin/pixmaps/emotes/default/22/theme +pidgin/pixmaps/emotes/none/theme pidgin/plugins/musicmessaging/music-messaging-bindings.c pidgin/plugins/perl/common/Makefile.PL$ pidgin/win32/pidgin_dll_rc.rc$ @@ -50,7 +54,7 @@ libpurple/purple-client-bindings.h libpurple/purple-client-example libpurple/tests/check_libpurple -libpurple/version.h +libpurple/version.h$ libpurple/win32/libpurplerc.rc$ libtool local.mak
--- a/COPYRIGHT Thu Jun 14 19:48:48 2007 +0000 +++ b/COPYRIGHT Mon Jun 18 01:48:35 2007 +0000 @@ -8,6 +8,7 @@ Dave Ahlswede Manuel Amador Matt Amato +Elliott Sales de Andrade Geoffrey Antos Daniel Atallah Paul Aurich @@ -88,6 +89,7 @@ Jeramey Crawford Michael Culbertson Steven Danna +Chris Davies Martijn Dekker Vinicius Depizzol Philip Derrin @@ -129,6 +131,7 @@ Decklin Foster Francesco Fracassi Adam Fritzler +Takao Fujiwara Max G. François Gagné Andrew Gaul @@ -149,6 +152,7 @@ Casey Harkins Andy Harrison Andrew Hart (arhart) +Rene Hausleitner G. Sumner Hayes Michael R. Head Nick Hebner @@ -222,6 +226,7 @@ Lalo Martins John Matthews Simo Mattila +Michal Matyska Ryan McCabe Peter McCurdy Kurt McKee @@ -334,8 +339,10 @@ Richard Stellingwerff Charlie Stockman David Stoddard +Oleg Sukhodolsky Sun Microsystems Mårten Svantesson (fursten) +Amir Szekely (kichik) Robert T. Greg Taeger Peter Tang
--- a/ChangeLog Thu Jun 14 19:48:48 2007 +0000 +++ b/ChangeLog Mon Jun 18 01:48:35 2007 +0000 @@ -1,5 +1,35 @@ Pidgin and Finch: The Pimpin' Penguin IM Clients That're Good for the Soul +version 2.0.2 (06/14/2007): + Pidgin: + * Added a custom conversation font option to preferences + * Fixed smiley ordering in the insert smiley popup to be more intuitive + * Conversation->More menu items work for Chats as well as Buddies, + including those not on your buddy list + * newline plugin should work better with conversation colors plugin now + * Get Info on users now provides immediate feedback that something is + happening + * Aliasing a buddy will not be interrupted by other buddy list activity + * Using the -l option to log in to a specific account works better + + libpurple: + * Moving an ICQ buddy from one group to another no longer + re-requests authorization from that person (Rene Hausleitner) + * Added nullprpl, an example protocol plugin (Ryan Barrett) + * Fixed SOCKS5 bug which caused Jabber file receiving to fail + * Remove MSN's random "Authorization Failed" dialogs + * Fix MSN to correctly detect incorrect passwords and disable the account + * Get User Info on MSN is now more reliable & accurate + * Updated SILC protocol to support SILC Toolkit 1.1 (Pekka Riikonen) + * Fix for some QQ authentication problems + * Fix for building on FreeBSD + * Prevent "Logged in:" times for AIM buddies being ridiculously high + * Updates and fixes to Bonjour support + * Improve ICQ encoding support for some non-latin languages + + Finch: + * Auto account reconnecting + version 2.0.1 (05/24/2007): * Buddy list update speedups when buddy icons are not being displayed. (Scott Wolchok)
--- a/ChangeLog.API Thu Jun 14 19:48:48 2007 +0000 +++ b/ChangeLog.API Mon Jun 18 01:48:35 2007 +0000 @@ -1,5 +1,11 @@ Pidgin and Finch: The Pimpin' Penguin IM Clients That're Good for the Soul +version 2.0.2 (6/14/2007): + Pidgin: + Deprecated: + * pidgin_dialogs_alias_contact: This will be removed in 3.0.0 + unless there is sufficient demand to keep it. + version 2.0.0 (5/3/2007): Please note all functions, defines, and data structures have been re-namespaced to match the new names of Pidgin, Finch, and libpurple.
--- a/ChangeLog.win32 Thu Jun 14 19:48:48 2007 +0000 +++ b/ChangeLog.win32 Mon Jun 18 01:48:35 2007 +0000 @@ -1,4 +1,7 @@ -version 2.0.1 (??/??/????): +version 2.0.2 (6/14/2007): + * Add Bonjour protocol support thanks to Chris Davies. This requires + Apple Bonjour for Windows from: + http://www.apple.com/support/downloads/bonjourforwindows.html version 2.0.0 (5/3/2007): * URI Handler support added via `pidgin.exe --protocolhandler=`
--- a/NEWS Thu Jun 14 19:48:48 2007 +0000 +++ b/NEWS Mon Jun 18 01:48:35 2007 +0000 @@ -1,5 +1,18 @@ Pidgin and Finch: The Pimpin' Penguin IM Clients That're Good for the Soul +2.0.2 (6/14/2007): + Sean: Another big maintenance release. Again, about 100 tickets were + resolved in this release, and they keep coming in. Lots of bug fixes, + some minor icon adjustements, hopefully we addressed some ICQ + internationalization issues, and support for Bonjour on Windows! + Our next release will be 2.1.0, and will come with some great new + features. + + Stu: I think we're gradually getting the hang of this 3 week thing + again. This release includes yet more bug fixes. I'd also like to + specifically thank Pekka Riikonen for the patch to enable using SILC + Toolkit 1.1 with Pidgin/libpurple that is included in this release. + 2.0.1 (5/24/2007): Sean: 2.0.1! Three weeks later, as scheduled! It is so nice to have regular, frequent, releases again! This is a bugfix release; We have
--- a/config.h.mingw Thu Jun 14 19:48:48 2007 +0000 +++ b/config.h.mingw Mon Jun 18 01:48:35 2007 +0000 @@ -306,7 +306,7 @@ /* #undef HAVE_TZNAME */ /* Define to 1 if you have the <unistd.h> header file. */ -#define HAVE_UNISTD_H 1 +/*#define HAVE_UNISTD_H 1*/ /* Define to 1 if you have the `vprintf' function. */ #define HAVE_VPRINTF 1 @@ -344,9 +344,6 @@ /* Define to the version of this package. */ /* #define PACKAGE_VERSION "2.0.0dev" */ -/* Define to make assertions fatal (useful for debugging). */ -/* #define PURPLE_FATAL_ASSERTS 1 */ - /* Define if plugins are enabled. */ #define PURPLE_PLUGINS 1
--- a/configure.ac Thu Jun 14 19:48:48 2007 +0000 +++ b/configure.ac Mon Jun 18 01:48:35 2007 +0000 @@ -46,7 +46,7 @@ m4_define([purple_lt_current], [0]) m4_define([purple_major_version], [2]) m4_define([purple_minor_version], [0]) -m4_define([purple_micro_version], [1]) +m4_define([purple_micro_version], [2]) m4_define([purple_version_suffix], []) m4_define([purple_version], [purple_major_version.purple_minor_version.purple_micro_version]) @@ -55,7 +55,7 @@ m4_define([gnt_lt_current], [0]) m4_define([gnt_major_version], [1]) m4_define([gnt_minor_version], [0]) -m4_define([gnt_micro_version], [1]) +m4_define([gnt_micro_version], [2]) m4_define([gnt_version_suffix], []) m4_define([gnt_version], [gnt_major_version.gnt_minor_version.gnt_micro_version]) @@ -142,7 +142,7 @@ dnl If we don't have msgfmt, then po/ is going to fail -- ensure that dnl AM_GLIB_GNU_GETTEXT found it. -if test x$MSGFMT = xno -o x$GMSGFMT = x +if test x$MSGFMT = xno then AC_ERROR([ @@ -569,14 +569,15 @@ AC_ARG_ENABLE(gstreamer, [AC_HELP_STRING([--disable-gstreamer], [compile without GStreamer audio support])], enable_gst="$enableval", enable_gst="yes") -PKG_CHECK_MODULES(GSTREAMER, [gstreamer-0.10], , [ - AC_MSG_RESULT(no) - enable_gst="no" -]) if test "x$enable_gst" != "xno"; then - AC_DEFINE(USE_GSTREAMER, 1, [Use GStreamer for playing sounds]) - AC_SUBST(GSTREAMER_CFLAGS) - AC_SUBST(GSTREAMER_LIBS) + PKG_CHECK_MODULES(GSTREAMER, [gstreamer-0.10], [ + AC_DEFINE(USE_GSTREAMER, 1, [Use GStreamer for playing sounds]) + AC_SUBST(GSTREAMER_CFLAGS) + AC_SUBST(GSTREAMER_LIBS) + ], [ + AC_MSG_RESULT(no) + enable_gst="no" + ]) fi dnl ####################################################################### @@ -646,13 +647,14 @@ AC_ARG_WITH(silc-libs, [AC_HELP_STRING([--with-silc-libs=DIR], [compile the SILC plugin against the SILC libs in DIR])], [ac_silc_libs="$withval"], [ac_silc_libs="no"]) SILC_CFLAGS="" SILC_LIBS="" +have_silc="no" if test -n "$with_silc_includes" || test -n "$with_silc_libs"; then silc_manual_check="yes" else silc_manual_check="no" fi if test "x$silc_manual_check" = "xno"; then - PKG_CHECK_MODULES(SILC, silcclient, [ + PKG_CHECK_MODULES(SILC, [silcclient >= 1.1], [ have_silc="yes" silcincludes="yes" silcclient="yes" @@ -660,16 +662,26 @@ AC_MSG_RESULT(no) have_silc="no" ]) - dnl If silcclient.pc wasn't found, check for just silc.pc if test "x$have_silc" = "xno"; then - PKG_CHECK_MODULES(SILC, silc, [ + PKG_CHECK_MODULES(SILC, silcclient, [ have_silc="yes" - silcincludes="yes" - silcclient="yes" + silc10includes="yes" + silc10client="yes" ], [ AC_MSG_RESULT(no) have_silc="no" ]) + dnl If silcclient.pc wasn't found, check for just silc.pc + if test "x$have_silc" = "xno"; then + PKG_CHECK_MODULES(SILC, silc, [ + have_silc="yes" + silc10includes="yes" + silc10client="yes" + ], [ + AC_MSG_RESULT(no) + have_silc="no" + ]) + fi fi else if test "$ac_silc_includes" != "no"; then @@ -677,7 +689,7 @@ fi CPPFLAGS_save="$CPPFLAGS" CPPFLAGS="$CPPFLAGS $SILC_CFLAGS" - AC_CHECK_HEADER(silcincludes.h, [silcincludes=yes]) + AC_CHECK_HEADER(silc.h, [silcincludes=yes]) CPPFLAGS="$CPPFLAGS_save" if test "$ac_silc_libs" != "no"; then @@ -685,11 +697,28 @@ fi SILC_LIBS="$SILC_LIBS -lsilc -lsilcclient -lpthread $LIBDL" AC_CHECK_LIB(silcclient, silc_client_init, [silcclient=yes], , $SILC_LIBS) + + if test "x$silcincludes" = "xyes" -a "x$silcclient" = "xyes"; then + have_silc="yes" + else + CPPFLAGS_save="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $SILC_CFLAGS" + AC_CHECK_HEADER(silcincludes.h, [silc10includes=yes]) + CPPFLAGS="$CPPFLAGS_save" + + SILC_LIBS="$SILC_LIBS -lsilc -lsilcclient -lpthread $LIBDL" + AC_CHECK_LIB(silcclient, silc_client_init, [silc10client=yes], , $SILC_LIBS) + if test "x$silc10includes" = "xyes" -a "x$silc10client" = "xyes"; then + have_silc="yes" + fi + fi fi AC_SUBST(SILC_LIBS) AC_SUBST(SILC_CFLAGS) dnl SILC Toolkit >= 1.0.1 has a new MIME API if test "x$silcclient" = "xyes"; then + AC_DEFINE(HAVE_SILCMIME_H, 1, [Define if we have silcmime.h]) +elif test "x$silc10client" = "xyes"; then CPPFLAGS_save="$CPPFLAGS" CPPFLAGS="$CPPFLAGS $SILC_CFLAGS" AC_MSG_CHECKING(for silcmime.h) @@ -794,7 +823,10 @@ STATIC_PRPLS=`echo $STATIC_PRPLS | $sedpath 's/bonjour//'` fi if test "x$silcincludes" != "xyes" -o "x$silcclient" != "xyes"; then - STATIC_PRPLS=`echo $STATIC_PRPLS | $sedpath 's/silc//'` + STATIC_PRPLS=`echo $STATIC_PRPLS | $sedpath 's/silc/silc10/'` +fi +if test "x$silc10includes" != "xyes" -o "x$silc10client" != "xyes"; then + STATIC_PRPLS=`echo $STATIC_PRPLS | $sedpath 's/silc10//'` fi AC_SUBST(STATIC_PRPLS) STATIC_LINK_LIBS= @@ -802,13 +834,24 @@ load_proto= for i in $STATIC_PRPLS ; do dnl Ugly special case for "libsilcpurple.a": - if test "x$i" = "xsilc"; then - STATIC_LINK_LIBS="$STATIC_LINK_LIBS protocols/$i/lib${i}purple.a" + dnl ... and Ugly special case for multi-protocol oscar + if test \( "x$i" = "xoscar" -o "x$i" = "xaim" -o "x$i" = "xicq" \) -a "x$static_oscar" != "xyes"; then + STATIC_LINK_LIBS="$STATIC_LINK_LIBS \$(top_builddir)/libpurple/protocols/oscar/liboscar.a" + extern_init="$extern_init extern gboolean purple_init_aim_plugin();" + extern_init="$extern_init extern gboolean purple_init_icq_plugin();" + load_proto="$load_proto purple_init_aim_plugin();" + load_proto="$load_proto purple_init_icq_plugin();" else - STATIC_LINK_LIBS="$STATIC_LINK_LIBS protocols/$i/lib$i.a" + if test "x$i" = "xsilc"; then + STATIC_LINK_LIBS="$STATIC_LINK_LIBS \$(top_builddir)/libpurple/protocols/$i/lib${i}purple.a" + elif test "x$i" = "xsilc10"; then + STATIC_LINK_LIBS="$STATIC_LINK_LIBS \$(top_builddir)/libpurple/protocols/$i/libsilcpurple.a" + else + STATIC_LINK_LIBS="$STATIC_LINK_LIBS \$(top_builddir)/libpurple/protocols/$i/lib$i.a" + fi + extern_init="$extern_init extern gboolean purple_init_${i}_plugin();" + load_proto="$load_proto purple_init_${i}_plugin();" fi - extern_init="$extern_init extern gboolean purple_init_${i}_plugin();" - load_proto="$load_proto purple_init_${i}_plugin();" case $i in bonjour) static_bonjour=yes ;; gg) static_gg=yes ;; @@ -823,6 +866,7 @@ qq) static_qq=yes ;; sametime) static_sametime=yes ;; silc) static_silc=yes ;; + silc10) static_silc=yes ;; simple) static_simple=yes ;; toc) static_toc=yes ;; yahoo) static_yahoo=yes ;; @@ -840,7 +884,7 @@ AM_CONDITIONAL(STATIC_OSCAR, test "x$static_oscar" = "xyes") AM_CONDITIONAL(STATIC_QQ, test "x$static_qq" = "xyes") AM_CONDITIONAL(STATIC_SAMETIME, test "x$static_sametime" = "xyes" -a "x$have_meanwhile" = "xyes") -AM_CONDITIONAL(STATIC_SILC, test "x$static_silc" = "xyes" -a "x$silcincludes" = "xyes" -a "x$silcclient" = "xyes") +AM_CONDITIONAL(STATIC_SILC, test "x$static_silc" = "xyes" -a "x$have_silc" = "xyes") AM_CONDITIONAL(STATIC_SIMPLE, test "x$static_simple" = "xyes") AM_CONDITIONAL(STATIC_TOC, test "x$static_toc" = "xyes") AM_CONDITIONAL(STATIC_YAHOO, test "x$static_yahoo" = "xyes") @@ -860,7 +904,10 @@ DYNAMIC_PRPLS=`echo $DYNAMIC_PRPLS | $sedpath 's/bonjour//'` fi if test "x$silcincludes" != "xyes" -o "x$silcclient" != "xyes"; then - DYNAMIC_PRPLS=`echo $DYNAMIC_PRPLS | $sedpath 's/silc//'` + DYNAMIC_PRPLS=`echo $DYNAMIC_PRPLS | $sedpath 's/silc/silc10/'` +fi +if test "x$silc10includes" != "xyes" -o "x$silc10client" != "xyes"; then + DYNAMIC_PRPLS=`echo $DYNAMIC_PRPLS | $sedpath 's/silc10//'` fi AC_SUBST(DYNAMIC_PRPLS) for i in $DYNAMIC_PRPLS ; do @@ -878,6 +925,7 @@ qq) dynamic_qq=yes ;; sametime) dynamic_sametime=yes ;; silc) dynamic_silc=yes ;; + silc10) dynamic_silc=yes ;; simple) dynamic_simple=yes ;; toc) dynamic_toc=yes ;; yahoo) dynamic_yahoo=yes ;; @@ -895,7 +943,7 @@ AM_CONDITIONAL(DYNAMIC_OSCAR, test "x$dynamic_oscar" = "xyes") AM_CONDITIONAL(DYNAMIC_QQ, test "x$dynamic_qq" = "xyes") AM_CONDITIONAL(DYNAMIC_SAMETIME, test "x$dynamic_sametime" = "xyes" -a "x$have_meanwhile" = "xyes") -AM_CONDITIONAL(DYNAMIC_SILC, test "x$dynamic_silc" = "xyes" -a "x$silcincludes" = "xyes" -a "x$silcclient" = "xyes") +AM_CONDITIONAL(DYNAMIC_SILC, test "x$dynamic_silc" = "xyes" -a "x$have_silc" = "xyes") AM_CONDITIONAL(DYNAMIC_SIMPLE, test "x$dynamic_simple" = "xyes") AM_CONDITIONAL(DYNAMIC_TOC, test "x$dynamic_toc" = "xyes") AM_CONDITIONAL(DYNAMIC_YAHOO, test "x$dynamic_yahoo" = "xyes") @@ -2060,6 +2108,8 @@ pidgin/pixmaps/tray/16/scalable/Makefile pidgin/pixmaps/tray/22/Makefile pidgin/pixmaps/tray/22/scalable/Makefile + pidgin/pixmaps/tray/32/Makefile + pidgin/pixmaps/tray/48/Makefile pidgin/plugins/Makefile pidgin/plugins/cap/Makefile pidgin/plugins/gestures/Makefile @@ -2090,10 +2140,12 @@ libpurple/protocols/msn/Makefile libpurple/protocols/myspace/Makefile libpurple/protocols/novell/Makefile + libpurple/protocols/null/Makefile libpurple/protocols/oscar/Makefile libpurple/protocols/qq/Makefile libpurple/protocols/sametime/Makefile libpurple/protocols/silc/Makefile + libpurple/protocols/silc10/Makefile libpurple/protocols/simple/Makefile libpurple/protocols/toc/Makefile libpurple/protocols/yahoo/Makefile
--- a/doc/funniest_home_convos.txt Thu Jun 14 19:48:48 2007 +0000 +++ b/doc/funniest_home_convos.txt Mon Jun 18 01:48:35 2007 +0000 @@ -471,4 +471,6 @@ 14:08 <elb> "... yes" 14:08 <elb> I mean, what do you say 14:08 <Robot101> elb: was their nick "idi"? - + +19:23 <-- elb has quit (K-lined) +
--- a/finch/gntaccount.c Thu Jun 14 19:48:48 2007 +0000 +++ b/finch/gntaccount.c Mon Jun 18 01:48:35 2007 +0000 @@ -717,6 +717,15 @@ gnt_tree_remove(GNT_TREE(accounts.tree), account); } +static void +account_abled_cb(PurpleAccount *account, gpointer user_data) +{ + if (accounts.window == NULL) + return; + gnt_tree_set_choice(GNT_TREE(accounts.tree), account, + GPOINTER_TO_INT(user_data)); +} + void finch_accounts_init() { GList *iter; @@ -727,7 +736,13 @@ purple_signal_connect(purple_accounts_get_handle(), "account-removed", finch_accounts_get_handle(), PURPLE_CALLBACK(account_removed_callback), NULL); - + purple_signal_connect(purple_accounts_get_handle(), "account-disabled", + finch_accounts_get_handle(), + PURPLE_CALLBACK(account_abled_cb), GINT_TO_POINTER(FALSE)); + purple_signal_connect(purple_accounts_get_handle(), "account-enabled", + finch_accounts_get_handle(), + PURPLE_CALLBACK(account_abled_cb), GINT_TO_POINTER(TRUE)); + for (iter = purple_accounts_get_all(); iter; iter = iter->next) { if (purple_account_get_enabled(iter->data, FINCH_UI)) break;
--- a/finch/gntconn.c Thu Jun 14 19:48:48 2007 +0000 +++ b/finch/gntconn.c Mon Jun 18 01:48:35 2007 +0000 @@ -24,34 +24,116 @@ */ #include "account.h" #include "core.h" +#include "connection.h" +#include "debug.h" #include "request.h" #include "gntconn.h" #include "finch.h" +#define INITIAL_RECON_DELAY_MIN 8000 +#define INITIAL_RECON_DELAY_MAX 60000 + +#define MAX_RECON_DELAY 600000 + +typedef struct { + int delay; + guint timeout; +} FinchAutoRecon; + +/** + * Contains accounts that are auto-reconnecting. + * The key is a pointer to the PurpleAccount and the + * value is a pointer to a FinchAutoRecon. + */ +static GHashTable *hash = NULL; + +static void +free_auto_recon(gpointer data) +{ + FinchAutoRecon *info = data; + + if (info->timeout != 0) + g_source_remove(info->timeout); + + g_free(info); +} + + +static gboolean +do_signon(gpointer data) +{ + PurpleAccount *account = data; + FinchAutoRecon *info; + PurpleStatus *status; + + purple_debug_info("autorecon", "do_signon called\n"); + g_return_val_if_fail(account != NULL, FALSE); + info = g_hash_table_lookup(hash, account); + + if (info) + info->timeout = 0; + + status = purple_account_get_active_status(account); + if (purple_status_is_online(status)) + { + purple_debug_info("autorecon", "calling purple_account_connect\n"); + purple_account_connect(account); + purple_debug_info("autorecon", "done calling purple_account_connect\n"); + } + + return FALSE; +} + static void finch_connection_report_disconnect(PurpleConnection *gc, const char *text) { - char *act, *primary, *secondary; + FinchAutoRecon *info; PurpleAccount *account = purple_connection_get_account(gc); - act = g_strdup_printf(_("%s (%s)"), purple_account_get_username(account), - purple_account_get_protocol_name(account)); + info = g_hash_table_lookup(hash, account); - primary = g_strdup_printf(_("%s disconnected."), act); - secondary = g_strdup_printf(_("%s was disconnected due to the following error:\n%s"), - act, text); + if (!gc->wants_to_die) { + if (info == NULL) { + info = g_new0(FinchAutoRecon, 1); + g_hash_table_insert(hash, account, info); + info->delay = g_random_int_range(INITIAL_RECON_DELAY_MIN, INITIAL_RECON_DELAY_MAX); + } else { + info->delay = MIN(2 * info->delay, MAX_RECON_DELAY); + if (info->timeout != 0) + g_source_remove(info->timeout); + } + info->timeout = g_timeout_add(info->delay, do_signon, account); + } else { + char *act, *primary, *secondary; + act = g_strdup_printf(_("%s (%s)"), purple_account_get_username(account), + purple_account_get_protocol_name(account)); - purple_request_action(account, _("Connection Error"), primary, secondary, 1, - account, NULL, NULL, - account, 2, - _("OK"), NULL, - _("Connect"), - PURPLE_CALLBACK(purple_account_connect)); + primary = g_strdup_printf(_("%s disconnected."), act); + secondary = g_strdup_printf(_("%s\n\n" + "Finch will not attempt to reconnect the account until you " + "correct the error and re-enable the account."), text); + purple_notify_error(NULL, NULL, primary, secondary); + + g_free(act); + g_free(primary); + g_free(secondary); + purple_account_set_enabled(account, FINCH_UI, FALSE); + } +} - g_free(act); - g_free(primary); - g_free(secondary); +static void +account_removed_cb(PurpleAccount *account, gpointer user_data) +{ + g_hash_table_remove(hash, account); +} + +static void * +finch_connection_get_handle(void) +{ + static int handle; + + return &handle; } static PurpleConnectionUiOps ops = @@ -75,8 +157,18 @@ } void finch_connections_init() -{} +{ + hash = g_hash_table_new_full( + g_direct_hash, g_direct_equal, + NULL, free_auto_recon); + + purple_signal_connect(purple_accounts_get_handle(), "account-removed", + finch_connection_get_handle(), + PURPLE_CALLBACK(account_removed_cb), NULL); +} void finch_connections_uninit() -{} - +{ + purple_signals_disconnect_by_handle(finch_connection_get_handle()); + g_hash_table_destroy(hash); +}
--- a/finch/gntrequest.c Thu Jun 14 19:48:48 2007 +0000 +++ b/finch/gntrequest.c Mon Jun 18 01:48:35 2007 +0000 @@ -672,10 +672,13 @@ pt = purple_prefs_get_type(id); switch (pt) { case PURPLE_PREF_INT: + { + long int tmp; if (type == PURPLE_REQUEST_FIELD_LIST) /* Lists always return string */ - sscanf(val, "%ld", (long int *)&val); - purple_prefs_set_int(id, GPOINTER_TO_INT(val)); + sscanf(val, "%ld", &tmp); + purple_prefs_set_int(id, (gint)tmp); break; + } case PURPLE_PREF_BOOLEAN: purple_prefs_set_bool(id, GPOINTER_TO_INT(val)); break;
--- a/libpurple/Makefile.mingw Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/Makefile.mingw Mon Jun 18 01:48:35 2007 +0000 @@ -72,6 +72,7 @@ upnp.c \ util.c \ value.c \ + version.c \ xmlnode.c \ whiteboard.c \ win32/giowin32.c \ @@ -120,7 +121,7 @@ $(OBJECTS): $(PURPLE_CONFIG_H) $(PURPLE_VERSION_H) $(TARGET).dll $(TARGET).dll.a: $(OBJECTS) - $(CC) -shared $(OBJECTS) $(LIB_PATHS) $(LIBS) $(DLL_LD_FLAGS) -Wl,--out-implib,$(TARGET).dll.a -o $(TARGET).dll + $(CC) -shared $(OBJECTS) $(LIB_PATHS) $(LIBS) $(DLL_LD_FLAGS) -Wl,--output-def,$(TARGET).def,--out-implib,$(TARGET).dll.a -o $(TARGET).dll ## ## CLEAN RULES
--- a/libpurple/blist.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/blist.c Mon Jun 18 01:48:35 2007 +0000 @@ -1774,7 +1774,7 @@ node = (PurpleBlistNode *)buddy; cnode = node->parent; - gnode = cnode->parent; + gnode = (cnode != NULL) ? cnode->parent : NULL; contact = (PurpleContact *)cnode; group = (PurpleGroup *)gnode; @@ -1783,35 +1783,37 @@ node->prev->next = node->next; if (node->next) node->next->prev = node->prev; - if (cnode->child == node) + if ((cnode != NULL) && (cnode->child == node)) cnode->child = node->next; /* Adjust size counts */ - if (PURPLE_BUDDY_IS_ONLINE(buddy)) { - contact->online--; - if (contact->online == 0) - group->online--; + if (contact != NULL) { + if (PURPLE_BUDDY_IS_ONLINE(buddy)) { + contact->online--; + if (contact->online == 0) + group->online--; + } + if (purple_account_is_connected(buddy->account)) { + contact->currentsize--; + if (contact->currentsize == 0) + group->currentsize--; + } + contact->totalsize--; + + /* Re-sort the contact */ + if (cnode->child && contact->priority == buddy) { + purple_contact_invalidate_priority_buddy(contact); + if (ops && ops->update) + ops->update(purplebuddylist, cnode); + } } - if (purple_account_is_connected(buddy->account)) { - contact->currentsize--; - if (contact->currentsize == 0) - group->currentsize--; - } - contact->totalsize--; purple_blist_schedule_save(); - /* Re-sort the contact */ - if (cnode->child && contact->priority == buddy) { - purple_contact_invalidate_priority_buddy(contact); - if (ops && ops->update) - ops->update(purplebuddylist, cnode); - } - /* Remove this buddy from the buddies hash table */ hb.name = g_strdup(purple_normalize(buddy->account, buddy->name)); hb.account = buddy->account; - hb.group = ((PurpleBlistNode*)buddy)->parent->parent; + hb.group = gnode; g_hash_table_remove(purplebuddylist->buddies, &hb); g_free(hb.name); @@ -1841,7 +1843,7 @@ while (g_source_remove_by_user_data((gpointer *)buddy)); /* If the contact is empty then remove it */ - if (!cnode->child) + if ((contact != NULL) && !cnode->child) purple_blist_remove_contact(contact); }
--- a/libpurple/cipher.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/cipher.c Mon Jun 18 01:48:35 2007 +0000 @@ -1447,14 +1447,14 @@ * Structs ******************************************************************************/ struct _PurpleCipher { - gchar *name; - PurpleCipherOps *ops; - guint ref; + gchar *name; /**< Internal name - used for searching */ + PurpleCipherOps *ops; /**< Operations supported by this cipher */ + guint ref; /**< Reference count */ }; struct _PurpleCipherContext { - PurpleCipher *cipher; - gpointer data; + PurpleCipher *cipher; /**< Cipher this context is under */ + gpointer data; /**< Internal cipher state data */ }; /******************************************************************************
--- a/libpurple/connection.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/connection.c Mon Jun 18 01:48:35 2007 +0000 @@ -436,7 +436,7 @@ g_return_if_fail(gc != NULL); if (text == NULL) { - g_critical("purple_connection_error: check `text != NULL' failed"); + purple_debug_error("connection", "purple_connection_error: check `text != NULL' failed"); text = _("Unknown error"); }
--- a/libpurple/connection.h Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/connection.h Mon Jun 18 01:48:35 2007 +0000 @@ -279,7 +279,7 @@ * TODO: Eventually this bad boy will be removed, because it is * a gross fix for a crashy problem. */ -#define PURPLE_CONNECTION_IS_VALID(gc) (g_list_find(purple_connections_get_all(), (gc))) +#define PURPLE_CONNECTION_IS_VALID(gc) (g_list_find(purple_connections_get_all(), (gc)) != NULL) /*@}*/
--- a/libpurple/conversation.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/conversation.c Mon Jun 18 01:48:35 2007 +0000 @@ -1535,20 +1535,22 @@ PurpleConvChatBuddyFlags flag = GPOINTER_TO_INT(fl->data); const char *extra_msg = (extra_msgs ? extra_msgs->data : NULL); - if (!strcmp(chat->nick, purple_normalize(conv->account, user))) { - const char *alias2 = purple_account_get_alias(conv->account); - if (alias2 != NULL) - alias = alias2; - else - { - const char *display_name = purple_connection_get_display_name(gc); - if (display_name != NULL) - alias = display_name; + if(!(prpl_info->options & OPT_PROTO_UNIQUE_CHATNAME)) { + if (!strcmp(chat->nick, purple_normalize(conv->account, user))) { + const char *alias2 = purple_account_get_alias(conv->account); + if (alias2 != NULL) + alias = alias2; + else + { + const char *display_name = purple_connection_get_display_name(gc); + if (display_name != NULL) + alias = display_name; + } + } else { + PurpleBuddy *buddy; + if ((buddy = purple_find_buddy(gc->account, user)) != NULL) + alias = purple_buddy_get_contact_alias(buddy); } - } else if (!(prpl_info->options & OPT_PROTO_UNIQUE_CHATNAME)) { - PurpleBuddy *buddy; - if ((buddy = purple_find_buddy(gc->account, user)) != NULL) - alias = purple_buddy_get_contact_alias(buddy); } quiet = GPOINTER_TO_INT(purple_signal_emit_return_1(purple_conversations_get_handle(), @@ -1633,14 +1635,16 @@ /* Note this for later. */ is_me = TRUE; - alias = purple_account_get_alias(conv->account); - if (alias != NULL) - new_alias = alias; - else - { - const char *display_name = purple_connection_get_display_name(gc); - if (display_name != NULL) - alias = display_name; + if(!(prpl_info->options & OPT_PROTO_UNIQUE_CHATNAME)) { + alias = purple_account_get_alias(conv->account); + if (alias != NULL) + new_alias = alias; + else + { + const char *display_name = purple_connection_get_display_name(gc); + if (display_name != NULL) + alias = display_name; + } } } else if (!(prpl_info->options & OPT_PROTO_UNIQUE_CHATNAME)) { PurpleBuddy *buddy; @@ -1806,7 +1810,7 @@ if (ops != NULL && ops->chat_remove_users != NULL) { for (l = users; l; l = l->next) { PurpleConvChatBuddy *cb = l->data; - names = g_list_append(names, cb->name); + names = g_list_prepend(names, cb->name); } ops->chat_remove_users(conv, names); g_list_free(names); @@ -1960,7 +1964,7 @@ for (l = purple_conv_chat_get_users(chat); l; l = l->next) { cb = l->data; - if (!purple_utf8_strcasecmp(cb->name, name)) + if (!g_utf8_collate(cb->name, name)) return cb; }
--- a/libpurple/dbus-analyze-functions.py Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/dbus-analyze-functions.py Mon Jun 18 01:48:35 2007 +0000 @@ -2,7 +2,6 @@ import string import sys - # types translated into "int" simpletypes = ["int", "gint", "guint", "gboolean"] @@ -166,8 +165,11 @@ self.returncode = [] def flush(self): + paramslist = ", ".join(self.paramshdr) + if (paramslist == "") : + paramslist = "void" print "%s %s(%s)" % (self.functiontype, self.function.name, - ", ".join(self.paramshdr)), + paramslist), if self.headersonly: print ";" @@ -277,7 +279,7 @@ for decl in self.cdecls: print decl - print "\t%s(message_DBUS, error_DBUS, " % self.argfunc, + print "\t%s(message_DBUS, error_DBUS," % self.argfunc, for param in self.cparams: print "DBUS_TYPE_%s, &%s," % param, print "DBUS_TYPE_INVALID);" @@ -287,14 +289,14 @@ for code in self.ccode: print code - print "\treply_DBUS = dbus_message_new_method_return (message_DBUS);" + print "\treply_DBUS = dbus_message_new_method_return (message_DBUS);" - print "\tdbus_message_append_args(reply_DBUS, ", + print "\tdbus_message_append_args(reply_DBUS,", for param in self.cparamsout: if type(param) is str: - print "%s, " % param + print "%s," % param else: - print "DBUS_TYPE_%s, &%s, " % param, + print "DBUS_TYPE_%s, &%s," % param, print "DBUS_TYPE_INVALID);" for code in self.ccodeout: @@ -359,8 +361,12 @@ self.ccode.append("\t%s;" % self.call) # just call the function def outputstring(self, type, name, const): - self.cdecls.append("\tconst char *%s;" % name) - self.ccode.append("\t%s = null_to_empty(%s);" % (name, self.call)) + if const: + self.cdecls.append("\tconst char *%s;" % name) + else: + self.cdecls.append("\tchar *%s;" % name) + self.ccode.append("\tif ((%s = %s) == NULL)" % (name, self.call)) + self.ccode.append("\t\t%s = \"\";" % (name)) self.cparamsout.append(("STRING", name)) self.addouttype("s", name) if not const:
--- a/libpurple/dbus-bindings.h Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/dbus-bindings.h Mon Jun 18 01:48:35 2007 +0000 @@ -35,9 +35,9 @@ extern "C" { #endif -gint purple_dbus_pointer_to_id(gpointer node); +gint purple_dbus_pointer_to_id(gconstpointer node); gpointer purple_dbus_id_to_pointer(gint id, PurpleDBusType *type); -gint purple_dbus_pointer_to_id_error(gpointer ptr, DBusError *error); +gint purple_dbus_pointer_to_id_error(gconstpointer ptr, DBusError *error); gpointer purple_dbus_id_to_pointer_error(gint id, PurpleDBusType *type, const char *typename, DBusError *error);
--- a/libpurple/dbus-server.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/dbus-server.c Mon Jun 18 01:48:35 2007 +0000 @@ -108,14 +108,14 @@ } gint -purple_dbus_pointer_to_id(gpointer node) +purple_dbus_pointer_to_id(gconstpointer node) { gint id = GPOINTER_TO_INT(g_hash_table_lookup(map_node_id, node)); if ((id == 0) && (node != NULL)) { purple_debug_warning("dbus", "Need to register an object with the dbus subsystem.\n"); - g_return_val_if_reached(0); + return 0; } return id; } @@ -138,7 +138,7 @@ } gint -purple_dbus_pointer_to_id_error(gpointer ptr, DBusError *error) +purple_dbus_pointer_to_id_error(gconstpointer ptr, DBusError *error) { gint id = purple_dbus_pointer_to_id(ptr);
--- a/libpurple/idle.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/idle.c Mon Jun 18 01:48:35 2007 +0000 @@ -92,7 +92,7 @@ } -static int no_away = 0; +static gboolean no_away = FALSE; static gint time_until_next_idle_event; /* * This function should be called when you think your idle state @@ -118,15 +118,15 @@ time_t time_idle; gboolean auto_away; const gchar *idle_reporting; - gboolean report_idle; - GList *l; + gboolean report_idle = TRUE; gint away_seconds = 0; - gint idle_recheck_interval; + gint idle_recheck_interval = 0; purple_signal_emit(purple_blist_get_handle(), "update-idle"); idle_reporting = purple_prefs_get_string("/purple/away/idle_reporting"); - report_idle = TRUE; + auto_away = purple_prefs_get_bool("/purple/away/away_when_idle"); + if (!strcmp(idle_reporting, "system") && (idle_ui_ops != NULL) && (idle_ui_ops->get_time_idle != NULL)) { @@ -145,15 +145,9 @@ /* Don't report idle time */ time_idle = 0; report_idle = FALSE; - } - /* Auto-away stuff */ - auto_away = purple_prefs_get_bool("/purple/away/away_when_idle"); - - /* If we're not reporting idle, we can still do auto-away. - * First try "system" and if that isn't possible, use "purple" */ - if (!report_idle) - { + /* If we're not reporting idle, we can still do auto-away. + * First try "system" and if that isn't possible, use "purple" */ if (auto_away) { if ((idle_ui_ops != NULL) && (idle_ui_ops->get_time_idle != NULL)) @@ -172,7 +166,7 @@ if (!no_away) { purple_savedstatus_set_idleaway(FALSE); - no_away = 1; + no_away = TRUE; } time_until_next_idle_event = 0; return; @@ -192,11 +186,11 @@ if (auto_away && time_idle > away_seconds) { purple_savedstatus_set_idleaway(TRUE); - no_away = 0; + no_away = FALSE; } else if (!no_away && time_idle < away_seconds) { - no_away = 1; + no_away = TRUE; purple_savedstatus_set_idleaway(FALSE); if (time_until_next_idle_event == 0 || (away_seconds - time_idle) < time_until_next_idle_event) time_until_next_idle_event = away_seconds - time_idle; @@ -205,6 +199,7 @@ /* Idle reporting stuff */ if (report_idle && (time_idle >= IDLEMARK)) { + GList *l; for (l = purple_connections_get_all(); l != NULL; l = l->next) { PurpleConnection *gc = l->data; @@ -305,6 +300,14 @@ return &handle; } +static gboolean _do_purple_idle_touch_cb(gpointer data) +{ + purple_idle_touch(); + + return FALSE; +} + + void purple_idle_init() { @@ -324,7 +327,10 @@ purple_prefs_connect_callback(purple_idle_get_handle(), "/purple/away/idle_reporting", idle_reporting_cb, NULL); - purple_idle_touch(); + /* Initialize the idleness asynchronously so it doesn't check idleness, + * and potentially try to change the status before the UI is initialized */ + g_idle_add(_do_purple_idle_touch_cb, NULL); + } void
--- a/libpurple/network.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/network.c Mon Jun 18 01:48:35 2007 +0000 @@ -598,8 +598,6 @@ void nm_callback_func(libnm_glib_ctx* ctx, gpointer user_data) { - GList *l; - PurpleAccount *account; static libnm_glib_state prev = LIBNM_NO_DBUS; libnm_glib_state current; PurpleConnectionUiOps *ui_ops = purple_connections_get_ui_ops();
--- a/libpurple/notify.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/notify.c Mon Jun 18 01:48:35 2007 +0000 @@ -749,18 +749,16 @@ void purple_notify_close_with_handle(void *handle) { - GList *l, *l_next; + GList *l, *prev = NULL; PurpleNotifyUiOps *ops; g_return_if_fail(handle != NULL); ops = purple_notify_get_ui_ops(); - for (l = handles; l != NULL; l = l_next) { + for (l = handles; l != NULL; l = prev ? prev->next : handles) { PurpleNotifyInfo *info = l->data; - l_next = l->next; - if (info->handle == handle) { handles = g_list_remove(handles, info); @@ -771,7 +769,8 @@ info->cb(info->cb_user_data); g_free(info); - } + } else + prev = l; } }
--- a/libpurple/plugins/Makefile.mingw Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/plugins/Makefile.mingw Mon Jun 18 01:48:35 2007 +0000 @@ -63,6 +63,7 @@ autoaccept.dll \ buddynote.dll \ idle.dll \ + joinpart.dll \ log_reader.dll \ newline.dll \ offlinemsg.dll \
--- a/libpurple/plugins/buddynote.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/plugins/buddynote.c Mon Jun 18 01:48:35 2007 +0000 @@ -58,6 +58,9 @@ { PurpleMenuAction *bna = NULL; + if (purple_blist_node_get_flags(node) & PURPLE_BLIST_NODE_FLAG_NO_SAVE) + return; + *m = g_list_append(*m, bna); bna = purple_menu_action_new(_("Edit Notes..."), PURPLE_CALLBACK(buddynote_edit_cb), NULL, NULL); *m = g_list_append(*m, bna);
--- a/libpurple/plugins/joinpart.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/plugins/joinpart.c Mon Jun 18 01:48:35 2007 +0000 @@ -210,7 +210,7 @@ * we don't have to worry one will be called after this. */ g_hash_table_destroy((GHashTable *)data[0]); - g_source_remove(GPOINTER_TO_UINT(data[1])); + purple_timeout_remove(GPOINTER_TO_UINT(data[1])); g_free(data); return TRUE;
--- a/libpurple/plugins/log_reader.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/plugins/log_reader.c Mon Jun 18 01:48:35 2007 +0000 @@ -1425,7 +1425,7 @@ char *escaped; GString *formatted; char *c; - char *line; + const char *line; g_return_val_if_fail(log != NULL, g_strdup("")); @@ -1460,221 +1460,234 @@ read = escaped; /* Apply formatting... */ - formatted = g_string_new(""); + formatted = g_string_sized_new(strlen(read)); c = read; line = read; - while (*c) + while (c) { - if (*c == '\n') - { - char *link_temp_line; - char *link; - char *timestamp; - char *footer = NULL; - *c = '\0'; + const char *link; + const char *footer = NULL; + GString *temp = NULL; - /* Convert links. - * - * The format is (Link: URL)URL - * So, I want to find each occurance of "(Link: " and replace that chunk with: - * <a href=" - * Then, replace the next ")" with: - * "> - * Then, replace the next " " (or add this if the end-of-line is reached) with: - * </a> - */ - link_temp_line = NULL; - while ((link = g_strstr_len(line, strlen(line), "(Link: "))) { - GString *temp; - - if (!*link) - continue; - - *link = '\0'; - link++; - - temp = g_string_new(line); - g_string_append(temp, "<a href=\""); - - if (strlen(link) >= 6) { - link += (sizeof("(Link: ") - 1); + if ((c = strstr(c, "\n"))) + { + *c = '\0'; + c++; + } - while (*link && *link != ')') { - g_string_append_c(temp, *link); - link++; - } - if (link) { - link++; - - g_string_append(temp, "\">"); - while (*link && *link != ' ') { - g_string_append_c(temp, *link); - link++; - } - g_string_append(temp, "</a>"); - } - - g_string_append(temp, link); - - /* Free the last round's line. */ - if (link_temp_line) - g_free(line); + /* Convert links. + * + * The format is (Link: URL)URL + * So, I want to find each occurance of "(Link: " and replace that chunk with: + * <a href=" + * Then, replace the next ")" with: + * "> + * Then, replace the next " " (or add this if the end-of-line is reached) with: + * </a> + * + * As implemented, this isn't perfect, but it should cover common cases. + */ + while (line && (link = strstr(line, "(Link: "))) + { + const char *tmp = link; - line = temp->str; - g_string_free(temp, FALSE); - - /* Save this memory location so we can free it later. */ - link_temp_line = line; - } - } + link += 7; + if (*link) + { + char *end_paren; + char *space; - timestamp = ""; - if (*line == '[') { - timestamp = line; - while (*timestamp && *timestamp != ']') - timestamp++; - if (*timestamp == ']') { - *timestamp = '\0'; - line++; - /* TODO: Parse the timestamp and convert it to Purple's format. */ - g_string_append_printf(formatted, - "<font size=\"2\">(%s)</font> ", line); - line = timestamp; - if (line[1] && line[2]) - line += 2; + if (!(end_paren = strstr(link, ")"))) + { + /* Something is not as we expect. Bail out. */ + break; } - if (purple_str_has_prefix(line, "*** ")) { - line += (sizeof("*** ") - 1); - g_string_append(formatted, "<b>"); - footer = "</b>"; - if (purple_str_has_prefix(line, "NOTE: This user is offline.")) { - line = _("User is offline."); - } else if (purple_str_has_prefix(line, - "NOTE: Your status is currently set to ")) { + if (!temp) + temp = g_string_sized_new(c ? (c - 1 - line) : strlen(line)); + + g_string_append_len(temp, line, (tmp - line)); + + /* Start an <a> tag. */ + g_string_append(temp, "<a href=\""); + + /* Append up to the ) */ + g_string_append_len(temp, link, end_paren - link); + + /* Finish the <a> tag. */ + g_string_append(temp, "\">"); + + /* The \r is a bit of a hack to keep there from being a \r in + * the link text, which may not matter. */ + if ((space = strstr(end_paren, " ")) || (space = strstr(end_paren, "\r"))) + { + g_string_append_len(temp, end_paren + 1, space - end_paren - 1); + + /* Close the <a> tag. */ + g_string_append(temp, "</a>"); + + space++; + } + else + { + /* There is no space before the end of the line. */ + g_string_append(temp, end_paren + 1); + /* Close the <a> tag. */ + g_string_append(temp, "</a>"); + } + line = space; + } + else + { + /* Something is not as we expect. Bail out. */ + break; + } + } + + if (temp) + { + if (line) + g_string_append(temp, line); + line = temp->str; + } + + if (*line == '[') { + const char *timestamp; + + if ((timestamp = strstr(line, "]"))) { + line++; + /* TODO: Parse the timestamp and convert it to Purple's format. */ + g_string_append(formatted, "<font size=\"2\">("); + g_string_append_len(formatted, line, (timestamp - line)); + g_string_append(formatted,")</font> "); + line = timestamp + 1; + if (line[0] && line[1]) + line++; + } - line += (sizeof("NOTE: ") - 1); - } else if (purple_str_has_prefix(line, "Auto-response sent to ")) { - g_string_append(formatted, _("Auto-response sent:")); - while (*line && *line != ':') - line++; - if (*line) - line++; - g_string_append(formatted, "</b>"); - footer = NULL; - } else if (strstr(line, " signed off ")) { - if (buddy != NULL && buddy->alias) - g_string_append_printf(formatted, - _("%s has signed off."), buddy->alias); - else - g_string_append_printf(formatted, - _("%s has signed off."), log->name); - line = ""; - } else if (strstr(line, " signed on ")) { - if (buddy != NULL && buddy->alias) - g_string_append(formatted, buddy->alias); - else - g_string_append(formatted, log->name); - line = " logged in."; - } else if (purple_str_has_prefix(line, - "One or more messages may have been undeliverable.")) { + if (purple_str_has_prefix(line, "*** ")) { + line += (sizeof("*** ") - 1); + g_string_append(formatted, "<b>"); + footer = "</b>"; + if (purple_str_has_prefix(line, "NOTE: This user is offline.")) { + line = _("User is offline."); + } else if (purple_str_has_prefix(line, + "NOTE: Your status is currently set to ")) { + + line += (sizeof("NOTE: ") - 1); + } else if (purple_str_has_prefix(line, "Auto-response sent to ")) { + g_string_append(formatted, _("Auto-response sent:")); + while (*line && *line != ':') + line++; + if (*line) + line++; + g_string_append(formatted, "</b>"); + footer = NULL; + } else if (strstr(line, " signed off ")) { + if (buddy != NULL && buddy->alias) + g_string_append_printf(formatted, + _("%s has signed off."), buddy->alias); + else + g_string_append_printf(formatted, + _("%s has signed off."), log->name); + line = ""; + } else if (strstr(line, " signed on ")) { + if (buddy != NULL && buddy->alias) + g_string_append(formatted, buddy->alias); + else + g_string_append(formatted, log->name); + line = " logged in."; + } else if (purple_str_has_prefix(line, + "One or more messages may have been undeliverable.")) { - g_string_append(formatted, - "<span style=\"color: #ff0000;\">"); - g_string_append(formatted, - _("One or more messages may have been " - "undeliverable.")); - line = ""; - footer = "</span></b>"; - } else if (purple_str_has_prefix(line, - "You have been disconnected.")) { + g_string_append(formatted, + "<span style=\"color: #ff0000;\">"); + g_string_append(formatted, + _("One or more messages may have been " + "undeliverable.")); + line = ""; + footer = "</span></b>"; + } else if (purple_str_has_prefix(line, + "You have been disconnected.")) { - g_string_append(formatted, - "<span style=\"color: #ff0000;\">"); - g_string_append(formatted, - _("You were disconnected from the server.")); - line = ""; - footer = "</span></b>"; - } else if (purple_str_has_prefix(line, - "You are currently disconnected.")) { + g_string_append(formatted, + "<span style=\"color: #ff0000;\">"); + g_string_append(formatted, + _("You were disconnected from the server.")); + line = ""; + footer = "</span></b>"; + } else if (purple_str_has_prefix(line, + "You are currently disconnected.")) { + + g_string_append(formatted, + "<span style=\"color: #ff0000;\">"); + line = _("You are currently disconnected. Messages " + "will not be received unless you are " + "logged in."); + footer = "</span></b>"; + } else if (purple_str_has_prefix(line, + "Your previous message has not been sent.")) { + + g_string_append(formatted, + "<span style=\"color: #ff0000;\">"); + + if (purple_str_has_prefix(line, + "Your previous message has not been sent. " + "Reason: Maximum length exceeded.")) { g_string_append(formatted, - "<span style=\"color: #ff0000;\">"); - line = _("You are currently disconnected. Messages " - "will not be received unless you are " - "logged in."); - footer = "</span></b>"; - } else if (purple_str_has_prefix(line, - "Your previous message has not been sent.")) { - + _("Message could not be sent because " + "the maximum length was exceeded.")); + line = ""; + } else { g_string_append(formatted, - "<span style=\"color: #ff0000;\">"); - - if (purple_str_has_prefix(line, - "Your previous message has not been sent. " - "Reason: Maximum length exceeded.")) { + _("Message could not be sent.")); + line += (sizeof( + "Your previous message " + "has not been sent. ") - 1); + } - g_string_append(formatted, - _("Message could not be sent because " - "the maximum length was exceeded.")); - line = ""; - } else { - g_string_append(formatted, - _("Message could not be sent.")); - line += (sizeof( - "Your previous message " - "has not been sent. ") - 1); - } + footer = "</span></b>"; + } + } else if (purple_str_has_prefix(line, data->their_nickname)) { + if (buddy != NULL && buddy->alias) { + line += strlen(data->their_nickname) + 2; + g_string_append_printf(formatted, + "<span style=\"color: #A82F2F;\">" + "<b>%s</b></span>: ", buddy->alias); + } + } else { + const char *line2 = strstr(line, ":"); + if (line2) { + const char *acct_name; + line2++; + line = line2; + acct_name = purple_account_get_alias(log->account); + if (!acct_name) + acct_name = purple_account_get_username(log->account); - footer = "</span></b>"; - } - } else if (purple_str_has_prefix(line, data->their_nickname)) { - if (buddy != NULL && buddy->alias) { - line += strlen(data->their_nickname) + 2; - g_string_append_printf(formatted, - "<span style=\"color: #A82F2F;\">" - "<b>%s</b></span>: ", buddy->alias); - } - } else { - char *line2 = line; - while (*line2 && *line2 != ':') - line2++; - if (*line2 == ':') { - const char *acct_name; - line2++; - line = line2; - acct_name = purple_account_get_alias(log->account); - if (!acct_name) - acct_name = purple_account_get_username(log->account); - - g_string_append_printf(formatted, - "<span style=\"color: #16569E;\">" - "<b>%s</b></span>:", acct_name); - } + g_string_append_printf(formatted, + "<span style=\"color: #16569E;\">" + "<b>%s</b></span>:", acct_name); } } - - g_string_append(formatted, line); + } - if (footer) - g_string_append(formatted, footer); - - g_string_append_c(formatted, '\n'); + g_string_append(formatted, line); - if (link_temp_line) - g_free(link_temp_line); + line = c; + if (temp) + g_string_free(temp, TRUE); - c++; - line = c; - } else - c++; + if (footer) + g_string_append(formatted, footer); + + g_string_append_c(formatted, '\n'); } g_free(read); - read = formatted->str; - g_string_free(formatted, FALSE); - - return read; + /* XXX: TODO: Avoid this g_strchomp() */ + return g_strchomp(g_string_free(formatted, FALSE)); } static int trillian_logger_size (PurpleLog *log)
--- a/libpurple/plugins/newline.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/plugins/newline.c Mon Jun 18 01:48:35 2007 +0000 @@ -32,7 +32,7 @@ PurpleConversation *conv, int *flags, void *data) { if (g_ascii_strncasecmp(*message, "/me ", strlen("/me "))) { - char *tmp = g_strdup_printf("\n%s", *message); + char *tmp = g_strdup_printf("<br/>%s", *message); g_free(*message); *message = tmp; }
--- a/libpurple/plugins/perl/perl-common.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/plugins/perl/perl-common.c Mon Jun 18 01:48:35 2007 +0000 @@ -205,7 +205,7 @@ purple_debug(PURPLE_DEBUG_ERROR, "perl", "Perl function %s exited abnormally: %s\n", function, SvPV(ERRSV, na)); - POPs; + (void)POPs; } else if (count != 1) { /* * This should NEVER happen. G_SCALAR ensures that we WILL
--- a/libpurple/plugins/perl/perl-handlers.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/plugins/perl/perl-handlers.c Mon Jun 18 01:48:35 2007 +0000 @@ -184,7 +184,7 @@ timeout_handlers = g_list_remove(timeout_handlers, handler); if (handler->iotag > 0) - g_source_remove(handler->iotag); + purple_timeout_remove(handler->iotag); if (handler->callback != NULL) SvREFCNT_dec(handler->callback); @@ -405,7 +405,7 @@ timeout_handlers = g_list_append(timeout_handlers, handler); - handler->iotag = g_timeout_add(seconds * 1000, perl_timeout_cb, handler); + handler->iotag = purple_timeout_add(seconds * 1000, perl_timeout_cb, handler); } void
--- a/libpurple/plugins/ssl/ssl-gnutls.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/plugins/ssl/ssl-gnutls.c Mon Jun 18 01:48:35 2007 +0000 @@ -123,6 +123,18 @@ gnutls_data->handshake_handler = purple_input_add(gsc->fd, PURPLE_INPUT_READ, ssl_gnutls_handshake_cb, gsc); + /* Orborde asks: Why are we configuring a callback, then + immediately calling it? + + Answer: gnutls_handshake (up in handshake_cb) needs to be called + once in order to get the ball rolling on the SSL connection. + Once it has done so, only then will the server reply, triggering + the callback. + + Since the logic driving gnutls_handshake is the same with the first + and subsequent calls, we'll just fire the callback immediately to + accomplish this. + */ ssl_gnutls_handshake_cb(gsc, gsc->fd, PURPLE_INPUT_READ); }
--- a/libpurple/plugins/ssl/ssl-nss.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/plugins/ssl/ssl-nss.c Mon Jun 18 01:48:35 2007 +0000 @@ -32,7 +32,6 @@ #undef HAVE_LONG_LONG /* Make Mozilla less angry. If angry, Mozilla SMASH! */ #include <nspr.h> -#include <private/pprio.h> #include <nss.h> #include <pk11func.h> #include <prio.h> @@ -42,6 +41,10 @@ #include <sslerr.h> #include <sslproto.h> +/* This is defined in NSPR's <private/pprio.h>, but to avoid including a + * private header we duplicate the prototype here */ +NSPR_API(PRFileDesc*) PR_ImportTCPSocket(PRInt32 osfd); + typedef struct { PRFileDesc *fd; @@ -311,8 +314,13 @@ if(!nss_data) return; - if (nss_data->in) PR_Close(nss_data->in); - /* if (nss_data->fd) PR_Close(nss_data->fd); */ + if (nss_data->in) { + PR_Close(nss_data->in); + gsc->fd = -1; + } else if (nss_data->fd) { + PR_Close(nss_data->fd); + gsc->fd = -1; + } if (nss_data->handshake_handler) purple_input_remove(nss_data->handshake_handler);
--- a/libpurple/plugins/tcl/tcl.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/plugins/tcl/tcl.c Mon Jun 18 01:48:35 2007 +0000 @@ -457,11 +457,23 @@ if ((version = wpurple_read_reg_string(HKEY_LOCAL_MACHINE, regkey, "CurrentVersion")) || (version = wpurple_read_reg_string(HKEY_CURRENT_USER, regkey, "CurrentVersion"))) { - char *path; + char *path = NULL; char *regkey2; + char **tokens; + int major = 0, minor = 0, micro = 0; + + tokens = g_strsplit(version, ".", 0); + if (tokens[0] && tokens[1] && tokens[2]) { + major = atoi(tokens[0]); + minor = atoi(tokens[1]); + micro = atoi(tokens[2]); + } + g_strfreev(tokens); regkey2 = g_strdup_printf("%s%s\\", regkey, version); - if ((path = wpurple_read_reg_string(HKEY_LOCAL_MACHINE, regkey2, NULL)) || (path = wpurple_read_reg_string(HKEY_CURRENT_USER, regkey2, NULL))) { + if (!(major == 8 && minor == 4 && micro >= 5)) + purple_debug(PURPLE_DEBUG_INFO, "tcl", "Unsupported ActiveTCL version %s found.\n", version); + else if ((path = wpurple_read_reg_string(HKEY_LOCAL_MACHINE, regkey2, NULL)) || (path = wpurple_read_reg_string(HKEY_CURRENT_USER, regkey2, NULL))) { char *tclpath; char *tkpath;
--- a/libpurple/plugins/tcl/tcl_signals.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/plugins/tcl/tcl_signals.c Mon Jun 18 01:48:35 2007 +0000 @@ -49,7 +49,9 @@ Tcl_DecrRefCount(handler->signal); if (handler->namespace) + { Tcl_DecrRefCount(handler->namespace); + } g_free(handler); }
--- a/libpurple/protocols/Makefile.am Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/Makefile.am Mon Jun 18 01:48:35 2007 +0000 @@ -1,5 +1,5 @@ EXTRA_DIST = Makefile.mingw -DIST_SUBDIRS = bonjour gg irc jabber msn novell oscar qq sametime silc toc simple yahoo zephyr +DIST_SUBDIRS = bonjour gg irc jabber msn novell null oscar qq sametime silc silc10 toc simple yahoo zephyr SUBDIRS = $(DYNAMIC_PRPLS) $(STATIC_PRPLS)
--- a/libpurple/protocols/Makefile.mingw Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/Makefile.mingw Mon Jun 18 01:48:35 2007 +0000 @@ -8,7 +8,7 @@ PIDGIN_TREE_TOP := ../.. include $(PIDGIN_TREE_TOP)/libpurple/win32/global.mak -SUBDIRS = gg irc jabber msn novell oscar qq sametime silc simple yahoo +SUBDIRS = gg irc jabber msn novell null oscar qq sametime silc10 simple yahoo bonjour .PHONY: all install clean
--- a/libpurple/protocols/bonjour/Makefile.am Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/bonjour/Makefile.am Mon Jun 18 01:48:35 2007 +0000 @@ -1,4 +1,6 @@ EXTRA_DIST = \ + mdns_win32.c \ + mdns_win32.h \ Makefile.mingw pkgdir = $(libdir)/purple-$(PURPLE_MAJOR_VERSION) @@ -8,12 +10,16 @@ bonjour.h \ buddy.c \ buddy.h \ - dns_sd.c \ - dns_sd.h \ + dns_sd_proxy.h \ jabber.c \ - jabber.h + jabber.h \ + mdns_common.c \ + mdns_common.h \ + mdns_howl.c \ + mdns_howl.h \ + mdns_types.h -AM_CFLAGS = $(st) +AM_CFLAGS = $(st) -DUSE_BONJOUR_HOWL libbonjour_la_LDFLAGS = -module -avoid-version
--- a/libpurple/protocols/bonjour/Makefile.mingw Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/bonjour/Makefile.mingw Mon Jun 18 01:48:35 2007 +0000 @@ -8,7 +8,6 @@ include $(PIDGIN_TREE_TOP)/libpurple/win32/global.mak TARGET = libbonjour -NEEDED_DLLS = $(HOWL_TOP)/bin/libhowl-1.dll TYPE = PLUGIN # Static or Plugin... @@ -21,20 +20,22 @@ endif endif +CFLAGS += -DUSE_BONJOUR_APPLE + ## ## INCLUDE PATHS ## -INCLUDE_PATHS += -I$(BONJOUR_ROOT) \ +INCLUDE_PATHS += -I. \ -I$(GTK_TOP)/include \ -I$(GTK_TOP)/include/glib-2.0 \ -I$(GTK_TOP)/lib/glib-2.0/include \ - -I$(HOWL_TOP)/include \ + -I$(BONJOUR_TOP)/include \ -I$(PURPLE_TOP) \ -I$(PURPLE_TOP)/win32 \ -I$(PIDGIN_TREE_TOP) LIB_PATHS += -L$(GTK_TOP)/lib \ - -L$(HOWL_TOP)/lib \ + -L$(BONJOUR_TOP)/lib \ -L$(PURPLE_TOP) ## @@ -42,7 +43,8 @@ ## C_SRC = bonjour.c \ buddy.c \ - dns_sd.c \ + mdns_common.c \ + mdns_win32.c \ jabber.c OBJECTS = $(C_SRC:%.c=%.o) @@ -54,7 +56,7 @@ -lglib-2.0 \ -lws2_32 \ -lintl \ - -lhowl \ + -ldnssd \ -lpurple include $(PIDGIN_COMMON_RULES) @@ -68,7 +70,6 @@ install: all $(DLL_INSTALL_DIR) cp $(TARGET).dll $(DLL_INSTALL_DIR) - cp $(NEEDED_DLLS) $(PURPLE_INSTALL_DIR) $(OBJECTS): $(PURPLE_CONFIG_H)
--- a/libpurple/protocols/bonjour/bonjour.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/bonjour/bonjour.c Mon Jun 18 01:48:35 2007 +0000 @@ -37,7 +37,7 @@ #include "version.h" #include "bonjour.h" -#include "dns_sd.h" +#include "mdns_common.h" #include "jabber.h" #include "buddy.h" @@ -94,14 +94,13 @@ bonjour_login(PurpleAccount *account) { PurpleConnection *gc = purple_account_get_connection(account); - PurpleGroup *bonjour_group = NULL; - BonjourData *bd = NULL; + PurpleGroup *bonjour_group; + BonjourData *bd; PurpleStatus *status; PurplePresence *presence; gc->flags |= PURPLE_CONNECTION_HTML; - gc->proto_data = g_new0(BonjourData, 1); - bd = gc->proto_data; + gc->proto_data = bd = g_new0(BonjourData, 1); /* Start waiting for jabber connections (iChat style) */ bd->jabber_data = g_new(BonjourJabber, 1); @@ -111,26 +110,16 @@ if (bonjour_jabber_start(bd->jabber_data) == -1) { /* Send a message about the connection error */ purple_connection_error(gc, _("Unable to listen for incoming IM connections\n")); - - /* Free the data */ - g_free(bd->jabber_data); - bd->jabber_data = NULL; return; } /* Connect to the mDNS daemon looking for buddies in the LAN */ bd->dns_sd_data = bonjour_dns_sd_new(); - bd->dns_sd_data->name = (sw_string)purple_account_get_username(account); - bd->dns_sd_data->txtvers = g_strdup("1"); - bd->dns_sd_data->version = g_strdup("1"); bd->dns_sd_data->first = g_strdup(purple_account_get_string(account, "first", default_firstname)); bd->dns_sd_data->last = g_strdup(purple_account_get_string(account, "last", default_lastname)); bd->dns_sd_data->port_p2pj = bd->jabber_data->port; - bd->dns_sd_data->phsh = g_strdup(""); - bd->dns_sd_data->email = g_strdup(purple_account_get_string(account, "email", "")); - bd->dns_sd_data->vc = g_strdup(""); - bd->dns_sd_data->jid = g_strdup(purple_account_get_string(account, "jid", "")); - bd->dns_sd_data->AIM = g_strdup(purple_account_get_string(account, "AIM", "")); + /* Not engaged in AV conference */ + bd->dns_sd_data->vc = g_strdup("!"); status = purple_account_get_active_status(account); presence = purple_account_get_presence(account); @@ -161,7 +150,7 @@ bonjour_close(PurpleConnection *connection) { PurpleGroup *bonjour_group; - BonjourData *bd = (BonjourData*)connection->proto_data; + BonjourData *bd = connection->proto_data; /* Stop looking for buddies in the LAN */ if (bd->dns_sd_data != NULL) @@ -278,6 +267,7 @@ bonjour_convo_closed(PurpleConnection *connection, const char *who) { PurpleBuddy *buddy = purple_find_buddy(connection->account, who); + BonjourBuddy *bb; if (buddy == NULL) { @@ -288,7 +278,9 @@ return; } - bonjour_jabber_close_conversation(((BonjourData*)(connection->proto_data))->jabber_data, buddy); + bb = buddy->proto_data; + bonjour_jabber_close_conversation(bb->conversation); + bb->conversation = NULL; } static char * @@ -331,6 +323,8 @@ static gboolean plugin_unload(PurplePlugin *plugin) { + /* These shouldn't happen here because they are allocated in _init() */ + g_free(default_firstname); g_free(default_lastname); g_free(default_hostname); @@ -491,8 +485,8 @@ LPUSER_INFO_10 user_info = NULL; LPSERVER_INFO_100 server_info = NULL; wchar_t *servername = NULL; - wchar_t username[UNLEN + 1] = {'\0'}; - DWORD dwLenUsername = sizeof(username); + wchar_t username[UNLEN + 1]; + DWORD dwLenUsername = UNLEN + 1; FARPROC myNetServerEnum = wpurple_find_and_loadproc( "Netapi32.dll", "NetServerEnum"); FARPROC myNetApiBufferFree = wpurple_find_and_loadproc( @@ -517,7 +511,7 @@ } } - if (!GetUserNameW(&username, &dwLenUsername)) { + if (!GetUserNameW((LPWSTR) &username, &dwLenUsername)) { purple_debug_warning("bonjour", "Unable to look up username\n"); } @@ -553,7 +547,7 @@ */ splitpoint = strchr(tmp, ','); if (splitpoint != NULL) - default_lastname = g_strndup(tmp, splitpoint - tmp); + default_lastname = g_strndup(tmp, splitpoint - tmp); else default_lastname = g_strdup(tmp); }
--- a/libpurple/protocols/bonjour/bonjour.h Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/bonjour/bonjour.h Mon Jun 18 01:48:35 2007 +0000 @@ -26,9 +26,7 @@ #ifndef _BONJOUR_H_ #define _BONJOUR_H_ -#include <howl.h> - -#include "dns_sd.h" +#include "mdns_common.h" #include "internal.h" #include "jabber.h"
--- a/libpurple/protocols/bonjour/buddy.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/bonjour/buddy.c Mon Jun 18 01:48:35 2007 +0000 @@ -27,51 +27,66 @@ * Creates a new buddy. */ BonjourBuddy * -bonjour_buddy_new(const gchar *name, const gchar *first, gint port_p2pj, - const gchar *phsh, const gchar *status, const gchar *email, - const gchar *last, const gchar *jid, const gchar *AIM, - const gchar *vc, const gchar *ip, const gchar *msg) +bonjour_buddy_new(const gchar *name, PurpleAccount* account) { - BonjourBuddy *buddy = malloc(sizeof(BonjourBuddy)); + BonjourBuddy *buddy = g_new0(BonjourBuddy, 1); + buddy->account = account; buddy->name = g_strdup(name); - buddy->first = g_strdup(first); - buddy->port_p2pj = port_p2pj; - buddy->phsh = g_strdup(phsh); - buddy->status = g_strdup(status); - buddy->email = g_strdup(email); - buddy->last = g_strdup(last); - buddy->jid = g_strdup(jid); - buddy->AIM = g_strdup(AIM); - buddy->vc = g_strdup(vc); - buddy->ip = g_strdup(ip); - buddy->msg = g_strdup(msg); - buddy->conversation = NULL; return buddy; } +void +set_bonjour_buddy_value(BonjourBuddy* buddy, const char *record_key, const char *value, uint32_t len){ + gchar **fld = NULL; + + if (!strcmp(record_key, "1st")) + fld = &buddy->first; + else if(!strcmp(record_key, "email")) + fld = &buddy->email; + else if(!strcmp(record_key, "ext")) + fld = &buddy->ext; + else if(!strcmp(record_key, "jid")) + fld = &buddy->jid; + else if(!strcmp(record_key, "last")) + fld = &buddy->last; + else if(!strcmp(record_key, "msg")) + fld = &buddy->msg; + else if(!strcmp(record_key, "nick")) + fld = &buddy->nick; + else if(!strcmp(record_key, "node")) + fld = &buddy->node; + else if(!strcmp(record_key, "phsh")) + fld = &buddy->phsh; + else if(!strcmp(record_key, "status")) + fld = &buddy->status; + else if(!strcmp(record_key, "vc")) + fld = &buddy->vc; + else if(!strcmp(record_key, "ver")) + fld = &buddy->ver; + else if(!strcmp(record_key, "AIM")) + fld = &buddy->AIM; + + if(fld == NULL) + return; + + g_free(*fld); + *fld = NULL; + *fld = g_strndup(value, len); +} + /** * Check if all the compulsory buddy data is present. */ gboolean bonjour_buddy_check(BonjourBuddy *buddy) { - if (buddy->name == NULL) { + if (buddy->account == NULL) return FALSE; - } - - if (buddy->first == NULL) { - return FALSE; - } - if (buddy->last == NULL) { + if (buddy->name == NULL) return FALSE; - } - - if (buddy->status == NULL) { - return FALSE; - } return TRUE; } @@ -82,12 +97,12 @@ * the buddy. */ void -bonjour_buddy_add_to_purple(PurpleAccount *account, BonjourBuddy *bonjour_buddy) +bonjour_buddy_add_to_purple(BonjourBuddy *bonjour_buddy) { PurpleBuddy *buddy; PurpleGroup *group; const char *status_id, *first, *last; - char *alias; + gchar *alias; /* Translate between the Bonjour status and the Purple status */ if (g_ascii_strcasecmp("dnd", bonjour_buddy->status) == 0) @@ -117,10 +132,11 @@ } /* Make sure the buddy exists in our buddy list */ - buddy = purple_find_buddy(account, bonjour_buddy->name); + buddy = purple_find_buddy(bonjour_buddy->account, bonjour_buddy->name); + if (buddy == NULL) { - buddy = purple_buddy_new(account, bonjour_buddy->name, alias); + buddy = purple_buddy_new(bonjour_buddy->account, bonjour_buddy->name, alias); buddy->proto_data = bonjour_buddy; purple_blist_node_set_flags((PurpleBlistNode *)buddy, PURPLE_BLIST_NODE_FLAG_NO_SAVE); purple_blist_add_buddy(buddy, NULL, group, NULL); @@ -128,13 +144,13 @@ /* Set the user's status */ if (bonjour_buddy->msg != NULL) - purple_prpl_got_user_status(account, buddy->name, status_id, + purple_prpl_got_user_status(bonjour_buddy->account, buddy->name, status_id, "message", bonjour_buddy->msg, NULL); else - purple_prpl_got_user_status(account, buddy->name, status_id, + purple_prpl_got_user_status(bonjour_buddy->account, buddy->name, status_id, NULL); - purple_prpl_got_user_idle(account, buddy->name, FALSE, 0); + purple_prpl_got_user_idle(bonjour_buddy->account, buddy->name, FALSE, 0); g_free(alias); } @@ -146,6 +162,8 @@ bonjour_buddy_delete(BonjourBuddy *buddy) { g_free(buddy->name); + g_free(buddy->ip); + g_free(buddy->first); g_free(buddy->phsh); g_free(buddy->status); @@ -154,14 +172,22 @@ g_free(buddy->jid); g_free(buddy->AIM); g_free(buddy->vc); - g_free(buddy->ip); g_free(buddy->msg); + g_free(buddy->ext); + g_free(buddy->nick); + g_free(buddy->node); + g_free(buddy->ver); - if (buddy->conversation != NULL) + bonjour_jabber_close_conversation(buddy->conversation); + buddy->conversation = NULL; + +#ifdef USE_BONJOUR_APPLE + if (buddy->txt_query != NULL) { - g_free(buddy->conversation->buddy_name); - g_free(buddy->conversation); + purple_input_remove(buddy->txt_query_fd); + DNSServiceRefDeallocate(buddy->txt_query); } +#endif - free(buddy); + g_free(buddy); }
--- a/libpurple/protocols/bonjour/buddy.h Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/bonjour/buddy.h Mon Jun 18 01:48:35 2007 +0000 @@ -17,17 +17,27 @@ #ifndef _BONJOUR_BUDDY #define _BONJOUR_BUDDY -#include <howl.h> #include <glib.h> +#include "config.h" #include "account.h" #include "jabber.h" +#ifdef USE_BONJOUR_APPLE +#include "dns_sd_proxy.h" +#else /* USE_BONJOUR_HOWL */ +#include <howl.h> +#endif + typedef struct _BonjourBuddy { + PurpleAccount *account; + gchar *name; + gchar *ip; + gint port_p2pj; + gchar *first; - gint port_p2pj; gchar *phsh; gchar *status; gchar *email; @@ -35,18 +45,49 @@ gchar *jid; gchar *AIM; gchar *vc; - gchar *ip; gchar *msg; + gchar *ext; + gchar *nick; + gchar *node; + gchar *ver; + BonjourJabberConversation *conversation; + +#ifdef USE_BONJOUR_APPLE + DNSServiceRef txt_query; + int txt_query_fd; +#endif + } BonjourBuddy; +static const char *const buddy_TXT_records[] = { + "1st", + "email", + "ext", + "jid", + "last", + "msg", + "nick", + "node", + "phsh", +/* "port.p2pj", Deprecated - MUST ignore */ + "status", +/* "txtvers", Deprecated - hardcoded to 1 */ + "vc", + "ver", + "AIM", /* non standard */ + NULL +}; + /** * Creates a new buddy. */ -BonjourBuddy *bonjour_buddy_new(const gchar *name, const gchar *first, - gint port_p2pj, const gchar *phsh, const gchar *status, - const gchar *email, const gchar *last, const gchar *jid, - const gchar *AIM, const gchar *vc, const gchar *ip, const gchar *msg); +BonjourBuddy *bonjour_buddy_new(const gchar *name, PurpleAccount *account); + +/** + * Sets a value in the BonjourBuddy struct, destroying the old value + */ +void set_bonjour_buddy_value(BonjourBuddy* buddy, const char *record_key, const char *value, uint32_t len); /** * Check if all the compulsory buddy data is present. @@ -56,7 +97,7 @@ /** * If the buddy doesn't previoulsy exists, it is created. Else, its data is changed (???) */ -void bonjour_buddy_add_to_purple(PurpleAccount *account, BonjourBuddy *buddy); +void bonjour_buddy_add_to_purple(BonjourBuddy *buddy); /** * Deletes a buddy from memory.
--- a/libpurple/protocols/bonjour/dns_sd.c Thu Jun 14 19:48:48 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,387 +0,0 @@ -/* - * 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 Library 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#include <string.h> - -#include "dns_sd.h" -#include "bonjour.h" -#include "buddy.h" -#include "debug.h" - -/* Private functions */ - -static sw_result HOWL_API -_publish_reply(sw_discovery discovery, sw_discovery_oid oid, - sw_discovery_publish_status status, sw_opaque extra) -{ - purple_debug_warning("bonjour", "_publish_reply --> Start\n"); - - /* Check the answer from the mDNS daemon */ - switch (status) - { - case SW_DISCOVERY_PUBLISH_STARTED : - purple_debug_info("bonjour", "_publish_reply --> Service started\n"); - break; - case SW_DISCOVERY_PUBLISH_STOPPED : - purple_debug_info("bonjour", "_publish_reply --> Service stopped\n"); - break; - case SW_DISCOVERY_PUBLISH_NAME_COLLISION : - purple_debug_info("bonjour", "_publish_reply --> Name collision\n"); - break; - case SW_DISCOVERY_PUBLISH_INVALID : - purple_debug_info("bonjour", "_publish_reply --> Service invalid\n"); - break; - } - - return SW_OKAY; -} - -static sw_result HOWL_API -_resolve_reply(sw_discovery discovery, sw_discovery_oid oid, - sw_uint32 interface_index, sw_const_string name, - sw_const_string type, sw_const_string domain, - sw_ipv4_address address, sw_port port, - sw_octets text_record, sw_ulong text_record_len, - sw_opaque extra) -{ - BonjourBuddy *buddy; - PurpleAccount *account = (PurpleAccount*)extra; - gchar *txtvers = NULL; - gchar *version = NULL; - gchar *first = NULL; - gchar *phsh = NULL; - gchar *status = NULL; - gchar *email = NULL; - gchar *last = NULL; - gchar *jid = NULL; - gchar *AIM = NULL; - gchar *vc = NULL; - gchar *msg = NULL; - gint address_length = 16; - gchar *ip = NULL; - sw_text_record_iterator iterator; - char key[SW_TEXT_RECORD_MAX_LEN]; - char value[SW_TEXT_RECORD_MAX_LEN]; - sw_uint32 value_length; - - sw_discovery_cancel(discovery, oid); - - /* Get the ip as a string */ - ip = malloc(address_length); - sw_ipv4_address_name(address, ip, address_length); - - /* Obtain the parameters from the text_record */ - if ((text_record_len > 0) && (text_record) && (*text_record != '\0')) - { - sw_text_record_iterator_init(&iterator, text_record, text_record_len); - while (sw_text_record_iterator_next(iterator, key, (sw_octet *)value, &value_length) == SW_OKAY) - { - /* Compare the keys with the possible ones and save them on */ - /* the appropiate place of the buddy_list */ - if (strcmp(key, "txtvers") == 0) { - txtvers = g_strdup(value); - } else if (strcmp(key, "version") == 0) { - version = g_strdup(value); - } else if (strcmp(key, "1st") == 0) { - first = g_strdup(value); - } else if (strcmp(key, "status") == 0) { - status = g_strdup(value); - } else if (strcmp(key, "email") == 0) { - email = g_strdup(value); - } else if (strcmp(key, "last") == 0) { - last = g_strdup(value); - } else if (strcmp(key, "jid") == 0) { - jid = g_strdup(value); - } else if (strcmp(key, "AIM") == 0) { - AIM = g_strdup(value); - } else if (strcmp(key, "vc") == 0) { - vc = g_strdup(value); - } else if (strcmp(key, "phsh") == 0) { - phsh = g_strdup(value); - } else if (strcmp(key, "msg") == 0) { - msg = g_strdup(value); - } - } - } - - /* Put the parameters of the text_record in a buddy and add the buddy to */ - /* the buddy list */ - buddy = bonjour_buddy_new(name, first, port, phsh, - status, email, last, jid, AIM, vc, ip, msg); - - if (bonjour_buddy_check(buddy) == FALSE) - { - bonjour_buddy_delete(buddy); - return SW_DISCOVERY_E_UNKNOWN; - } - - /* Add or update the buddy in our buddy list */ - bonjour_buddy_add_to_purple(account, buddy); - - /* Free all the temporal strings */ - g_free(txtvers); - g_free(version); - g_free(first); - g_free(last); - g_free(status); - g_free(email); - g_free(jid); - g_free(AIM); - g_free(vc); - g_free(phsh); - g_free(msg); - - return SW_OKAY; -} - -static sw_result HOWL_API -_browser_reply(sw_discovery discovery, sw_discovery_oid oid, - sw_discovery_browse_status status, - sw_uint32 interface_index, sw_const_string name, - sw_const_string type, sw_const_string domain, - sw_opaque_t extra) -{ - sw_discovery_resolve_id rid; - PurpleAccount *account = (PurpleAccount*)extra; - PurpleBuddy *gb = NULL; - - switch (status) - { - case SW_DISCOVERY_BROWSE_INVALID: - purple_debug_warning("bonjour", "_browser_reply --> Invalid\n"); - break; - case SW_DISCOVERY_BROWSE_RELEASE: - purple_debug_warning("bonjour", "_browser_reply --> Release\n"); - break; - case SW_DISCOVERY_BROWSE_ADD_DOMAIN: - purple_debug_warning("bonjour", "_browser_reply --> Add domain\n"); - break; - case SW_DISCOVERY_BROWSE_ADD_DEFAULT_DOMAIN: - purple_debug_warning("bonjour", "_browser_reply --> Add default domain\n"); - break; - case SW_DISCOVERY_BROWSE_REMOVE_DOMAIN: - purple_debug_warning("bonjour", "_browser_reply --> Remove domain\n"); - break; - case SW_DISCOVERY_BROWSE_ADD_SERVICE: - /* A new peer has joined the network and uses iChat bonjour */ - purple_debug_info("bonjour", "_browser_reply --> Add service\n"); - if (g_ascii_strcasecmp(name, account->username) != 0) - { - if (sw_discovery_resolve(discovery, interface_index, name, type, - domain, _resolve_reply, extra, &rid) != SW_OKAY) - { - purple_debug_warning("bonjour", "_browser_reply --> Cannot send resolve\n"); - } - } - break; - case SW_DISCOVERY_BROWSE_REMOVE_SERVICE: - purple_debug_info("bonjour", "_browser_reply --> Remove service\n"); - gb = purple_find_buddy((PurpleAccount*)extra, name); - if (gb != NULL) - { - bonjour_buddy_delete(gb->proto_data); - purple_blist_remove_buddy(gb); - } - break; - case SW_DISCOVERY_BROWSE_RESOLVED: - purple_debug_info("bonjour", "_browse_reply --> Resolved\n"); - break; - default: - break; - } - - return SW_OKAY; -} - -static int -_dns_sd_publish(BonjourDnsSd *data, PublishType type) -{ - sw_text_record dns_data; - sw_result publish_result = SW_OKAY; - char portstring[6]; - - /* Fill the data for the service */ - if (sw_text_record_init(&dns_data) != SW_OKAY) - { - purple_debug_error("bonjour", "Unable to initialize the data for the mDNS.\n"); - return -1; - } - - /* Convert the port to a string */ - snprintf(portstring, sizeof(portstring), "%d", data->port_p2pj); - - /* Publish standard records */ - sw_text_record_add_key_and_string_value(dns_data, "txtvers", data->txtvers); - sw_text_record_add_key_and_string_value(dns_data, "version", data->version); - sw_text_record_add_key_and_string_value(dns_data, "1st", data->first); - sw_text_record_add_key_and_string_value(dns_data, "last", data->last); - sw_text_record_add_key_and_string_value(dns_data, "port.p2pj", portstring); - sw_text_record_add_key_and_string_value(dns_data, "phsh", data->phsh); - sw_text_record_add_key_and_string_value(dns_data, "status", data->status); - sw_text_record_add_key_and_string_value(dns_data, "vc", data->vc); - - /* Publish extra records */ - if ((data->email != NULL) && (*data->email != '\0')) - sw_text_record_add_key_and_string_value(dns_data, "email", data->email); - - if ((data->jid != NULL) && (*data->jid != '\0')) - sw_text_record_add_key_and_string_value(dns_data, "jid", data->jid); - - if ((data->AIM != NULL) && (*data->AIM != '\0')) - sw_text_record_add_key_and_string_value(dns_data, "AIM", data->AIM); - - if ((data->msg != NULL) && (*data->msg != '\0')) - sw_text_record_add_key_and_string_value(dns_data, "msg", data->msg); - - /* Publish the service */ - switch (type) - { - case PUBLISH_START: - publish_result = sw_discovery_publish(data->session, 0, data->name, ICHAT_SERVICE, NULL, - NULL, data->port_p2pj, sw_text_record_bytes(dns_data), sw_text_record_len(dns_data), - _publish_reply, NULL, &data->session_id); - break; - case PUBLISH_UPDATE: - publish_result = sw_discovery_publish_update(data->session, data->session_id, - sw_text_record_bytes(dns_data), sw_text_record_len(dns_data)); - break; - } - if (publish_result != SW_OKAY) - { - purple_debug_error("bonjour", "Unable to publish or change the status of the _presence._tcp service.\n"); - return -1; - } - - /* Free the memory used by temp data */ - sw_text_record_fina(dns_data); - - return 0; -} - -static void -_dns_sd_handle_packets(gpointer data, gint source, PurpleInputCondition condition) -{ - sw_discovery_read_socket((sw_discovery)data); -} - -/* End private functions */ - -/** - * Allocate space for the dns-sd data. - */ -BonjourDnsSd * -bonjour_dns_sd_new() -{ - BonjourDnsSd *data = g_new0(BonjourDnsSd, 1); - - return data; -} - -/** - * Deallocate the space of the dns-sd data. - */ -void -bonjour_dns_sd_free(BonjourDnsSd *data) -{ - g_free(data->first); - g_free(data->last); - g_free(data->email); - g_free(data); -} - -/** - * Send a new dns-sd packet updating our status. - */ -void -bonjour_dns_sd_send_status(BonjourDnsSd *data, const char *status, const char *status_message) -{ - g_free(data->status); - g_free(data->msg); - - data->status = g_strdup(status); - data->msg = g_strdup(status_message); - - /* Update our text record with the new status */ - _dns_sd_publish(data, PUBLISH_UPDATE); /* <--We must control the errors */ -} - -/** - * Advertise our presence within the dns-sd daemon and start browsing - * for other bonjour peers. - */ -gboolean -bonjour_dns_sd_start(BonjourDnsSd *data) -{ - PurpleAccount *account; - PurpleConnection *gc; - gint dns_sd_socket; - sw_discovery_oid session_id; - - account = data->account; - gc = purple_account_get_connection(account); - - /* Initialize the dns-sd data and session */ - if (sw_discovery_init(&data->session) != SW_OKAY) - { - purple_debug_error("bonjour", "Unable to initialize an mDNS session.\n"); - - /* In Avahi, sw_discovery_init frees data->session but doesn't clear it */ - data->session = NULL; - - return FALSE; - } - - /* Publish our bonjour IM client at the mDNS daemon */ - _dns_sd_publish(data, PUBLISH_START); /* <--We must control the errors */ - - /* Advise the daemon that we are waiting for connections */ - if (sw_discovery_browse(data->session, 0, ICHAT_SERVICE, NULL, _browser_reply, - data->account, &session_id) != SW_OKAY) - { - purple_debug_error("bonjour", "Unable to get service."); - return FALSE; - } - - /* Get the socket that communicates with the mDNS daemon and bind it to a */ - /* callback that will handle the dns_sd packets */ - dns_sd_socket = sw_discovery_socket(data->session); - gc->inpa = purple_input_add(dns_sd_socket, PURPLE_INPUT_READ, - _dns_sd_handle_packets, data->session); - - return TRUE; -} - -/** - * Unregister the "_presence._tcp" service at the mDNS daemon. - */ -void -bonjour_dns_sd_stop(BonjourDnsSd *data) -{ - PurpleAccount *account; - PurpleConnection *gc; - - if (data->session == NULL) - return; - - sw_discovery_cancel(data->session, data->session_id); - - account = data->account; - gc = purple_account_get_connection(account); - purple_input_remove(gc->inpa); - - g_free(data->session); - data->session = NULL; -}
--- a/libpurple/protocols/bonjour/dns_sd.h Thu Jun 14 19:48:48 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,81 +0,0 @@ -/* - * 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 Library 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef _BONJOUR_DNS_SD -#define _BONJOUR_DNS_SD - -#include <howl.h> -#include <glib.h> -#include "account.h" - -#define ICHAT_SERVICE "_presence._tcp." - -/** - * Data to be used by the dns-sd connection. - */ -typedef struct _BonjourDnsSd -{ - sw_discovery session; - sw_discovery_oid session_id; - PurpleAccount *account; - gchar *name; - gchar *txtvers; - gchar *version; - gchar *first; - gchar *last; - gint port_p2pj; - gchar *phsh; - gchar *status; - gchar *email; - gchar *vc; - gchar *jid; - gchar *AIM; - gchar *msg; - GHashTable *buddies; -} BonjourDnsSd; - -typedef enum _PublishType { - PUBLISH_START, - PUBLISH_UPDATE -} PublishType; - -/** - * Allocate space for the dns-sd data. - */ -BonjourDnsSd *bonjour_dns_sd_new(void); - -/** - * Deallocate the space of the dns-sd data. - */ -void bonjour_dns_sd_free(BonjourDnsSd *data); - -/** - * Send a new dns-sd packet updating our status. - */ -void bonjour_dns_sd_send_status(BonjourDnsSd *data, const char *status, const char *status_message); - -/** - * Advertise our presence within the dns-sd daemon and start - * browsing for other bonjour peers. - */ -gboolean bonjour_dns_sd_start(BonjourDnsSd *data); - -/** - * Unregister the "_presence._tcp" service at the mDNS daemon. - */ -void bonjour_dns_sd_stop(BonjourDnsSd *data); - -#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/bonjour/dns_sd_proxy.h Mon Jun 18 01:48:35 2007 +0000 @@ -0,0 +1,19 @@ +#ifndef _DNS_SD_PROXY +#define _DNS_SD_PROXY + +#include <stdint.h> + +/* fixup to make pidgin compile against win32 bonjour */ +#ifdef _WIN32 +#define _MSL_STDINT_H +#undef bzero +#endif + +#include <dns_sd.h> + +/* dns_sd.h defines bzero and we also do in libc_internal.h */ +#ifdef _WIN32 +#undef bzero +#endif + +#endif
--- a/libpurple/protocols/bonjour/issues.txt Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/bonjour/issues.txt Mon Jun 18 01:48:35 2007 +0000 @@ -6,4 +6,3 @@ * Avatars * File transfers * Typing notifications -* Check if it works on win32
--- a/libpurple/protocols/bonjour/jabber.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/bonjour/jabber.c Mon Jun 18 01:48:35 2007 +0000 @@ -28,7 +28,6 @@ #endif #include <sys/types.h> #include <glib.h> -#include <glib/gprintf.h> #include <unistd.h> #include <fcntl.h> @@ -45,29 +44,10 @@ #include "bonjour.h" #include "buddy.h" -static gint -_connect_to_buddy(PurpleBuddy *gb) -{ - gint socket_fd; - gint retorno = 0; - struct sockaddr_in buddy_address; - - /* Create a socket and make it non-blocking */ - socket_fd = socket(PF_INET, SOCK_STREAM, 0); - - buddy_address.sin_family = PF_INET; - buddy_address.sin_port = htons(((BonjourBuddy*)(gb->proto_data))->port_p2pj); - inet_aton(((BonjourBuddy*)(gb->proto_data))->ip, &(buddy_address.sin_addr)); - memset(&(buddy_address.sin_zero), '\0', 8); - - retorno = connect(socket_fd, (struct sockaddr*)&buddy_address, sizeof(struct sockaddr)); - if (retorno == -1) { - purple_debug_warning("bonjour", "connect error: %s\n", strerror(errno)); - } - fcntl(socket_fd, F_SETFL, O_NONBLOCK); - - return socket_fd; -} +#define STREAM_END "</stream:stream>" +/* TODO: specify version='1.0' and send stream features */ +#define DOCTYPE "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" \ + "<stream:stream xmlns=\"jabber:client\" xmlns:stream=\"http://etherx.jabber.org/streams\" from=\"%s\" to=\"%s\">" #if 0 /* this isn't used anywhere... */ static const char * @@ -94,6 +74,19 @@ } #endif +static BonjourJabberConversation * +bonjour_jabber_conv_new() { + + BonjourJabberConversation *bconv = g_new0(BonjourJabberConversation, 1); + bconv->socket = -1; + bconv->tx_buf = purple_circ_buffer_new(512); + bconv->tx_handler = -1; + bconv->rx_handler = -1; + + return bconv; +} + + static const char * _font_size_ichat_to_purple(int size) { @@ -113,46 +106,34 @@ return "1"; } + static void -_jabber_parse_and_write_message_to_ui(char *message, PurpleConnection *connection, PurpleBuddy *gb) +_jabber_parse_and_write_message_to_ui(xmlnode *message_node, PurpleConnection *connection, PurpleBuddy *pb) { - xmlnode *body_node = NULL; - char *body = NULL; - xmlnode *html_node = NULL; - gboolean isHTML = FALSE; - xmlnode *html_body_node = NULL; + xmlnode *body_node, *html_node, *events_node; + char *body, *html_body = NULL; const char *ichat_balloon_color = NULL; const char *ichat_text_color = NULL; - xmlnode *html_body_font_node = NULL; const char *font_face = NULL; const char *font_size = NULL; const char *font_color = NULL; - char *html_body = NULL; - xmlnode *events_node = NULL; gboolean composing_event = FALSE; - gint garbage = -1; - xmlnode *message_node = NULL; - - /* Parsing of the message */ - message_node = xmlnode_from_str(message, strlen(message)); - if (message_node == NULL) { - return; - } body_node = xmlnode_get_child(message_node, "body"); - if (body_node != NULL) { - body = xmlnode_get_data(body_node); - } else { + if (body_node == NULL) return; - } + body = xmlnode_get_data(body_node); html_node = xmlnode_get_child(message_node, "html"); if (html_node != NULL) { - isHTML = TRUE; + xmlnode *html_body_node; + html_body_node = xmlnode_get_child(html_node, "body"); if (html_body_node != NULL) { + xmlnode *html_body_font_node; + ichat_balloon_color = xmlnode_get_attrib(html_body_node, "ichatballooncolor"); ichat_text_color = xmlnode_get_attrib(html_body_node, "ichattextcolor"); html_body_font_node = xmlnode_get_child(html_body_node, "font"); @@ -162,36 +143,25 @@ /* The absolute iChat font sizes should be converted to 1..7 range */ font_size = xmlnode_get_attrib(html_body_font_node, "ABSZ"); if (font_size != NULL) - { font_size = _font_size_ichat_to_purple(atoi(font_size)); - } font_color = xmlnode_get_attrib(html_body_font_node, "color"); html_body = xmlnode_get_data(html_body_font_node); if (html_body == NULL) - { /* This is the kind of formated messages that Purple creates */ - html_body = xmlnode_to_str(html_body_font_node, &garbage); - } - } else { - isHTML = FALSE; + html_body = xmlnode_to_str(html_body_font_node, NULL); } - } else { - isHTML = FALSE; } - } events_node = xmlnode_get_child_with_namespace(message_node, "x", "jabber:x:event"); if (events_node != NULL) { if (xmlnode_get_child(events_node, "composing") != NULL) - { composing_event = TRUE; - } if (xmlnode_get_child(events_node, "id") != NULL) { /* The user is just typing */ - xmlnode_free(message_node); + /* TODO: Deal with typing notification */ g_free(body); g_free(html_body); return; @@ -199,51 +169,51 @@ } /* Compose the message */ - if (isHTML) + if (html_body != NULL) { + g_free(body); + if (font_face == NULL) font_face = "Helvetica"; if (font_size == NULL) font_size = "3"; if (ichat_text_color == NULL) ichat_text_color = "#000000"; if (ichat_balloon_color == NULL) ichat_balloon_color = "#FFFFFF"; - body = g_strconcat("<font face='", font_face, "' size='", font_size, "' color='", ichat_text_color, - "' back='", ichat_balloon_color, "'>", html_body, "</font>", NULL); + body = g_strdup_printf("<font face='%s' size='%s' color='%s' back='%s'>%s</font>", + font_face, font_size, ichat_text_color, ichat_balloon_color, + html_body); } + /* TODO: Should we do something with "composing_event" here? */ + /* Send the message to the UI */ - serv_got_im(connection, gb->name, body, 0, time(NULL)); + serv_got_im(connection, pb->name, body, 0, time(NULL)); - /* Free all the strings and nodes (the attributes are freed with their nodes) */ - xmlnode_free(message_node); g_free(body); g_free(html_body); } struct _check_buddy_by_address_t { - char *address; - PurpleBuddy **gb; + const char *address; + PurpleBuddy **pb; BonjourJabber *bj; }; static void _check_buddy_by_address(gpointer key, gpointer value, gpointer data) { - PurpleBuddy *gb = (PurpleBuddy*)value; + PurpleBuddy *pb = value; BonjourBuddy *bb; - struct _check_buddy_by_address_t *cbba; - - gb = value; - cbba = data; + struct _check_buddy_by_address_t *cbba = data; /* * If the current PurpleBuddy's data is not null and the PurpleBuddy's account * is the same as the account requesting the check then continue to determine * whether the buddies IP matches the target IP. */ - if (cbba->bj->account == gb->account) + if (cbba->bj->account == pb->account) { - bb = gb->proto_data; + bb = pb->proto_data; if ((bb != NULL) && (g_ascii_strcasecmp(bb->ip, cbba->address) == 0)) - *(cbba->gb) = gb; + *(cbba->pb) = pb; } } @@ -258,44 +228,116 @@ /* Read chunks of 512 bytes till the end of the data */ while ((partial_message_length = recv(socket, partial_data, 512, 0)) > 0) { - g_string_append_len(data, partial_data, partial_message_length); - total_message_length += partial_message_length; + g_string_append_len(data, partial_data, partial_message_length); + total_message_length += partial_message_length; } if (partial_message_length == -1) { - purple_debug_warning("bonjour", "receive error: %s\n", strerror(errno)); + if (errno != EAGAIN) + purple_debug_warning("bonjour", "receive error: %s\n", strerror(errno)); if (total_message_length == 0) { return -1; } } - *message = data->str; - g_string_free(data, FALSE); + *message = g_string_free(data, FALSE); if (total_message_length != 0) purple_debug_info("bonjour", "Receive: -%s- %d bytes\n", *message, total_message_length); return total_message_length; } -static gint -_send_data(gint socket, char *message) +static void +_send_data_write_cb(gpointer data, gint source, PurpleInputCondition cond) { - gint message_len = strlen(message); - gint partial_sent = 0; - gchar *partial_message = message; + PurpleBuddy *pb = data; + BonjourBuddy *bb = pb->proto_data; + BonjourJabberConversation *bconv = bb->conversation; + int ret, writelen; + + /* TODO: Make sure that the stream has been established before sending */ + + writelen = purple_circ_buffer_get_max_read(bconv->tx_buf); + + if (writelen == 0) { + purple_input_remove(bconv->tx_handler); + bconv->tx_handler = -1; + return; + } - while ((partial_sent = send(socket, partial_message, message_len, 0)) < message_len) - { - if (partial_sent != -1) { - partial_message += partial_sent; - message_len -= partial_sent; - } else { - return -1; - } + ret = send(bconv->socket, bconv->tx_buf->outptr, writelen, 0); + + if (ret < 0 && errno == EAGAIN) + return; + else if (ret <= 0) { + PurpleConversation *conv; + const char *error = strerror(errno); + + purple_debug_error("bonjour", "Error sending message to buddy %s error: %s\n", + purple_buddy_get_name(pb), error ? error : "(null)"); + + conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, bb->name, pb->account); + if (conv != NULL) + purple_conversation_write(conv, NULL, + _("Unable to send message."), + PURPLE_MESSAGE_SYSTEM, time(NULL)); + + bonjour_jabber_close_conversation(bb->conversation); + bb->conversation = NULL; + return; } - return strlen(message); + purple_circ_buffer_mark_read(bconv->tx_buf, ret); +} + +static gint +_send_data(PurpleBuddy *pb, char *message) +{ + gint ret; + int len = strlen(message); + BonjourBuddy *bb = pb->proto_data; + BonjourJabberConversation *bconv = bb->conversation; + + /* If we're not ready to actually send, append it to the buffer */ + if (bconv->tx_handler != -1 + || bconv->connect_data != NULL + || !bconv->stream_started + || purple_circ_buffer_get_max_read(bconv->tx_buf) > 0) { + ret = -1; + errno = EAGAIN; + } else { + ret = send(bconv->socket, message, len, 0); + } + + if (ret == -1 && errno == EAGAIN) + ret = 0; + else if (ret <= 0) { + PurpleConversation *conv; + const char *error = strerror(errno); + + purple_debug_error("bonjour", "Error sending message to buddy %s error: %s\n", + purple_buddy_get_name(pb), error ? error : "(null)"); + + conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, bb->name, pb->account); + if (conv != NULL) + purple_conversation_write(conv, NULL, + _("Unable to send message."), + PURPLE_MESSAGE_SYSTEM, time(NULL)); + + bonjour_jabber_close_conversation(bb->conversation); + bb->conversation = NULL; + return -1; + } + + if (ret < len) { + if (bconv->tx_handler == -1) + bconv->tx_handler = purple_input_add(bconv->socket, PURPLE_INPUT_WRITE, + _send_data_write_cb, pb); + purple_circ_buffer_append(bconv->tx_buf, message + ret, len - ret); + } + + return ret; } static void @@ -303,17 +345,22 @@ { char *message = NULL; gint message_length; - PurpleBuddy *gb = (PurpleBuddy*)data; - PurpleAccount *account = gb->account; - PurpleConversation *conversation; - char *closed_conv_message; - BonjourBuddy *bb = (BonjourBuddy*)gb->proto_data; + PurpleBuddy *pb = data; + PurpleAccount *account = pb->account; + BonjourBuddy *bb = pb->proto_data; gboolean closed_conversation = FALSE; - xmlnode *message_node = NULL; + xmlnode *message_node; /* Read the data from the socket */ if ((message_length = _read_data(socket, &message)) == -1) { /* There have been an error reading from the socket */ + if (errno != EAGAIN) { + bonjour_jabber_close_conversation(bb->conversation); + bb->conversation = NULL; + + /* I guess we really don't need to notify the user. + * If they try to send another message it'll reconnect */ + } return; } else if (message_length == 0) { /* The other end has closed the socket */ closed_conversation = TRUE; @@ -329,118 +376,184 @@ /* Parse the message into an XMLnode for analysis */ message_node = xmlnode_from_str(message, strlen(message)); - /* Check if the start of the stream has been received, if not check that the current */ - /* data is the start of the stream */ - if (!(bb->conversation->stream_started)) - { - /* Check if this is the start of the stream */ - if ((message_node != NULL) && - g_ascii_strcasecmp(xmlnode_get_attrib(message_node, "xmlns"), "jabber:client") && - (xmlnode_get_attrib(message_node,"xmlns:stream") != NULL)) - { - bb->conversation->stream_started = TRUE; - } - else - { - /* TODO: This needs to be nonblocking! */ - if (send(bb->conversation->socket, DOCTYPE, strlen(DOCTYPE), 0) == -1) - { - purple_debug_error("bonjour", "Unable to start a conversation with %s\n", bb->name); - } - else - { - bb->conversation->stream_started = TRUE; - } - } - } - /* * Check that this is not the end of the conversation. This is * using a magic string, but xmlnode won't play nice when just * parsing an end tag */ - if (purple_str_has_prefix(message, STREAM_END) || (closed_conversation == TRUE)) { + if (closed_conversation || purple_str_has_prefix(message, STREAM_END)) { + PurpleConversation *conv; + /* Close the socket, clear the watcher and free memory */ - if (bb->conversation != NULL) { - close(bb->conversation->socket); - purple_input_remove(bb->conversation->watcher_id); - g_free(bb->conversation->buddy_name); - g_free(bb->conversation); - bb->conversation = NULL; - } + bonjour_jabber_close_conversation(bb->conversation); + bb->conversation = NULL; /* Inform the user that the conversation has been closed */ - conversation = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, gb->name, account); - closed_conv_message = g_strdup_printf(_("%s has closed the conversation."), gb->name); - purple_conversation_write(conversation, NULL, closed_conv_message, PURPLE_MESSAGE_SYSTEM, time(NULL)); - g_free(closed_conv_message); + conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, pb->name, account); + if (conv != NULL) { + char *tmp = g_strdup_printf(_("%s has closed the conversation."), pb->name); + purple_conversation_write(conv, NULL, tmp, PURPLE_MESSAGE_SYSTEM, time(NULL)); + g_free(tmp); + } + } else if (message_node != NULL) { + /* Parse the message to get the data and send to the ui */ + _jabber_parse_and_write_message_to_ui(message_node, account->gc, pb); } else { - /* Parse the message to get the data and send to the ui */ - _jabber_parse_and_write_message_to_ui(message, account->gc, gb); + /* TODO: Deal with receiving only a partial message */ } + g_free(message); if (message_node != NULL) xmlnode_free(message_node); } +struct _stream_start_data { + char *msg; + PurpleInputFunction tx_handler_cb; +}; + +static void +_start_stream(gpointer data, gint source, PurpleInputCondition condition) +{ + PurpleBuddy *pb = data; + BonjourBuddy *bb = pb->proto_data; + struct _stream_start_data *ss = bb->conversation->stream_data; + int len, ret; + + len = strlen(ss->msg); + + /* Start Stream */ + ret = send(source, ss->msg, len, 0); + + if (ret == -1 && errno == EAGAIN) + return; + else if (ret <= 0) { + const char *err = strerror(errno); + PurpleConversation *conv; + + purple_debug_error("bonjour", "Error starting stream with buddy %s at %s:%d error: %s\n", + purple_buddy_get_name(pb), bb->ip ? bb->ip : "(null)", bb->port_p2pj, err ? err : "(null)"); + + conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, bb->name, pb->account); + if (conv != NULL) + purple_conversation_write(conv, NULL, + _("Unable to send the message, the conversation couldn't be started."), + PURPLE_MESSAGE_SYSTEM, time(NULL)); + + bonjour_jabber_close_conversation(bb->conversation); + bb->conversation = NULL; + + return; + } + + /* This is EXTREMELY unlikely to happen */ + if (ret < len) { + char *tmp = g_strdup(ss->msg + ret); + g_free(ss->msg); + ss->msg = tmp; + return; + } + + /* Stream started; process the send buffer if there is one*/ + purple_input_remove(bb->conversation->tx_handler); + bb->conversation->tx_handler= -1; + + bb->conversation->stream_started = TRUE; + + g_free(ss->msg); + g_free(ss); + bb->conversation->stream_data = NULL; + + if (ss->tx_handler_cb) { + bb->conversation->tx_handler = purple_input_add(source, PURPLE_INPUT_WRITE, + ss->tx_handler_cb, pb); + /* We can probably write the data now. */ + (ss->tx_handler_cb)(pb, source, PURPLE_INPUT_WRITE); + } +} + static void _server_socket_handler(gpointer data, int server_socket, PurpleInputCondition condition) { - PurpleBuddy *gb = NULL; + PurpleBuddy *pb = NULL; struct sockaddr_in their_addr; /* connector's address information */ socklen_t sin_size = sizeof(struct sockaddr); int client_socket; - BonjourBuddy *bb = NULL; - BonjourJabber *bj = data; + BonjourBuddy *bb; char *address_text = NULL; PurpleBuddyList *bl = purple_get_blist(); struct _check_buddy_by_address_t *cbba; /* Check that it is a read condition */ - if (condition != PURPLE_INPUT_READ) { + if (condition != PURPLE_INPUT_READ) return; - } if ((client_socket = accept(server_socket, (struct sockaddr *)&their_addr, &sin_size)) == -1) - { return; - } + fcntl(client_socket, F_SETFL, O_NONBLOCK); /* Look for the buddy that has opened the conversation and fill information */ address_text = inet_ntoa(their_addr.sin_addr); cbba = g_new0(struct _check_buddy_by_address_t, 1); cbba->address = address_text; - cbba->gb = &gb; - cbba->bj = bj; + cbba->pb = &pb; + cbba->bj = data; g_hash_table_foreach(bl->buddies, _check_buddy_by_address, cbba); g_free(cbba); - if (gb == NULL) + if (pb == NULL) { purple_debug_info("bonjour", "We don't like invisible buddies, this is not a superheros comic\n"); close(client_socket); return; } - bb = (BonjourBuddy*)gb->proto_data; + bb = pb->proto_data; /* Check if the conversation has been previously started */ if (bb->conversation == NULL) { - bb->conversation = g_new(BonjourJabberConversation, 1); + int ret, len; + char *stream_start = g_strdup_printf(DOCTYPE, purple_account_get_username(pb->account), + purple_buddy_get_name(pb)); + + len = strlen(stream_start); + + /* Start the stream */ + ret = send(client_socket, stream_start, len, 0); + + if (ret == -1 && errno == EAGAIN) + ret = 0; + else if (ret <= 0) { + const char *err = strerror(errno); + + purple_debug_error("bonjour", "Error starting stream with buddy %s at %s:%d error: %s\n", + purple_buddy_get_name(pb), bb->ip ? bb->ip : "(null)", bb->port_p2pj, err ? err : "(null)"); + + close(client_socket); + g_free(stream_start); + + return; + } + + bb->conversation = bonjour_jabber_conv_new(); bb->conversation->socket = client_socket; - bb->conversation->stream_started = FALSE; - bb->conversation->buddy_name = g_strdup(gb->name); - bb->conversation->message_id = 1; + bb->conversation->rx_handler = purple_input_add(client_socket, + PURPLE_INPUT_READ, _client_socket_handler, pb); - if (bb->conversation->stream_started == FALSE) { - /* Start the stream */ - send(bb->conversation->socket, DOCTYPE, strlen(DOCTYPE), 0); + /* This is unlikely to happen */ + if (ret < len) { + struct _stream_start_data *ss = g_new(struct _stream_start_data, 1); + ss->msg = g_strdup(stream_start + ret); + ss->tx_handler_cb = NULL; /* We have nothing to write yet */ + bb->conversation->stream_data = ss; + /* Finish sending the stream start */ + bb->conversation->tx_handler = purple_input_add(client_socket, + PURPLE_INPUT_WRITE, _start_stream, pb); + } else { bb->conversation->stream_started = TRUE; } - /* Open a watcher for the client socket */ - bb->conversation->watcher_id = purple_input_add(client_socket, PURPLE_INPUT_READ, - _client_socket_handler, gb); + g_free(stream_start); } else { close(client_socket); } @@ -518,158 +631,224 @@ return data->port; } +static void +_connected_to_buddy(gpointer data, gint source, const gchar *error) +{ + PurpleBuddy *pb = data; + BonjourBuddy *bb = pb->proto_data; + int len, ret; + char *stream_start = g_strdup_printf(DOCTYPE, purple_account_get_username(pb->account), purple_buddy_get_name(pb)); + + bb->conversation->connect_data = NULL; + + if (source < 0) { + PurpleConversation *conv; + + purple_debug_error("bonjour", "Error connecting to buddy %s at %s:%d error: %s\n", + purple_buddy_get_name(pb), bb->ip ? bb->ip : "(null)", bb->port_p2pj, error ? error : "(null)"); + + conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, bb->name, pb->account); + if (conv != NULL) + purple_conversation_write(conv, NULL, + _("Unable to send the message, the conversation couldn't be started."), + PURPLE_MESSAGE_SYSTEM, time(NULL)); + + bonjour_jabber_close_conversation(bb->conversation); + bb->conversation = NULL; + return; + } + + len = strlen(stream_start); + + /* Start the stream and send queued messages */ + ret = send(source, stream_start, len, 0); + + if (ret == -1 && errno == EAGAIN) + ret = 0; + else if (ret <= 0) { + const char *err = strerror(errno); + PurpleConversation *conv; + + purple_debug_error("bonjour", "Error starting stream with buddy %s at %s:%d error: %s\n", + purple_buddy_get_name(pb), bb->ip ? bb->ip : "(null)", bb->port_p2pj, err ? err : "(null)"); + + conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, bb->name, pb->account); + if (conv != NULL) + purple_conversation_write(conv, NULL, + _("Unable to send the message, the conversation couldn't be started."), + PURPLE_MESSAGE_SYSTEM, time(NULL)); + + close(source); + bonjour_jabber_close_conversation(bb->conversation); + bb->conversation = NULL; + + g_free(stream_start); + + return; + } + + bb->conversation->socket = source; + bb->conversation->rx_handler = purple_input_add(source, + PURPLE_INPUT_READ, _client_socket_handler, pb); + + /* This is unlikely to happen */ + if (ret < len) { + struct _stream_start_data *ss = g_new(struct _stream_start_data, 1); + ss->msg = g_strdup(stream_start + ret); + ss->tx_handler_cb = _send_data_write_cb; + bb->conversation->stream_data = ss; + /* Finish sending the stream start */ + bb->conversation->tx_handler = purple_input_add(source, + PURPLE_INPUT_WRITE, _start_stream, pb); + } + /* Process the send buffer */ + else { + bb->conversation->stream_started = TRUE; + /* Watch for when we can write the buffered messages */ + bb->conversation->tx_handler = purple_input_add(source, PURPLE_INPUT_WRITE, + _send_data_write_cb, pb); + /* We can probably write the data now. */ + _send_data_write_cb(pb, source, PURPLE_INPUT_WRITE); + } + + g_free(stream_start); +} + int bonjour_jabber_send_message(BonjourJabber *data, const gchar *to, const gchar *body) { - xmlnode *message_node = NULL; - gchar *message = NULL; - gint message_length = -1; - xmlnode *message_body_node = NULL; - xmlnode *message_html_node = NULL; - xmlnode *message_html_body_node = NULL; - xmlnode *message_html_body_font_node = NULL; - xmlnode *message_x_node = NULL; - PurpleBuddy *gb = NULL; - BonjourBuddy *bb = NULL; - PurpleConversation *conversation = NULL; - char *message_from_ui = NULL; - char *stripped_message = NULL; - gint ret; + xmlnode *message_node, *node, *node2; + gchar *message; + PurpleBuddy *pb; + BonjourBuddy *bb; + int ret; - gb = purple_find_buddy(data->account, to); - if (gb == NULL) + pb = purple_find_buddy(data->account, to); + if (pb == NULL) { + purple_debug_info("bonjour", "Can't send a message to an offline buddy (%s).\n", to); /* You can not send a message to an offline buddy */ return -10000; - - bb = (BonjourBuddy *)gb->proto_data; - - /* Enclose the message from the UI within a "font" node */ - message_body_node = xmlnode_new("body"); - stripped_message = purple_markup_strip_html(body); - xmlnode_insert_data(message_body_node, stripped_message, strlen(stripped_message)); - g_free(stripped_message); - - message_from_ui = g_strconcat("<font>", body, "</font>", NULL); - message_html_body_font_node = xmlnode_from_str(message_from_ui, strlen(message_from_ui)); - g_free(message_from_ui); - - message_html_body_node = xmlnode_new("body"); - xmlnode_insert_child(message_html_body_node, message_html_body_font_node); + } - message_html_node = xmlnode_new("html"); - xmlnode_set_attrib(message_html_node, "xmlns", "http://www.w3.org/1999/xhtml"); - xmlnode_insert_child(message_html_node, message_html_body_node); - - message_x_node = xmlnode_new("x"); - xmlnode_set_attrib(message_x_node, "xmlns", "jabber:x:event"); - xmlnode_insert_child(message_x_node, xmlnode_new("composing")); - - message_node = xmlnode_new("message"); - xmlnode_set_attrib(message_node, "to", ((BonjourBuddy*)(gb->proto_data))->name); - xmlnode_set_attrib(message_node, "from", data->account->username); - xmlnode_set_attrib(message_node, "type", "chat"); - xmlnode_insert_child(message_node, message_body_node); - xmlnode_insert_child(message_node, message_html_node); - xmlnode_insert_child(message_node, message_x_node); - - message = xmlnode_to_str(message_node, &message_length); - xmlnode_free(message_node); + bb = pb->proto_data; /* Check if there is a previously open conversation */ if (bb->conversation == NULL) { - bb->conversation = g_new(BonjourJabberConversation, 1); - bb->conversation->socket = _connect_to_buddy(gb); - bb->conversation->stream_started = FALSE; - bb->conversation->buddy_name = g_strdup(gb->name); - bb->conversation->watcher_id = purple_input_add(bb->conversation->socket, - PURPLE_INPUT_READ, _client_socket_handler, gb); + PurpleProxyConnectData *connect_data; + PurpleProxyInfo *proxy_info; + + /* Make sure that the account always has a proxy of "none". + * This is kind of dirty, but proxy_connect_none() isn't exposed. */ + proxy_info = purple_account_get_proxy_info(data->account); + if (proxy_info == NULL) { + proxy_info = purple_proxy_info_new(); + purple_account_set_proxy_info(data->account, proxy_info); + } + purple_proxy_info_set_type(proxy_info, PURPLE_PROXY_NONE); + + connect_data = + purple_proxy_connect(data->account->gc, data->account, bb->ip, + bb->port_p2pj, _connected_to_buddy, pb); + + if (connect_data == NULL) { + purple_debug_error("bonjour", "Unable to connect to buddy (%s).\n", to); + return -10001; + } + + bb->conversation = bonjour_jabber_conv_new(); + bb->conversation->connect_data = connect_data; + /* We don't want _send_data() to register the tx_handler; + * that neeeds to wait until we're actually connected. */ + bb->conversation->tx_handler = 0; } - /* Check if the stream for the conversation has been started */ - if (bb->conversation->stream_started == FALSE) - { - /* Start the stream */ - if (send(bb->conversation->socket, DOCTYPE, strlen(DOCTYPE), 0) == -1) - { - purple_debug_error("bonjour", "Unable to start a conversation\n"); - purple_debug_warning("bonjour", "send error: %s\n", strerror(errno)); - conversation = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, bb->name, data->account); - purple_conversation_write(conversation, NULL, - _("Unable to send the message, the conversation couldn't be started."), - PURPLE_MESSAGE_SYSTEM, time(NULL)); - close(bb->conversation->socket); - purple_input_remove(bb->conversation->watcher_id); + message_node = xmlnode_new("message"); + xmlnode_set_attrib(message_node, "to", bb->name); + xmlnode_set_attrib(message_node, "from", purple_account_get_username(data->account)); + xmlnode_set_attrib(message_node, "type", "chat"); - /* Free all the data related to the conversation */ - g_free(bb->conversation->buddy_name); - g_free(bb->conversation); - bb->conversation = NULL; - g_free(message); - return 0; - } - - bb->conversation->stream_started = TRUE; - } - - /* Send the message */ - ret = _send_data(bb->conversation->socket, message) == -1; + /* Enclose the message from the UI within a "font" node */ + node = xmlnode_new_child(message_node, "body"); + message = purple_markup_strip_html(body); + xmlnode_insert_data(node, message, strlen(message)); g_free(message); - if (ret == -1) - return -10000; + node = xmlnode_new_child(message_node, "html"); + xmlnode_set_namespace(node, "http://www.w3.org/1999/xhtml"); + + node = xmlnode_new_child(node, "body"); + message = g_strdup_printf("<font>%s</font>", body); + node2 = xmlnode_from_str(message, strlen(message)); + g_free(message); + xmlnode_insert_child(node, node2); - return 1; + node = xmlnode_new_child(message_node, "x"); + xmlnode_set_namespace(node, "jabber:x:event"); + xmlnode_insert_child(node, xmlnode_new("composing")); + + message = xmlnode_to_str(message_node, NULL); + xmlnode_free(message_node); + + ret = _send_data(pb, message) >= 0; + + g_free(message); + + return ret; } void -bonjour_jabber_close_conversation(BonjourJabber *data, PurpleBuddy *gb) +bonjour_jabber_close_conversation(BonjourJabberConversation *bconv) { - BonjourBuddy *bb = (BonjourBuddy*)gb->proto_data; - - if (bb->conversation != NULL) + if (bconv != NULL) { - /* Send the end of the stream to the other end of the conversation */ - send(bb->conversation->socket, STREAM_END, strlen(STREAM_END), 0); - /* Close the socket and remove the watcher */ - close(bb->conversation->socket); - purple_input_remove(bb->conversation->watcher_id); + if (bconv->socket >= 0) { + /* Send the end of the stream to the other end of the conversation */ + if (bconv->stream_started) + send(bconv->socket, STREAM_END, strlen(STREAM_END), 0); + /* TODO: We're really supposed to wait for "</stream:stream>" before closing the socket */ + close(bconv->socket); + } + if (bconv->rx_handler != -1) + purple_input_remove(bconv->rx_handler); + if (bconv->tx_handler > 0) + purple_input_remove(bconv->tx_handler); /* Free all the data related to the conversation */ - g_free(bb->conversation->buddy_name); - g_free(bb->conversation); - bb->conversation = NULL; + purple_circ_buffer_destroy(bconv->tx_buf); + if (bconv->connect_data != NULL) + purple_proxy_connect_cancel(bconv->connect_data); + if (bconv->stream_data != NULL) { + struct _stream_start_data *ss = bconv->stream_data; + g_free(ss->msg); + g_free(ss); + } + g_free(bconv); } } void bonjour_jabber_stop(BonjourJabber *data) { - PurpleBuddy *gb = NULL; - BonjourBuddy *bb = NULL; - GSList *buddies; - GSList *l; + /* Close the server socket and remove the watcher */ + if (data->socket >= 0) + close(data->socket); + if (data->watcher_id > 0) + purple_input_remove(data->watcher_id); - /* Close the server socket and remove all the watcher */ - close(data->socket); - purple_input_remove(data->watcher_id); - - /* Close all the sockets and remove all the watchers after sending end streams */ + /* Close all the conversation sockets and remove all the watchers after sending end streams */ if (data->account->gc != NULL) { - buddies = purple_find_buddies(data->account, data->account->username); - for (l = buddies; l; l = l->next) - { - gb = (PurpleBuddy*)l->data; - bb = (BonjourBuddy*)gb->proto_data; - if (bb->conversation != NULL) - { - send(bb->conversation->socket, STREAM_END, strlen(STREAM_END), 0); - close(bb->conversation->socket); - purple_input_remove(bb->conversation->watcher_id); - } + GSList *buddies, *l; + + buddies = purple_find_buddies(data->account, purple_account_get_username(data->account)); + for (l = buddies; l; l = l->next) { + BonjourBuddy *bb = ((PurpleBuddy*) l->data)->proto_data; + bonjour_jabber_close_conversation(bb->conversation); + bb->conversation = NULL; } + g_slist_free(buddies); } }
--- a/libpurple/protocols/bonjour/jabber.h Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/bonjour/jabber.h Mon Jun 18 01:48:35 2007 +0000 @@ -27,9 +27,7 @@ #define _BONJOUR_JABBER_H_ #include "account.h" - -#define STREAM_END "</stream:stream>" -#define DOCTYPE "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<stream:stream xmlns=\"jabber:client\" xmlns:stream=\"http://etherx.jabber.org/streams\">" +#include "circbuffer.h" typedef struct _BonjourJabber { @@ -42,10 +40,12 @@ typedef struct _BonjourJabberConversation { gint socket; - gint watcher_id; - gchar* buddy_name; + guint rx_handler; + guint tx_handler; + PurpleCircBuffer *tx_buf; gboolean stream_started; - gint message_id; + PurpleProxyConnectData *connect_data; + gpointer stream_data; } BonjourJabberConversation; /** @@ -58,7 +58,7 @@ int bonjour_jabber_send_message(BonjourJabber *data, const gchar *to, const gchar *body); -void bonjour_jabber_close_conversation(BonjourJabber *data, PurpleBuddy *gb); +void bonjour_jabber_close_conversation(BonjourJabberConversation *bconv); void bonjour_jabber_stop(BonjourJabber *data);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/bonjour/mdns_common.c Mon Jun 18 01:48:35 2007 +0000 @@ -0,0 +1,175 @@ +/* + * 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 Library 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <string.h> + +#include "config.h" +#include "mdns_common.h" +#include "bonjour.h" +#include "buddy.h" +#include "debug.h" + + +/** + * Allocate space for the dns-sd data. + */ +BonjourDnsSd * +bonjour_dns_sd_new() +{ + BonjourDnsSd *data = g_new0(BonjourDnsSd, 1); + + return data; +} + +/** + * Deallocate the space of the dns-sd data. + */ +void +bonjour_dns_sd_free(BonjourDnsSd *data) +{ + g_free(data->first); + g_free(data->last); + g_free(data->phsh); + g_free(data->status); + g_free(data->vc); + g_free(data->msg); + g_free(data); +} + +/** + * Send a new dns-sd packet updating our status. + */ +void +bonjour_dns_sd_send_status(BonjourDnsSd *data, const char *status, const char *status_message) +{ + g_free(data->status); + g_free(data->msg); + + data->status = g_strdup(status); + data->msg = g_strdup(status_message); + + /* Update our text record with the new status */ + _mdns_publish(data, PUBLISH_UPDATE); /* <--We must control the errors */ +} + +/** + * Advertise our presence within the dns-sd daemon and start browsing + * for other bonjour peers. + */ +gboolean +bonjour_dns_sd_start(BonjourDnsSd *data) +{ + PurpleAccount *account; + PurpleConnection *gc; + gint dns_sd_socket; + gpointer opaque_data; + +#ifdef USE_BONJOUR_HOWL + sw_discovery_oid session_id; +#endif + + account = data->account; + gc = purple_account_get_connection(account); + + /* Initialize the dns-sd data and session */ +#ifndef USE_BONJOUR_APPLE + if (sw_discovery_init(&data->session) != SW_OKAY) + { + purple_debug_error("bonjour", "Unable to initialize an mDNS session.\n"); + + /* In Avahi, sw_discovery_init frees data->session but doesn't clear it */ + data->session = NULL; + + return FALSE; + } +#endif + + /* Publish our bonjour IM client at the mDNS daemon */ + + if (0 != _mdns_publish(data, PUBLISH_START)) + { + return FALSE; + } + + /* Advise the daemon that we are waiting for connections */ + +#ifdef USE_BONJOUR_APPLE + if (DNSServiceBrowse(&data->browser, 0, 0, ICHAT_SERVICE, NULL, _mdns_service_browse_callback, account) + != kDNSServiceErr_NoError) +#else /* USE_BONJOUR_HOWL */ + if (sw_discovery_browse(data->session, 0, ICHAT_SERVICE, NULL, _browser_reply, + account, &session_id) != SW_OKAY) +#endif + { + purple_debug_error("bonjour", "Unable to get service."); + return FALSE; + } + + /* Get the socket that communicates with the mDNS daemon and bind it to a */ + /* callback that will handle the dns_sd packets */ + +#ifdef USE_BONJOUR_APPLE + dns_sd_socket = DNSServiceRefSockFD(data->browser); + opaque_data = data->browser; +#else /* USE_BONJOUR_HOWL */ + dns_sd_socket = sw_discovery_socket(data->session); + opaque_data = data->session; +#endif + + gc->inpa = purple_input_add(dns_sd_socket, PURPLE_INPUT_READ, + _mdns_handle_event, opaque_data); + + return TRUE; +} + +/** + * Unregister the "_presence._tcp" service at the mDNS daemon. + */ + +void +bonjour_dns_sd_stop(BonjourDnsSd *data) +{ + PurpleAccount *account; + PurpleConnection *gc; + +#ifdef USE_BONJOUR_APPLE + if (data->advertisement == NULL || data->browser == NULL) +#else /* USE_BONJOUR_HOWL */ + if (data->session == NULL) +#endif + return; + +#ifdef USE_BONJOUR_HOWL + sw_discovery_cancel(data->session, data->session_id); +#endif + + account = data->account; + gc = purple_account_get_connection(account); + purple_input_remove(gc->inpa); + +#ifdef USE_BONJOUR_APPLE + /* hack: for win32, we need to stop listening to the advertisement pipe too */ + purple_input_remove(data->advertisement_handler); + + DNSServiceRefDeallocate(data->advertisement); + DNSServiceRefDeallocate(data->browser); + data->advertisement = NULL; + data->browser = NULL; +#else /* USE_BONJOUR_HOWL */ + g_free(data->session); + data->session = NULL; +#endif +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/bonjour/mdns_common.h Mon Jun 18 01:48:35 2007 +0000 @@ -0,0 +1,54 @@ +/* + * 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 Library 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _BONJOUR_MDNS_COMMON +#define _BONJOUR_MDNS_COMMON + +#include "mdns_types.h" + +#ifdef USE_BONJOUR_APPLE +#include "mdns_win32.h" +#elif defined USE_BONJOUR_HOWL +#include "mdns_howl.h" +#endif + +/** + * Allocate space for the dns-sd data. + */ +BonjourDnsSd *bonjour_dns_sd_new(void); + +/** + * Deallocate the space of the dns-sd data. + */ +void bonjour_dns_sd_free(BonjourDnsSd *data); + +/** + * Send a new dns-sd packet updating our status. + */ +void bonjour_dns_sd_send_status(BonjourDnsSd *data, const char *status, const char *status_message); + +/** + * Advertise our presence within the dns-sd daemon and start + * browsing for other bonjour peers. + */ +gboolean bonjour_dns_sd_start(BonjourDnsSd *data); + +/** + * Unregister the "_presence._tcp" service at the mDNS daemon. + */ +void bonjour_dns_sd_stop(BonjourDnsSd *data); + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/bonjour/mdns_howl.c Mon Jun 18 01:48:35 2007 +0000 @@ -0,0 +1,238 @@ +/* + * 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 Library 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "mdns_howl.h" + +#include "debug.h" +#include "buddy.h" + +sw_result HOWL_API +_publish_reply(sw_discovery discovery, sw_discovery_oid oid, + sw_discovery_publish_status status, sw_opaque extra) +{ + purple_debug_warning("bonjour", "_publish_reply --> Start\n"); + + /* Check the answer from the mDNS daemon */ + switch (status) + { + case SW_DISCOVERY_PUBLISH_STARTED : + purple_debug_info("bonjour", "_publish_reply --> Service started\n"); + break; + case SW_DISCOVERY_PUBLISH_STOPPED : + purple_debug_info("bonjour", "_publish_reply --> Service stopped\n"); + break; + case SW_DISCOVERY_PUBLISH_NAME_COLLISION : + purple_debug_info("bonjour", "_publish_reply --> Name collision\n"); + break; + case SW_DISCOVERY_PUBLISH_INVALID : + purple_debug_info("bonjour", "_publish_reply --> Service invalid\n"); + break; + } + + return SW_OKAY; +} + +sw_result HOWL_API +_resolve_reply(sw_discovery discovery, sw_discovery_oid oid, + sw_uint32 interface_index, sw_const_string name, + sw_const_string type, sw_const_string domain, + sw_ipv4_address address, sw_port port, + sw_octets text_record, sw_ulong text_record_len, + sw_opaque extra) +{ + BonjourBuddy *buddy; + PurpleAccount *account = (PurpleAccount*)extra; + gint address_length = 16; + sw_text_record_iterator iterator; + char key[SW_TEXT_RECORD_MAX_LEN]; + char value[SW_TEXT_RECORD_MAX_LEN]; + sw_uint32 value_length; + + sw_discovery_cancel(discovery, oid); + + /* create a buddy record */ + buddy = bonjour_buddy_new(name, account); + + /* Get the ip as a string */ + buddy->ip = g_malloc(address_length); + sw_ipv4_address_name(address, buddy->ip, address_length); + + buddy->port_p2pj = port; + + /* Obtain the parameters from the text_record */ + if ((text_record_len > 0) && (text_record) && (*text_record != '\0')) + { + sw_text_record_iterator_init(&iterator, text_record, text_record_len); + while (sw_text_record_iterator_next(iterator, key, (sw_octet *)value, &value_length) == SW_OKAY) + set_bonjour_buddy_value(buddy, key, value, value_length); + + sw_text_record_iterator_fina(iterator); + } + + if (!bonjour_buddy_check(buddy)) + { + bonjour_buddy_delete(buddy); + return SW_DISCOVERY_E_UNKNOWN; + } + + /* Add or update the buddy in our buddy list */ + bonjour_buddy_add_to_purple(buddy); + + return SW_OKAY; +} + +sw_result HOWL_API +_browser_reply(sw_discovery discovery, sw_discovery_oid oid, + sw_discovery_browse_status status, + sw_uint32 interface_index, sw_const_string name, + sw_const_string type, sw_const_string domain, + sw_opaque_t extra) +{ + sw_discovery_resolve_id rid; + PurpleAccount *account = (PurpleAccount*)extra; + PurpleBuddy *gb = NULL; + + switch (status) + { + case SW_DISCOVERY_BROWSE_INVALID: + purple_debug_warning("bonjour", "_browser_reply --> Invalid\n"); + break; + case SW_DISCOVERY_BROWSE_RELEASE: + purple_debug_warning("bonjour", "_browser_reply --> Release\n"); + break; + case SW_DISCOVERY_BROWSE_ADD_DOMAIN: + purple_debug_warning("bonjour", "_browser_reply --> Add domain\n"); + break; + case SW_DISCOVERY_BROWSE_ADD_DEFAULT_DOMAIN: + purple_debug_warning("bonjour", "_browser_reply --> Add default domain\n"); + break; + case SW_DISCOVERY_BROWSE_REMOVE_DOMAIN: + purple_debug_warning("bonjour", "_browser_reply --> Remove domain\n"); + break; + case SW_DISCOVERY_BROWSE_ADD_SERVICE: + /* A new peer has joined the network and uses iChat bonjour */ + purple_debug_info("bonjour", "_browser_reply --> Add service\n"); + if (g_ascii_strcasecmp(name, account->username) != 0) + { + if (sw_discovery_resolve(discovery, interface_index, name, type, + domain, _resolve_reply, extra, &rid) != SW_OKAY) + { + purple_debug_warning("bonjour", "_browser_reply --> Cannot send resolve\n"); + } + } + break; + case SW_DISCOVERY_BROWSE_REMOVE_SERVICE: + purple_debug_info("bonjour", "_browser_reply --> Remove service\n"); + gb = purple_find_buddy((PurpleAccount*)extra, name); + if (gb != NULL) + { + bonjour_buddy_delete(gb->proto_data); + purple_blist_remove_buddy(gb); + } + break; + case SW_DISCOVERY_BROWSE_RESOLVED: + purple_debug_info("bonjour", "_browse_reply --> Resolved\n"); + break; + default: + break; + } + + return SW_OKAY; +} + +int +_mdns_publish(BonjourDnsSd *data, PublishType type) +{ + sw_text_record dns_data; + sw_result publish_result = SW_OKAY; + char portstring[6]; + const char *jid, *aim, *email; + + /* Fill the data for the service */ + if (sw_text_record_init(&dns_data) != SW_OKAY) + { + purple_debug_error("bonjour", "Unable to initialize the data for the mDNS.\n"); + return -1; + } + + /* Convert the port to a string */ + snprintf(portstring, sizeof(portstring), "%d", data->port_p2pj); + + jid = purple_account_get_string(data->account, "jid", NULL); + aim = purple_account_get_string(data->account, "AIM", NULL); + email = purple_account_get_string(data->account, "email", NULL); + + /* We should try to follow XEP-0174, but some clients have "issues", so we humor them. + * See http://telepathy.freedesktop.org/wiki/SalutInteroperability + */ + + /* Needed by iChat */ + sw_text_record_add_key_and_string_value(dns_data, "txtvers", "1"); + /* Needed by Gaim/Pidgin <= 2.0.1 (remove at some point) */ + sw_text_record_add_key_and_string_value(dns_data, "1st", data->first); + /* Needed by Gaim/Pidgin <= 2.0.1 (remove at some point) */ + sw_text_record_add_key_and_string_value(dns_data, "last", data->last); + /* Needed by Adium */ + sw_text_record_add_key_and_string_value(dns_data, "port.p2pj", portstring); + /* Needed by iChat, Gaim/Pidgin <= 2.0.1 */ + sw_text_record_add_key_and_string_value(dns_data, "status", data->status); + /* Currently always set to "!" since we don't support AV and wont ever be in a conference */ + sw_text_record_add_key_and_string_value(dns_data, "vc", data->vc); + sw_text_record_add_key_and_string_value(dns_data, "ver", VERSION); + if (email != NULL && *email != '\0') + sw_text_record_add_key_and_string_value(dns_data, "email", email); + if (jid != NULL && *jid != '\0') + sw_text_record_add_key_and_string_value(dns_data, "jid", jid); + /* Nonstandard, but used by iChat */ + if (aim != NULL && *aim != '\0') + sw_text_record_add_key_and_string_value(dns_data, "AIM", aim); + if (data->msg != NULL && *data->msg != '\0') + sw_text_record_add_key_and_string_value(dns_data, "msg", data->msg); + if (data->phsh != NULL && *data->phsh != '\0') + sw_text_record_add_key_and_string_value(dns_data, "phsh", data->phsh); + + /* TODO: ext, nick, node */ + + /* Publish the service */ + switch (type) + { + case PUBLISH_START: + publish_result = sw_discovery_publish(data->session, 0, purple_account_get_username(data->account), ICHAT_SERVICE, NULL, + NULL, data->port_p2pj, sw_text_record_bytes(dns_data), sw_text_record_len(dns_data), + _publish_reply, NULL, &data->session_id); + break; + case PUBLISH_UPDATE: + publish_result = sw_discovery_publish_update(data->session, data->session_id, + sw_text_record_bytes(dns_data), sw_text_record_len(dns_data)); + break; + } + if (publish_result != SW_OKAY) + { + purple_debug_error("bonjour", "Unable to publish or change the status of the _presence._tcp service.\n"); + return -1; + } + + /* Free the memory used by temp data */ + sw_text_record_fina(dns_data); + + return 0; +} + +void +_mdns_handle_event(gpointer data, gint source, PurpleInputCondition condition) +{ + sw_discovery_read_socket((sw_discovery)data); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/bonjour/mdns_howl.h Mon Jun 18 01:48:35 2007 +0000 @@ -0,0 +1,47 @@ +/* + * 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 Library 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _BONJOUR_MDNS_HOWL +#define _BONJOUR_MDNS_HOWL + +#include "config.h" + +#ifdef USE_BONJOUR_HOWL + +#include <howl.h> +#include <glib.h> +#include "mdns_types.h" + +/* callback functions */ + +sw_result HOWL_API _publish_reply(sw_discovery discovery, sw_discovery_oid oid, sw_discovery_publish_status status, sw_opaque extra); + +sw_result HOWL_API _resolve_reply(sw_discovery discovery, sw_discovery_oid oid, sw_uint32 interface_index, sw_const_string name, + sw_const_string type, sw_const_string domain, sw_ipv4_address address, sw_port port, sw_octets text_record, + sw_ulong text_record_len, sw_opaque extra); + +sw_result HOWL_API _browser_reply(sw_discovery discovery, sw_discovery_oid oid, sw_discovery_browse_status status, + sw_uint32 interface_index, sw_const_string name, sw_const_string type, sw_const_string domain, sw_opaque_t extra); + + +/* interface functions */ + +int _mdns_publish(BonjourDnsSd *data, PublishType type); +void _mdns_handle_event(gpointer data, gint source, PurpleInputCondition condition); + +#endif + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/bonjour/mdns_types.h Mon Jun 18 01:48:35 2007 +0000 @@ -0,0 +1,63 @@ +/* + * 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 Library 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _BONJOUR_MDNS_TYPES +#define _BONJOUR_MDNS_TYPES + +#include <glib.h> +#include "account.h" +#include "config.h" + +#ifdef USE_BONJOUR_APPLE +#include "dns_sd_proxy.h" +#else /* USE_BONJOUR_HOWL */ +#include <howl.h> +#endif + +#define ICHAT_SERVICE "_presence._tcp." + +/** + * Data to be used by the dns-sd connection. + */ +typedef struct _BonjourDnsSd +{ +#ifdef USE_BONJOUR_APPLE + DNSServiceRef advertisement; + DNSServiceRef browser; + + int advertisement_handler; /* hack... windows bonjour is broken, so we have to have this */ +#else /* USE_BONJOUR_HOWL */ + sw_discovery session; + sw_discovery_oid session_id; +#endif + + PurpleAccount *account; + gchar *first; + gchar *last; + gint port_p2pj; + gchar *phsh; + gchar *status; + gchar *vc; + gchar *msg; +} BonjourDnsSd; + +typedef enum _PublishType { + PUBLISH_START, + PUBLISH_UPDATE +} PublishType; + + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/bonjour/mdns_win32.c Mon Jun 18 01:48:35 2007 +0000 @@ -0,0 +1,296 @@ +/* + * 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 Library 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "mdns_win32.h" + +#include "debug.h" + +/* data structure for the resolve callback */ +typedef struct _ResolveCallbackArgs +{ + DNSServiceRef resolver; + int resolver_fd; + + PurpleDnsQueryData *query; + gchar *fqn; + + BonjourBuddy* buddy; +} ResolveCallbackArgs; + +static void +_mdns_parse_text_record(BonjourBuddy* buddy, const char* record, uint16_t record_len) +{ + const char *txt_entry; + uint8_t txt_len; + int i; + + for (i = 0; buddy_TXT_records[i] != NULL; i++) { + txt_entry = TXTRecordGetValuePtr(record_len, record, buddy_TXT_records[i], &txt_len); + if (txt_entry != NULL) + set_bonjour_buddy_value(buddy, buddy_TXT_records[i], txt_entry, txt_len); + } +} + +static void DNSSD_API +_mdns_text_record_query_callback(DNSServiceRef DNSServiceRef, DNSServiceFlags flags, + uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *fullname, + uint16_t rrtype, uint16_t rrclass, uint16_t rdlen, const void *rdata, + uint32_t ttl, void *context) +{ + if (kDNSServiceErr_NoError != errorCode) + purple_debug_error("bonjour", "text record query - callback error.\n"); + else if (flags & kDNSServiceFlagsAdd) + { + BonjourBuddy *buddy = (BonjourBuddy*)context; + _mdns_parse_text_record(buddy, rdata, rdlen); + bonjour_buddy_add_to_purple(buddy); + } +} + +static void +_mdns_resolve_host_callback(GSList *hosts, gpointer data, const char *error_message) +{ + ResolveCallbackArgs* args = (ResolveCallbackArgs*)data; + + if (!hosts || !hosts->data) + purple_debug_error("bonjour", "host resolution - callback error.\n"); + else + { + struct sockaddr_in *addr = (struct sockaddr_in*)g_slist_nth_data(hosts, 1); + BonjourBuddy* buddy = args->buddy; + + buddy->ip = g_strdup(inet_ntoa(addr->sin_addr)); + + /* finally, set up the continuous txt record watcher, and add the buddy to purple */ + + if (kDNSServiceErr_NoError == DNSServiceQueryRecord(&buddy->txt_query, 0, 0, args->fqn, + kDNSServiceType_TXT, kDNSServiceClass_IN, _mdns_text_record_query_callback, buddy)) + { + gint fd = DNSServiceRefSockFD(buddy->txt_query); + buddy->txt_query_fd = purple_input_add(fd, PURPLE_INPUT_READ, _mdns_handle_event, buddy->txt_query); + + bonjour_buddy_add_to_purple(buddy); + } + else + bonjour_buddy_delete(buddy); + + } + + /* free the hosts list*/ + g_slist_free(hosts); + + /* free the remaining args memory */ + purple_dnsquery_destroy(args->query); + g_free(args->fqn); + g_free(args); +} + +static void DNSSD_API +_mdns_service_resolve_callback(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, + const char *fullname, const char *hosttarget, uint16_t port, uint16_t txtLen, const char *txtRecord, void *context) +{ + ResolveCallbackArgs *args = (ResolveCallbackArgs*)context; + + /* remove the input fd and destroy the service ref */ + purple_input_remove(args->resolver_fd); + DNSServiceRefDeallocate(args->resolver); + + if (kDNSServiceErr_NoError != errorCode) + { + purple_debug_error("bonjour", "service resolver - callback error.\n"); + bonjour_buddy_delete(args->buddy); + g_free(args); + } + else + { + args->buddy->port_p2pj = ntohs(port); + + /* parse the text record */ + _mdns_parse_text_record(args->buddy, txtRecord, txtLen); + + /* set more arguments, and start the host resolver */ + args->fqn = g_strdup(fullname); + + if (!(args->query = + purple_dnsquery_a(hosttarget, port, _mdns_resolve_host_callback, args))) + { + purple_debug_error("bonjour", "service resolver - host resolution failed.\n"); + bonjour_buddy_delete(args->buddy); + g_free(args->fqn); + g_free(args); + } + } + +} + +static void DNSSD_API +_mdns_service_register_callback(DNSServiceRef sdRef, DNSServiceFlags flags, DNSServiceErrorType errorCode, + const char *name, const char *regtype, const char *domain, void *context) +{ + /* we don't actually care about anything said in this callback - this is only here because Bonjour for windows is broken */ + if (kDNSServiceErr_NoError != errorCode) + purple_debug_error("bonjour", "service advertisement - callback error.\n"); + else + purple_debug_info("bonjour", "service advertisement - callback.\n"); +} + +void DNSSD_API +_mdns_service_browse_callback(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, + DNSServiceErrorType errorCode, const char *serviceName, const char *regtype, const char *replyDomain, void *context) +{ + PurpleAccount *account = (PurpleAccount*)context; + PurpleBuddy *gb = NULL; + + if (kDNSServiceErr_NoError != errorCode) + purple_debug_error("bonjour", "service browser - callback error"); + else if (flags & kDNSServiceFlagsAdd) + { + /* A presence service instance has been discovered... check it isn't us! */ + if (g_ascii_strcasecmp(serviceName, account->username) != 0) + { + /* OK, lets go ahead and resolve it to add to the buddy list */ + ResolveCallbackArgs *args = g_new0(ResolveCallbackArgs, 1); + args->buddy = bonjour_buddy_new(serviceName, account); + + if (kDNSServiceErr_NoError != DNSServiceResolve(&args->resolver, 0, 0, serviceName, regtype, replyDomain, _mdns_service_resolve_callback, args)) + { + bonjour_buddy_delete(args->buddy); + g_free(args); + purple_debug_error("bonjour", "service browser - failed to resolve service.\n"); + } + else + { + /* get a file descriptor for this service ref, and add it to the input list */ + gint resolver_fd = DNSServiceRefSockFD(args->resolver); + args->resolver_fd = purple_input_add(resolver_fd, PURPLE_INPUT_READ, _mdns_handle_event, args->resolver); + } + } + } + else + { + /* A peer has sent a goodbye packet, remove them from the buddy list */ + purple_debug_info("bonjour", "service browser - remove notification\n"); + gb = purple_find_buddy(account, serviceName); + if (gb != NULL) + { + bonjour_buddy_delete(gb->proto_data); + purple_blist_remove_buddy(gb); + } + } +} + +int +_mdns_publish(BonjourDnsSd *data, PublishType type) +{ + TXTRecordRef dns_data; + char portstring[6]; + int ret = 0; + const char *jid, *aim, *email; + DNSServiceErrorType set_ret; + + TXTRecordCreate(&dns_data, 256, NULL); + + /* Convert the port to a string */ + snprintf(portstring, sizeof(portstring), "%d", data->port_p2pj); + + jid = purple_account_get_string(data->account, "jid", NULL); + aim = purple_account_get_string(data->account, "AIM", NULL); + email = purple_account_get_string(data->account, "email", NULL); + + /* We should try to follow XEP-0174, but some clients have "issues", so we humor them. + * See http://telepathy.freedesktop.org/wiki/SalutInteroperability + */ + + /* Needed by iChat */ + set_ret = TXTRecordSetValue(&dns_data, "txtvers", 1, "1"); + /* Needed by Gaim/Pidgin <= 2.0.1 (remove at some point) */ + if (set_ret == kDNSServiceErr_NoError) + set_ret = TXTRecordSetValue(&dns_data, "1st", strlen(data->first), data->first); + /* Needed by Gaim/Pidgin <= 2.0.1 (remove at some point) */ + if (set_ret == kDNSServiceErr_NoError) + set_ret = TXTRecordSetValue(&dns_data, "last", strlen(data->last), data->last); + /* Needed by Adium */ + if (set_ret == kDNSServiceErr_NoError) + set_ret = TXTRecordSetValue(&dns_data, "port.p2pj", strlen(portstring), portstring); + /* Needed by iChat, Gaim/Pidgin <= 2.0.1 */ + if (set_ret == kDNSServiceErr_NoError) + set_ret = TXTRecordSetValue(&dns_data, "status", strlen(data->status), data->status); + if (set_ret == kDNSServiceErr_NoError) + set_ret = TXTRecordSetValue(&dns_data, "ver", strlen(VERSION), VERSION); + /* Currently always set to "!" since we don't support AV and wont ever be in a conference */ + if (set_ret == kDNSServiceErr_NoError) + set_ret = TXTRecordSetValue(&dns_data, "vc", strlen(data->vc), data->vc); + if (set_ret == kDNSServiceErr_NoError && email != NULL && *email != '\0') + set_ret = TXTRecordSetValue(&dns_data, "email", strlen(email), email); + if (set_ret == kDNSServiceErr_NoError && jid != NULL && *jid != '\0') + set_ret = TXTRecordSetValue(&dns_data, "jid", strlen(jid), jid); + /* Nonstandard, but used by iChat */ + if (set_ret == kDNSServiceErr_NoError && aim != NULL && *aim != '\0') + set_ret = TXTRecordSetValue(&dns_data, "AIM", strlen(aim), aim); + if (set_ret == kDNSServiceErr_NoError && data->msg != NULL && *data->msg != '\0') + set_ret = TXTRecordSetValue(&dns_data, "msg", strlen(data->msg), data->msg); + if (set_ret == kDNSServiceErr_NoError && data->phsh != NULL && *data->phsh != '\0') + set_ret = TXTRecordSetValue(&dns_data, "phsh", strlen(data->phsh), data->phsh); + + /* TODO: ext, nick, node */ + + if (set_ret != kDNSServiceErr_NoError) + { + purple_debug_error("bonjour", "Unable to allocate memory for text record.\n"); + ret = -1; + } + else + { + DNSServiceErrorType err = kDNSServiceErr_NoError; + + /* OK, we're done constructing the text record, (re)publish the service */ + + switch (type) + { + case PUBLISH_START: + err = DNSServiceRegister(&data->advertisement, 0, 0, purple_account_get_username(data->account), ICHAT_SERVICE, + NULL, NULL, htons(data->port_p2pj), TXTRecordGetLength(&dns_data), TXTRecordGetBytesPtr(&dns_data), + _mdns_service_register_callback, NULL); + break; + + case PUBLISH_UPDATE: + err = DNSServiceUpdateRecord(data->advertisement, NULL, 0, TXTRecordGetLength(&dns_data), TXTRecordGetBytesPtr(&dns_data), 0); + break; + } + + if (kDNSServiceErr_NoError != err) + { + purple_debug_error("bonjour", "Failed to publish presence service.\n"); + ret = -1; + } + else if (PUBLISH_START == type) + { + /* hack: Bonjour on windows is broken. We don't care about the callback but we have to listen anyway */ + gint advertisement_fd = DNSServiceRefSockFD(data->advertisement); + data->advertisement_handler = purple_input_add(advertisement_fd, PURPLE_INPUT_READ, _mdns_handle_event, data->advertisement); + } + } + + /* Free the memory used by temp data */ + TXTRecordDeallocate(&dns_data); + return ret; +} + +void +_mdns_handle_event(gpointer data, gint source, PurpleInputCondition condition) +{ + DNSServiceProcessResult((DNSServiceRef)data); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/bonjour/mdns_win32.h Mon Jun 18 01:48:35 2007 +0000 @@ -0,0 +1,40 @@ +/* + * 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 Library 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _BONJOUR_MDNS_WIN32 +#define _BONJOUR_MDNS_WIN32 + +#ifdef USE_BONJOUR_APPLE + +#include <glib.h> +#include "mdns_types.h" +#include "buddy.h" +#include "dnsquery.h" +#include "dns_sd_proxy.h" + +/* Bonjour async callbacks */ + +void DNSSD_API _mdns_service_browse_callback(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, + DNSServiceErrorType errorCode, const char *serviceName, const char *regtype, const char *replyDomain, void *context); + +/* interface functions */ + +int _mdns_publish(BonjourDnsSd *data, PublishType type); +void _mdns_handle_event(gpointer data, gint source, PurpleInputCondition condition); + +#endif + +#endif
--- a/libpurple/protocols/gg/gg.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/gg/gg.c Mon Jun 18 01:48:35 2007 +0000 @@ -253,8 +253,8 @@ /* */ -/* static void ggp_callback_buddylist_save_ok(PurpleConnection *gc, gchar *file) {{{ */ -static void ggp_callback_buddylist_save_ok(PurpleConnection *gc, gchar *file) +/* static void ggp_callback_buddylist_save_ok(PurpleConnection *gc, const char *file) {{{ */ +static void ggp_callback_buddylist_save_ok(PurpleConnection *gc, const char *file) { PurpleAccount *account = purple_connection_get_account(gc); @@ -277,7 +277,7 @@ purple_debug_error("gg", "Could not open file: %s\n", file); purple_notify_error(account, _("Couldn't open file"), msg, NULL); g_free(msg); - g_free(file); + g_free(buddylist); return; }
--- a/libpurple/protocols/irc/msgs.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/irc/msgs.c Mon Jun 18 01:48:35 2007 +0000 @@ -369,6 +369,7 @@ if (!strcmp(name, "322")) { PurpleRoomlistRoom *room; + char *topic; if (!args[0] || !args[1] || !args[2] || !args[3]) return; @@ -376,7 +377,9 @@ room = purple_roomlist_room_new(PURPLE_ROOMLIST_ROOMTYPE_ROOM, args[1], NULL); purple_roomlist_room_add_field(irc->roomlist, room, args[1]); purple_roomlist_room_add_field(irc->roomlist, room, GINT_TO_POINTER(strtol(args[2], NULL, 10))); - purple_roomlist_room_add_field(irc->roomlist, room, args[3]); + topic = irc_mirc2txt(args[3]); + purple_roomlist_room_add_field(irc->roomlist, room, topic); + g_free(topic); purple_roomlist_room_add(irc->roomlist, room); } }
--- a/libpurple/protocols/irc/parse.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/irc/parse.c Mon Jun 18 01:48:35 2007 +0000 @@ -402,6 +402,22 @@ switch (result[i]) { case '\002': case '\003': + /* Foreground color */ + if (isdigit(result[i + 1])) + i++; + if (isdigit(result[i + 1])) + i++; + /* Optional comma and background color */ + if (result[i + 1] == ',') { + i++; + if (isdigit(result[i + 1])) + i++; + if (isdigit(result[i + 1])) + i++; + } + /* Note that i still points to the last character + * of the color selection string. */ + continue; case '\007': case '\017': case '\026':
--- a/libpurple/protocols/jabber/.todo Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/jabber/.todo Mon Jun 18 01:48:35 2007 +0000 @@ -38,7 +38,7 @@ formatted. enhancement-request so that the birthday field in the setinfo form would split up into relevant fields allowing for a strict syntax (like year--month--day or so, perhaps even dropdown menus) </note> <note priority="low" time="1037890968"> - have set info pre-fill values from the server when no local vcard exists. this will help people migrating to gaim + have set info pre-fill values from the server when no local vcard exists. this will help people migrating to libpurple-based clients </note> </note> <note priority="verylow" time="1036044192">
--- a/libpurple/protocols/jabber/Makefile.am Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/jabber/Makefile.am Mon Jun 18 01:48:35 2007 +0000 @@ -43,15 +43,12 @@ if STATIC_JABBER st = -DPURPLE_STATIC_PRPL -noinst_LIBRARIES = libjabber.a libxmpp.a +noinst_LIBRARIES = libjabber.a pkg_LTLIBRARIES = -libjabber_a_SOURCES = $(JABBERSOURCES) +libjabber_a_SOURCES = $(JABBERSOURCES) libxmpp.c libjabber_a_CFLAGS = $(AM_CFLAGS) -libxmpp_a_SOURCES = libxmpp.c -libxmpp_a_CFLAGS = $(AM_CFLAGS) - else st =
--- a/libpurple/protocols/jabber/disco.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/jabber/disco.c Mon Jun 18 01:48:35 2007 +0000 @@ -224,17 +224,17 @@ /* If the server supports JABBER_CAP_GOOGLE_ROSTER; we will have already requested it */ jabber_roster_request(js); } - + /* Send initial presence; this will trigger receipt of presence for contacts on the roster */ gpresence = purple_account_get_presence(js->gc->account); status = purple_presence_get_active_status(gpresence); - jabber_presence_send(js->gc->account, status); + jabber_presence_send(js->gc->account, status); } static void jabber_disco_server_info_result_cb(JabberStream *js, xmlnode *packet, gpointer data) { - xmlnode *query, *child; + xmlnode *query, *child; const char *from = xmlnode_get_attrib(packet, "from"); const char *type = xmlnode_get_attrib(packet, "type"); @@ -257,7 +257,7 @@ return; } - for (child = xmlnode_get_child(query, "identity"); child; + for (child = xmlnode_get_child(query, "identity"); child; child = xmlnode_get_next_twin(child)) { const char *category, *type, *name; category = xmlnode_get_attrib(child, "category"); @@ -266,7 +266,7 @@ type = xmlnode_get_attrib(child, "type"); if (!type || strcmp(type, "im")) continue; - + name = xmlnode_get_attrib(child, "name"); if (!name) continue; @@ -279,7 +279,7 @@ } } - for (child = xmlnode_get_child(query, "feature"); child; + for (child = xmlnode_get_child(query, "feature"); child; child = xmlnode_get_next_twin(child)) { const char *var; var = xmlnode_get_attrib(child, "var"); @@ -324,11 +324,16 @@ for(child = xmlnode_get_child(query, "item"); child; child = xmlnode_get_next_twin(child)) { JabberIq *iq; - const char *jid; + const char *jid, *node; if(!(jid = xmlnode_get_attrib(child, "jid"))) continue; + /* we don't actually care about the specific nodes, + * so we won't query them */ + if((node = xmlnode_get_attrib(child, "node"))) + continue; + iq = jabber_iq_new_query(js, JABBER_IQ_GET, "http://jabber.org/protocol/disco#info"); xmlnode_set_attrib(iq->node, "to", jid); jabber_iq_send(iq);
--- a/libpurple/protocols/jabber/jabber.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/jabber/jabber.c Mon Jun 18 01:48:35 2007 +0000 @@ -463,7 +463,11 @@ JabberStream *js = gc->proto_data; if (source < 0) { - purple_connection_error(gc, _("Couldn't connect to host")); + gchar *tmp; + tmp = g_strdup_printf(_("Could not establish a connection with the server:\n%s"), + error); + purple_connection_error(gc, tmp); + g_free(tmp); return; } @@ -1070,8 +1074,10 @@ /* lets make sure our buddy icon is up to date * before we go letting people know we're here */ img = purple_buddy_icons_find_account_icon(js->gc->account); - jabber_set_buddy_icon(js->gc, img); - purple_imgstore_unref(img); + if(NULL != img) { + jabber_set_buddy_icon(js->gc, img); + purple_imgstore_unref(img); + } /* now we can alert the core that we're ready to send status */ purple_connection_set_state(js->gc, PURPLE_CONNECTED);
--- a/libpurple/protocols/jabber/libxmpp.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/jabber/libxmpp.c Mon Jun 18 01:48:35 2007 +0000 @@ -64,7 +64,7 @@ jabber_set_info, /* set_info */ jabber_send_typing, /* send_typing */ jabber_buddy_get_info, /* get_info */ - jabber_presence_send, /* set_away */ + jabber_presence_send, /* set_status */ jabber_idle_set, /* set_idle */ NULL, /* change_passwd */ jabber_roster_add_buddy, /* add_buddy */
--- a/libpurple/protocols/jabber/message.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/jabber/message.c Mon Jun 18 01:48:35 2007 +0000 @@ -544,7 +544,6 @@ char *buf; char *xhtml; char *resource; - char *c; if(!who || !msg) return 0;
--- a/libpurple/protocols/jabber/presence.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/jabber/presence.c Mon Jun 18 01:48:35 2007 +0000 @@ -106,11 +106,12 @@ return; disconnected = purple_account_is_disconnected(account); - primitive = purple_status_type_get_primitive(purple_status_get_type(status)); if(disconnected) return; + primitive = purple_status_type_get_primitive(purple_status_get_type(status)); + gc = purple_account_get_connection(account); js = gc->proto_data; @@ -378,8 +379,7 @@ } else if(xmlns && !strcmp(xmlns, "vcard-temp:x:update")) { xmlnode *photo = xmlnode_get_child(y, "photo"); if(photo) { - if(avatar_hash) - g_free(avatar_hash); + g_free(avatar_hash); avatar_hash = xmlnode_get_data(photo); } } @@ -408,8 +408,7 @@ jabber_id_free(jid); g_free(status); g_free(room_jid); - if(avatar_hash) - g_free(avatar_hash); + g_free(avatar_hash); return; } @@ -425,8 +424,7 @@ jabber_id_free(jid); g_free(status); g_free(room_jid); - if(avatar_hash) - g_free(avatar_hash); + g_free(avatar_hash); return; } @@ -509,8 +507,7 @@ purple_debug_warning("jabber", "Got presence for unknown buddy %s on account %s (%x)", buddy_name, purple_account_get_username(js->gc->account), js->gc->account); jabber_id_free(jid); - if(avatar_hash) - g_free(avatar_hash); + g_free(avatar_hash); g_free(buddy_name); g_free(status); return; @@ -567,8 +564,7 @@ } g_free(status); jabber_id_free(jid); - if(avatar_hash) - g_free(avatar_hash); + g_free(avatar_hash); } void jabber_presence_subscription_set(JabberStream *js, const char *who, const char *type) @@ -607,7 +603,7 @@ formatted_msg = NULL; if(formatted_msg) - purple_markup_html_to_xhtml(formatted_msg, NULL, msg); + *msg = purple_markup_strip_html(formatted_msg); } if(priority)
--- a/libpurple/protocols/jabber/si.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/jabber/si.c Mon Jun 18 01:48:35 2007 +0000 @@ -26,6 +26,7 @@ #include "cipher.h" #include "debug.h" #include "ft.h" +#include "request.h" #include "network.h" #include "notify.h" @@ -104,6 +105,9 @@ jsx->connect_data = NULL; if(source < 0) { + purple_debug_warning("jabber", + "si connection failed, jid was %s, host was %s, error was %s\n", + streamhost->jid, streamhost->host, error_message); jsx->streamhosts = g_list_remove(jsx->streamhosts, streamhost); g_free(streamhost->jid); g_free(streamhost->host); @@ -769,6 +773,36 @@ } } +static void resource_select_cancel_cb(PurpleXfer *xfer, PurpleRequestFields *fields) +{ + purple_xfer_cancel_local(xfer); +} + +static void do_transfer_send(PurpleXfer *xfer, const char *resource) +{ + JabberSIXfer *jsx = xfer->data; + char **who_v = g_strsplit(xfer->who, "/", 2); + char *who; + + who = g_strdup_printf("%s/%s", who_v[0], resource); + g_strfreev(who_v); + g_free(xfer->who); + xfer->who = who; + jabber_disco_info_do(jsx->js, who, + jabber_si_xfer_send_disco_cb, xfer); +} + +static void resource_select_ok_cb(PurpleXfer *xfer, PurpleRequestFields *fields) +{ + PurpleRequestField *field = purple_request_fields_get_field(fields, "resource"); + int selected_id = purple_request_field_choice_get_value(field); + GList *labels = purple_request_field_choice_get_labels(field); + + const char *selected_label = g_list_nth_data(labels, selected_id); + + do_transfer_send(xfer, selected_label); +} + static void jabber_si_xfer_init(PurpleXfer *xfer) { JabberSIXfer *jsx = xfer->data; @@ -776,26 +810,65 @@ if(purple_xfer_get_type(xfer) == PURPLE_XFER_SEND) { JabberBuddy *jb; JabberBuddyResource *jbr = NULL; + char *resource; + + if(NULL != (resource = jabber_get_resource(xfer->who))) { + /* they've specified a resource, no need to ask or + * default or anything, just do it */ + + do_transfer_send(xfer, resource); + g_free(resource); + } jb = jabber_buddy_find(jsx->js, xfer->who, TRUE); - /* XXX */ - if(!jb) - return; + + if(!jb || !jb->resources) { + /* no resources online, we're trying to send to someone + * whose presence we're not subscribed to, or + * someone who is offline. Let's inform the user */ + char *msg; - /* XXX: for now, send to the first resource available */ - if(jb->resources != NULL) { - char **who_v = g_strsplit(xfer->who, "/", 2); - char *who; + if(!jb) { + msg = g_strdup_printf(_("Unable to send file to %s, invalid JID"), xfer->who); + } else if(jb->subscription & JABBER_SUB_TO) { + msg = g_strdup_printf(_("Unable to send file to %s, user is not online"), xfer->who); + } else { + msg = g_strdup_printf(_("Unable to send file to %s, not subscribed to user presence"), xfer->who); + } + + purple_notify_error(jsx->js->gc, _("File Send Failed"), _("File Send Failed"), msg); + g_free(msg); + } else if(g_list_length(jb->resources) == 1) { + /* only 1 resource online (probably our most common case) + * so no need to ask who to send to */ + jbr = jb->resources->data; + + do_transfer_send(xfer, jbr->name); - jbr = jabber_buddy_find_resource(jb, NULL); - who = g_strdup_printf("%s/%s", who_v[0], jbr->name); - g_strfreev(who_v); - g_free(xfer->who); - xfer->who = who; - jabber_disco_info_do(jsx->js, who, - jabber_si_xfer_send_disco_cb, xfer); } else { - return; /* XXX: ick */ + /* we've got multiple resources, we need to pick one to send to */ + GList *l; + char *msg = g_strdup_printf(_("Please select which resource of %s you would like to send a file to"), xfer->who); + PurpleRequestFields *fields = purple_request_fields_new(); + PurpleRequestField *field = purple_request_field_choice_new("resource", _("Resource"), 0); + PurpleRequestFieldGroup *group = purple_request_field_group_new(NULL); + + for(l = jb->resources; l; l = l->next) + { + jbr = l->data; + + purple_request_field_choice_add(field, jbr->name); + } + + purple_request_field_group_add_field(group, field); + + purple_request_fields_add_group(fields, group); + + purple_request_fields(jsx->js->gc, _("Select a Resource"), msg, NULL, fields, + _("Send File"), G_CALLBACK(resource_select_ok_cb), _("Cancel"), G_CALLBACK(resource_select_cancel_cb), + jsx->js->gc->account, xfer->who, NULL, xfer); + + g_free(msg); } } else { xmlnode *si, *feature, *x, *field, *value;
--- a/libpurple/protocols/msn/msn.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/msn/msn.c Mon Jun 18 01:48:35 2007 +0000 @@ -1423,6 +1423,22 @@ if (found) \ sect_info = TRUE; +#define MSN_GOT_INFO_GET_FIELD_NO_SEARCH(a, b) \ + found = purple_markup_extract_info_field(stripped, stripped_len, user_info, \ + "\n" a ":", 0, "\n", 0, "Undisclosed", b, 0, NULL, msn_info_strip_search_link); \ + if (found) \ + sect_info = TRUE; + +static char * +msn_info_strip_search_link(const char *field, size_t len) +{ + const char *c; + if ((c = strstr(field, " (http://spaces.live.com/default.aspx?page=searchresults")) == NULL && + (c = strstr(field, " (http://spaces.msn.com/default.aspx?page=searchresults")) == NULL) + return g_strndup(field, len); + return g_strndup(field, c - field); +} + static void msn_got_info(PurpleUtilFetchUrlData *url_data, gpointer data, const gchar *url_text, size_t len, const gchar *error_message) @@ -1538,10 +1554,10 @@ /* General */ MSN_GOT_INFO_GET_FIELD("Nickname", _("Nickname")); - MSN_GOT_INFO_GET_FIELD("Age", _("Age")); - MSN_GOT_INFO_GET_FIELD("Gender", _("Gender")); - MSN_GOT_INFO_GET_FIELD("Occupation", _("Occupation")); - MSN_GOT_INFO_GET_FIELD("Location", _("Location")); + MSN_GOT_INFO_GET_FIELD_NO_SEARCH("Age", _("Age")); + MSN_GOT_INFO_GET_FIELD_NO_SEARCH("Gender", _("Gender")); + MSN_GOT_INFO_GET_FIELD_NO_SEARCH("Occupation", _("Occupation")); + MSN_GOT_INFO_GET_FIELD_NO_SEARCH("Location", _("Location")); /* Extract their Interests and put it in */ found = purple_markup_extract_info_field(stripped, stripped_len, user_info, @@ -1802,7 +1818,10 @@ /* This doesn't work with the new spaces profiles - Stu 3/2/06 char *p = strstr(url_buffer, "Unknown Member </TITLE>"); * This might not work for long either ... */ + /* Nope, it failed some time before 5/2/07 :( char *p = strstr(url_buffer, "form id=\"SpacesSearch\" name=\"SpacesSearch\""); + * Let's see how long this one holds out for ... */ + char *p = strstr(url_buffer, "<form id=\"profile_form\" name=\"profile_form\" action=\"http://spaces.live.com/profile.aspx?cid=0\""); PurpleBuddy *b = purple_find_buddy (purple_connection_get_account(info_data->gc), info_data->name); purple_notify_user_info_add_pair(user_info, _("Error retrieving profile"),
--- a/libpurple/protocols/msn/msn.h Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/msn/msn.h Mon Jun 18 01:48:35 2007 +0000 @@ -67,7 +67,7 @@ #define HOTMAIL_URL "http://www.hotmail.com/cgi-bin/folders" #define PASSPORT_URL "http://lc1.law13.hotmail.passport.com/cgi-bin/dologin?login=" -#define PROFILE_URL "http://spaces.msn.com/profile.aspx?mem=" +#define PROFILE_URL "http://spaces.live.com/profile.aspx?mem=" #define USEROPT_HOTMAIL 0
--- a/libpurple/protocols/msn/nexus.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/msn/nexus.c Mon Jun 18 01:48:35 2007 +0000 @@ -247,6 +247,8 @@ temp = g_strndup(error, c - error); error = purple_url_decode(temp); g_free(temp); + if ((temp = strstr(error, " Do one of the following or try again:")) != NULL) + *temp = '\0'; } }
--- a/libpurple/protocols/msn/notification.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/msn/notification.c Mon Jun 18 01:48:35 2007 +0000 @@ -591,12 +591,23 @@ static void qng_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) { + MsnSession *session; static int count = 0; - MsnSession *session = cmdproc->session; + const char *passport; + PurpleAccount *account; + + session = cmdproc->session; + account = session->account; if (session->passport_info.file == NULL) return; + passport = purple_normalize(account, purple_account_get_username(account)); + + if ((strstr(passport, "@hotmail.") != NULL) || + (strstr(passport, "@msn.com") != NULL)) + return; + if (count++ < 26) return; @@ -901,6 +912,7 @@ syn_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) { MsnSession *session; + MsnSync *sync; int total_users; session = cmdproc->session; @@ -919,22 +931,12 @@ total_users = atoi(cmd->params[2]); - if (total_users == 0) - { - msn_session_finish_login(session); - } - else - { - /* syn_table */ - MsnSync *sync; + sync = msn_sync_new(session); + sync->total_users = total_users; + sync->old_cbs_table = cmdproc->cbs_table; - sync = msn_sync_new(session); - sync->total_users = total_users; - sync->old_cbs_table = cmdproc->cbs_table; - - session->sync = sync; - cmdproc->cbs_table = sync->cbs_table; - } + session->sync = sync; + cmdproc->cbs_table = sync->cbs_table; } /**************************************************************************
--- a/libpurple/protocols/msn/servconn.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/msn/servconn.c Mon Jun 18 01:48:35 2007 +0000 @@ -195,6 +195,7 @@ } else { + purple_debug_error("msn", "Connection error: %s\n", error_message); msn_servconn_got_error(servconn, MSN_SERVCONN_ERROR_CONNECT); } } @@ -351,7 +352,7 @@ if (ret < 0 && errno == EAGAIN) ret = 0; - if (ret < len) { + if (ret >= 0 && ret < len) { if (servconn->tx_handler == -1) servconn->tx_handler = purple_input_add( servconn->fd, PURPLE_INPUT_WRITE,
--- a/libpurple/protocols/msn/session.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/msn/session.c Mon Jun 18 01:48:35 2007 +0000 @@ -316,6 +316,7 @@ "temporarily.")); break; case MSN_ERROR_AUTH: + gc->wants_to_die = TRUE; msg = g_strdup_printf(_("Unable to authenticate: %s"), (info == NULL ) ? _("Unknown error") : info); @@ -385,6 +386,7 @@ PurpleAccount *account; PurpleConnection *gc; PurpleStoredImage *img; + const char *passport; if (session->logged_in) return; @@ -408,5 +410,12 @@ * and @msn.com accounts don't automatically get the initial email * notification so we always request it on login */ - msn_cmdproc_send(session->notification->cmdproc, "URL", "%s", "INBOX"); + + passport = purple_normalize(account, purple_account_get_username(account)); + + if ((strstr(passport, "@hotmail.") != NULL) || + (strstr(passport, "@msn.com") != NULL)) + { + msn_cmdproc_send(session->notification->cmdproc, "URL", "%s", "INBOX"); + } }
--- a/libpurple/protocols/msn/switchboard.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/msn/switchboard.c Mon Jun 18 01:48:35 2007 +0000 @@ -419,7 +419,14 @@ case MSN_SB_ERROR_TOO_FAST: str_reason = _("Message could not be sent " "because we are sending too quickly:"); - break; + break; + case MSN_SB_ERROR_AUTHFAILED: + str_reason = _("Message could not be sent " + "because we wer unable to establish a " + "session with the server. This is " + "likely a server problem, try again in " + "a few minutes:"); + break; default: str_reason = _("Message could not be sent " "because an error with " @@ -963,9 +970,13 @@ * Connect stuff **************************************************************************/ static void +ans_usr_error(MsnCmdProc *cmdproc, MsnTransaction *trans, int error); + +static void connect_cb(MsnServConn *servconn) { MsnSwitchBoard *swboard; + MsnTransaction *trans; MsnCmdProc *cmdproc; PurpleAccount *account; @@ -980,16 +991,44 @@ { swboard->empty = FALSE; - msn_cmdproc_send(cmdproc, "ANS", "%s %s %s", - purple_account_get_username(account), - swboard->auth_key, swboard->session_id); + trans = msn_transaction_new(cmdproc, "ANS", "%s %s %s", + purple_account_get_username(account), + swboard->auth_key, swboard->session_id); } else { - msn_cmdproc_send(cmdproc, "USR", "%s %s", - purple_account_get_username(account), - swboard->auth_key); + trans = msn_transaction_new(cmdproc, "USR", "%s %s", + purple_account_get_username(account), + swboard->auth_key); } + + msn_transaction_set_error_cb(trans, ans_usr_error); + msn_transaction_set_data(trans, swboard); + msn_cmdproc_send_trans(cmdproc, trans); +} + +static void +ans_usr_error(MsnCmdProc *cmdproc, MsnTransaction *trans, int error) +{ + MsnSwitchBoard *swboard; + char **params; + char *passport; + int reason = MSN_SB_ERROR_UNKNOWN; + + if (error == 911) + { + reason = MSN_SB_ERROR_AUTHFAILED; + } + + purple_debug_warning("msn", "ans_usr_error: command %s gave error %i\n", trans->command, error); + + params = g_strsplit(trans->params, " ", 0); + passport = params[0]; + swboard = trans->data; + + swboard_error_helper(swboard, reason, passport); + + g_strfreev(params); } static void
--- a/libpurple/protocols/msn/switchboard.h Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/msn/switchboard.h Mon Jun 18 01:48:35 2007 +0000 @@ -46,6 +46,7 @@ MSN_SB_ERROR_USER_OFFLINE, /**< The user to call is offline. */ MSN_SB_ERROR_CONNECTION, /**< There was a connection error. */ MSN_SB_ERROR_TOO_FAST, /**< We are sending too fast */ + MSN_SB_ERROR_AUTHFAILED, /**< Authentication failed joining the switchboard session */ MSN_SB_ERROR_UNKNOWN /**< An unknown error occurred. */ } MsnSBErrorType;
--- a/libpurple/protocols/msn/sync.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/msn/sync.c Mon Jun 18 01:48:35 2007 +0000 @@ -99,8 +99,19 @@ /* HACK */ if (group_id == 0) + { /* Group of ungroupped buddies */ + if (session->sync->total_users == 0) + { + cmdproc->cbs_table = session->sync->old_cbs_table; + + msn_session_finish_login(session); + + msn_sync_destroy(session->sync); + session->sync = NULL; + } return; + } if ((purple_find_group(name)) == NULL) { @@ -184,6 +195,8 @@ user = sync->last_user; + g_return_if_fail(user != NULL); + type = cmd->params[0]; value = cmd->params[1];
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/null/Makefile.am Mon Jun 18 01:48:35 2007 +0000 @@ -0,0 +1,21 @@ +EXTRA_DIST = README Makefile.mingw + +pkgdir = $(libdir)/purple-$(PURPLE_MAJOR_VERSION) + +NULLSOURCES = nullprpl.c + +AM_CFLAGS = $(st) + +libnull_la_LDFLAGS = -module -avoid-version + +# nullprpl isn't built by default. when it is built, it's dynamically linked. +st = +pkg_LTLIBRARIES = libnull.la +libnull_la_SOURCES = $(NULLSOURCES) +libnull_la_LIBADD = $(GLIB_LIBS) + +AM_CPPFLAGS = \ + -I$(top_srcdir)/libpurple \ + -I$(top_builddir)/libpurple \ + $(GLIB_CFLAGS) \ + $(DEBUG_CFLAGS)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/null/Makefile.mingw Mon Jun 18 01:48:35 2007 +0000 @@ -0,0 +1,77 @@ +# +# Makefile.mingw +# +# Description: Makefile for win32 (mingw) version of libnull +# + +PIDGIN_TREE_TOP := ../../.. +include $(PIDGIN_TREE_TOP)/libpurple/win32/global.mak + +TARGET = libnull +TYPE = PLUGIN + +# Static or Plugin... +ifeq ($(TYPE),STATIC) + DEFINES += -DSTATIC + DLL_INSTALL_DIR = $(PURPLE_INSTALL_DIR) +else +ifeq ($(TYPE),PLUGIN) + DLL_INSTALL_DIR = $(PURPLE_INSTALL_PLUGINS_DIR) +endif +endif + +## +## INCLUDE PATHS +## +INCLUDE_PATHS += -I. \ + -I$(GTK_TOP)/include \ + -I$(GTK_TOP)/include/glib-2.0 \ + -I$(GTK_TOP)/lib/glib-2.0/include \ + -I$(PURPLE_TOP) \ + -I$(PURPLE_TOP)/win32 \ + -I$(PIDGIN_TREE_TOP) + +LIB_PATHS += -L$(GTK_TOP)/lib \ + -L$(PURPLE_TOP) + +## +## SOURCES, OBJECTS +## +C_SRC = nullprpl.c + +OBJECTS = $(C_SRC:%.c=%.o) + +## +## LIBRARIES +## +LIBS = \ + -lglib-2.0 \ + -lintl \ + -lws2_32 \ + -lpurple + +include $(PIDGIN_COMMON_RULES) + +## +## TARGET DEFINITIONS +## +.PHONY: all install clean + +all: $(TARGET).dll + +install: all $(DLL_INSTALL_DIR) $(PURPLE_INSTALL_DIR) + cp $(TARGET).dll $(DLL_INSTALL_DIR) + +$(OBJECTS): $(PURPLE_CONFIG_H) + +$(TARGET).dll: $(PURPLE_DLL).a $(OBJECTS) + $(CC) -shared $(OBJECTS) $(LIB_PATHS) $(LIBS) $(DLL_LD_FLAGS) -o $(TARGET).dll + +## +## CLEAN RULES +## +clean: + rm -f $(OBJECTS) + rm -f $(TARGET).dll + +include $(PIDGIN_COMMON_TARGETS)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/null/README Mon Jun 18 01:48:35 2007 +0000 @@ -0,0 +1,46 @@ +nullprpl + +-------- +OVERVIEW +-------- +Nullprpl is a mock protocol plugin for Pidgin and libpurple. You can create +accounts with it, sign on and off, add buddies, and send and receive IMs, all +without connecting to a server! + +Beyond that basic functionality, nullprpl supports presence and away/available +messages, offline messages, user info, typing notification, privacy +allow/block lists, chat rooms, whispering, room lists, and protocol icons and +emblems. Notable missing features are file transfer and account registration +and authentication. + +Nullprpl is intended as an example of how to write a libpurple protocol +plugin. It doesn't contain networking code or an event loop, but it does +demonstrate how to use the libpurple API to do pretty much everything a prpl +might need to do. + +Nullprpl is also a useful tool for hacking on Pidgin, Finch, and other +libpurple clients. It's a full-featured protocol plugin, but doesn't depend on +an external server, so it's a quick and easy way to exercise test new code. It +also allows you to work while you're disconnected. + +----------------------- +BUILDING AND INSTALLING +----------------------- + +To build, just run ./configure as usual in the root directory of the pidgin +source distribution. Then cd libpurple/protocols/null and type make. To +install, copy libnull.la and .libs/libnull.so into your ~/.purple/plugins +directory. Then run Pidgin. + +To build nullprpl on Windows (with Cygwin/MinGW), use Makefile.mingw. + +----- +USAGE +----- +To add a nullprpl account, go to the account editor window and click Add. +Select Nullprpl from the protocol drop-down list, and enter any username you +want. + +Now, use Pidgin like normal. You can add buddies, send IMs, set away messages, +etc. If you send IMs to your own username, they will be echoed back to you. +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/null/nullprpl.c Mon Jun 18 01:48:35 2007 +0000 @@ -0,0 +1,1202 @@ +/** + * purple + * + * Purple is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * Nullprpl is a mock protocol plugin for Pidgin and libpurple. You can create + * accounts with it, sign on and off, add buddies, and send and receive IMs, + * all without connecting to a server! + * + * Beyond that basic functionality, nullprpl supports presence and + * away/available messages, offline messages, user info, typing notification, + * privacy allow/block lists, chat rooms, whispering, room lists, and protocol + * icons and emblems. Notable missing features are file transfer and account + * registration and authentication. + * + * Nullprpl is intended as an example of how to write a libpurple protocol + * plugin. It doesn't contain networking code or an event loop, but it does + * demonstrate how to use the libpurple API to do pretty much everything a prpl + * might need to do. + * + * Nullprpl is also a useful tool for hacking on Pidgin, Finch, and other + * libpurple clients. It's a full-featured protocol plugin, but doesn't depend + * on an external server, so it's a quick and easy way to exercise test new + * code. It also allows you to work while you're disconnected. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <stdarg.h> +#include <string.h> +#include <time.h> + +#include <glib.h> + +#include "internal.h" +#include "config.h" +#include "account.h" +#include "accountopt.h" +#include "blist.h" +#include "cmds.h" +#include "conversation.h" +#include "connection.h" +#include "debug.h" +#include "notify.h" +#include "privacy.h" +#include "prpl.h" +#include "roomlist.h" +#include "status.h" +#include "util.h" +#include "version.h" + + +#define NULLPRPL_ID "prpl-null" +static PurplePlugin *_null_protocol = NULL; + +#define NULL_STATUS_ONLINE "online" +#define NULL_STATUS_AWAY "away" +#define NULL_STATUS_OFFLINE "offline" + +typedef void (*GcFunc)(PurpleConnection *from, + PurpleConnection *to, + gpointer userdata); + +typedef struct { + GcFunc fn; + PurpleConnection *from; + gpointer userdata; +} GcFuncData; + +/* + * stores offline messages that haven't been delivered yet. maps username + * (char *) to GList * of GOfflineMessages. initialized in nullprpl_init. + */ +GHashTable* goffline_messages = NULL; + +typedef struct { + char *from; + char *message; + time_t mtime; + PurpleMessageFlags flags; +} GOfflineMessage; + +/* + * helpers + */ +static PurpleConnection *get_nullprpl_gc(const char *username) { + PurpleAccount *acct = purple_accounts_find(username, NULLPRPL_ID); + if (acct && purple_account_is_connected(acct)) + return acct->gc; + else + return NULL; +} + +static void call_if_nullprpl(gpointer data, gpointer userdata) { + PurpleConnection *gc = (PurpleConnection *)(data); + GcFuncData *gcfdata = (GcFuncData *)userdata; + + if (!strcmp(gc->account->protocol_id, NULLPRPL_ID)) + gcfdata->fn(gcfdata->from, gc, gcfdata->userdata); +} + +static void foreach_nullprpl_gc(GcFunc fn, PurpleConnection *from, + gpointer userdata) { + GcFuncData gcfdata = { fn, from, userdata }; + g_list_foreach(purple_connections_get_all(), call_if_nullprpl, + &gcfdata); +} + + +typedef void(*ChatFunc)(PurpleConvChat *from, PurpleConvChat *to, + int id, const char *room, gpointer userdata); + +typedef struct { + ChatFunc fn; + PurpleConvChat *from_chat; + gpointer userdata; +} ChatFuncData; + +static void call_chat_func(gpointer data, gpointer userdata) { + PurpleConnection *to = (PurpleConnection *)data; + ChatFuncData *cfdata = (ChatFuncData *)userdata; + + int id = cfdata->from_chat->id; + PurpleConversation *conv = purple_find_chat(to, id); + if (conv) { + PurpleConvChat *chat = purple_conversation_get_chat_data(conv); + cfdata->fn(cfdata->from_chat, chat, id, conv->name, cfdata->userdata); + } +} + +static void foreach_gc_in_chat(ChatFunc fn, PurpleConnection *from, + int id, gpointer userdata) { + PurpleConversation *conv = purple_find_chat(from, id); + ChatFuncData cfdata = { fn, + purple_conversation_get_chat_data(conv), + userdata }; + + g_list_foreach(purple_connections_get_all(), call_chat_func, + &cfdata); +} + + +static void discover_status(PurpleConnection *from, PurpleConnection *to, + gpointer userdata) { + char *from_username = from->account->username; + char *to_username = to->account->username; + + if (purple_find_buddy(from->account, to_username)) { + PurpleStatus *status = purple_account_get_active_status(to->account); + const char *status_id = purple_status_get_id(status); + const char *message = purple_status_get_attr_string(status, "message"); + + if (!strcmp(status_id, NULL_STATUS_ONLINE) || + !strcmp(status_id, NULL_STATUS_AWAY) || + !strcmp(status_id, NULL_STATUS_OFFLINE)) { + purple_debug_info("nullprpl", "%s sees that %s is %s: %s\n", + from_username, to_username, status_id, message); + purple_prpl_got_user_status(from->account, to_username, status_id, + (message) ? "message" : NULL, message, NULL); + } else { + purple_debug_error("nullprpl", + "%s's buddy %s has an unknown status: %s, %s", + from_username, to_username, status_id, message); + } + } +} + +static void report_status_change(PurpleConnection *from, PurpleConnection *to, + gpointer userdata) { + purple_debug_info("nullprpl", "notifying %s that %s changed status\n", + to->account->username, from->account->username); + discover_status(to, from, NULL); +} + + +/* + * UI callbacks + */ +static void nullprpl_input_user_info(PurplePluginAction *action) +{ + PurpleConnection *gc = (PurpleConnection *)action->context; + PurpleAccount *acct = purple_connection_get_account(gc); + purple_debug_info("nullprpl", "showing 'Set User Info' dialog for %s\n", + acct->username); + + purple_account_request_change_user_info(acct); +} + +/* this is set to the actions member of the PurplePluginInfo struct at the + * bottom. + */ +static GList *nullprpl_actions(PurplePlugin *plugin, gpointer context) +{ + PurplePluginAction *action = purple_plugin_action_new( + _("Set User Info..."), nullprpl_input_user_info); + return g_list_append(NULL, action); +} + + +/* + * prpl functions + */ +static const char *nullprpl_list_icon(PurpleAccount *acct, PurpleBuddy *buddy) +{ + /* shamelessly steal (er, borrow) the meanwhile protocol icon. it's cute! */ + return "meanwhile"; +} + +static const char *nullprpl_list_emblem(PurpleBuddy *buddy) +{ + const char* emblem; + + if (get_nullprpl_gc(buddy->name)) { + PurplePresence *presence = purple_buddy_get_presence(buddy); + PurpleStatus *status = purple_presence_get_active_status(presence); + emblem = purple_status_get_name(status); + } else { + emblem = "offline"; + } + + purple_debug_info("nullprpl", "using emblem %s for %s's buddy %s\n", + emblem, buddy->account->username, buddy->name); + return emblem; +} + +static char *nullprpl_status_text(PurpleBuddy *buddy) { + purple_debug_info("nullprpl", "getting %s's status text for %s\n", + buddy->name, buddy->account->username); + + if (purple_find_buddy(buddy->account, buddy->name)) { + PurplePresence *presence = purple_buddy_get_presence(buddy); + PurpleStatus *status = purple_presence_get_active_status(presence); + const char *name = purple_status_get_name(status); + const char *message = purple_status_get_attr_string(status, "message"); + + char *text; + if (message && strlen(message) > 0) + text = g_strdup_printf("%s: %s", name, message); + else + text = g_strdup(name); + + purple_debug_info("nullprpl", "%s's status text is %s\n", buddy->name, text); + return text; + + } else { + purple_debug_info("nullprpl", "...but %s is not logged in\n", buddy->name); + return "Not logged in"; + } +} + +static void nullprpl_tooltip_text(PurpleBuddy *buddy, + PurpleNotifyUserInfo *info, + gboolean full) { + PurpleConnection *gc = get_nullprpl_gc(buddy->name); + + if (gc) { + /* they're logged in */ + PurplePresence *presence = purple_buddy_get_presence(buddy); + PurpleStatus *status = purple_presence_get_active_status(presence); + const char *msg = nullprpl_status_text(buddy); + purple_notify_user_info_add_pair(info, purple_status_get_name(status), + msg); + + if (full) { + const char *user_info = purple_account_get_user_info(gc->account); + if (user_info) + purple_notify_user_info_add_pair(info, _("User info"), user_info); + } + + } else { + /* they're not logged in */ + purple_notify_user_info_add_pair(info, _("User info"), _("not logged in")); + } + + purple_debug_info("nullprpl", "showing %s tooltip for %s\n", + (full) ? "full" : "short", buddy->name); +} + +static GList *nullprpl_status_types(PurpleAccount *acct) +{ + GList *types = NULL; + PurpleStatusType *type; + + purple_debug_info("nullprpl", "returning status types for %s: %s, %s, %s\n", + acct->username, + NULL_STATUS_ONLINE, NULL_STATUS_AWAY, NULL_STATUS_OFFLINE); + + type = purple_status_type_new(PURPLE_STATUS_AVAILABLE, NULL_STATUS_ONLINE, + NULL_STATUS_ONLINE, TRUE); + purple_status_type_add_attr(type, "message", _("Online"), + purple_value_new(PURPLE_TYPE_STRING)); + types = g_list_append(types, type); + + type = purple_status_type_new(PURPLE_STATUS_AWAY, NULL_STATUS_AWAY, + NULL_STATUS_AWAY, TRUE); + purple_status_type_add_attr(type, "message", _("Away"), + purple_value_new(PURPLE_TYPE_STRING)); + types = g_list_append(types, type); + + type = purple_status_type_new(PURPLE_STATUS_OFFLINE, NULL_STATUS_OFFLINE, + NULL_STATUS_OFFLINE, TRUE); + purple_status_type_add_attr(type, "message", _("Offline"), + purple_value_new(PURPLE_TYPE_STRING)); + types = g_list_append(types, type); + + return types; +} + +static void blist_example_menu_item(PurpleBlistNode *node, gpointer userdata) { + purple_debug_info("nullprpl", "example menu item clicked on user", + ((PurpleBuddy *)node)->name); + + purple_notify_info(NULL, /* plugin handle or PurpleConnection */ + _("Primary title"), + _("Secondary title"), + _("This is the callback for the nullprpl menu item.")); +} + +static GList *nullprpl_blist_node_menu(PurpleBlistNode *node) { + purple_debug_info("nullprpl", "providing buddy list context menu item\n"); + + if (PURPLE_BLIST_NODE_IS_BUDDY(node)) { + PurpleMenuAction *action = purple_menu_action_new( + _("Nullprpl example menu item"), + PURPLE_CALLBACK(blist_example_menu_item), + NULL, /* userdata passed to the callback */ + NULL); /* child menu items */ + return g_list_append(NULL, action); + } else { + return NULL; + } +} + +static GList *nullprpl_chat_info(PurpleConnection *gc) { + struct proto_chat_entry *pce; /* defined in prpl.h */ + + purple_debug_info("nullprpl", "returning chat setting 'room'\n"); + + pce = g_new0(struct proto_chat_entry, 1); + pce->label = _(_("Chat _room")); + pce->identifier = "room"; + pce->required = TRUE; + + return g_list_append(NULL, pce); +} + +static GHashTable *nullprpl_chat_info_defaults(PurpleConnection *gc, + const char *room) { + GHashTable *defaults; + + purple_debug_info("nullprpl", "returning chat default setting " + "'room' = 'default'\n"); + + defaults = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, g_free); + g_hash_table_insert(defaults, "room", g_strdup("default")); + return defaults; +} + +static void nullprpl_login(PurpleAccount *acct) +{ + PurpleConnection *gc = purple_account_get_connection(acct); + GList *offline_messages; + + purple_debug_info("nullprpl", "logging in %s\n", acct->username); + + purple_connection_update_progress(gc, _("Connecting"), + 0, /* which connection step this is */ + 2); /* total number of steps */ + + purple_connection_update_progress(gc, _("Connected"), + 1, /* which connection step this is */ + 2); /* total number of steps */ + purple_connection_set_state(gc, PURPLE_CONNECTED); + + /* tell purple about everyone on our buddy list who's connected */ + foreach_nullprpl_gc(discover_status, gc, NULL); + + /* notify other nullprpl accounts */ + foreach_nullprpl_gc(report_status_change, gc, NULL); + + /* fetch stored offline messages */ + purple_debug_info("nullprpl", "checking for offline messages for %s\n", + acct->username); + offline_messages = g_hash_table_lookup(goffline_messages, acct->username); + while (offline_messages) { + GOfflineMessage *message = (GOfflineMessage *)offline_messages->data; + purple_debug_info("nullprpl", "delivering offline message to %s: %s\n", + acct->username, message->message); + serv_got_im(gc, message->from, message->message, message->flags, + message->mtime); + offline_messages = g_list_next(offline_messages); + + g_free(message->from); + g_free(message->message); + g_free(message); + } + + g_list_free(offline_messages); + g_hash_table_remove(goffline_messages, &acct->username); +} + +static void nullprpl_close(PurpleConnection *gc) +{ + /* notify other nullprpl accounts */ + foreach_nullprpl_gc(report_status_change, gc, NULL); +} + +static int nullprpl_send_im(PurpleConnection *gc, const char *who, + const char *message, PurpleMessageFlags flags) +{ + const char *from_username = gc->account->username; + PurpleMessageFlags receive_flags = ((flags & ~PURPLE_MESSAGE_SEND) + | PURPLE_MESSAGE_RECV); + PurpleAccount *to_acct = purple_accounts_find(who, NULLPRPL_ID); + PurpleConnection *to; + + purple_debug_info("nullprpl", "sending message from %s to %s: %s\n", + from_username, who, message); + + /* is the sender blocked by the recipient's privacy settings? */ + if (to_acct && !purple_privacy_check(to_acct, gc->account->username)) { + char *msg = g_strdup_printf( + _("Your message was blocked by %s's privacy settings."), who); + purple_debug_info("nullprpl", + "discarding; %s is blocked by %s's privacy settings\n", + from_username, who); + purple_conv_present_error(who, gc->account, msg); + g_free(msg); + return 0; + } + + /* is the recipient online? */ + to = get_nullprpl_gc(who); + if (to) { /* yes, send */ + serv_got_im(to, from_username, message, receive_flags, time(NULL)); + + } else { /* nope, store as an offline message */ + GOfflineMessage *offline_message; + GList *messages; + + purple_debug_info("nullprpl", + "%s is offline, sending as offline message\n", who); + offline_message = g_new0(GOfflineMessage, 1); + offline_message->from = g_strdup(from_username); + offline_message->message = g_strdup(message); + offline_message->mtime = time(NULL); + offline_message->flags = receive_flags; + + messages = g_hash_table_lookup(goffline_messages, who); + messages = g_list_append(messages, offline_message); + g_hash_table_insert(goffline_messages, g_strdup(who), messages); + } + + return 1; +} + +static void nullprpl_set_info(PurpleConnection *gc, const char *info) { + purple_debug_info("nullprpl", "setting %s's user info to %s\n", + gc->account->username, info); +} + +static char *typing_state_to_string(PurpleTypingState typing) { + switch (typing) { + case PURPLE_NOT_TYPING: return "is not typing"; + case PURPLE_TYPING: return "is typing"; + case PURPLE_TYPED: return "stopped typing momentarily"; + default: return "unknown typing state"; + } +} + +static void notify_typing(PurpleConnection *from, PurpleConnection *to, + gpointer typing) { + char *from_username = from->account->username; + char *action = typing_state_to_string((PurpleTypingState)typing); + purple_debug_info("nullprpl", "notifying %s that %s %s\n", + to->account->username, from_username, action); + + serv_got_typing(to, + from_username, + 0, /* if non-zero, a timeout in seconds after which to + * reset the typing status to PURPLE_NOT_TYPING */ + (PurpleTypingState)typing); +} + +static unsigned int nullprpl_send_typing(PurpleConnection *gc, const char *name, + PurpleTypingState typing) { + purple_debug_info("nullprpl", "%s %s\n", gc->account->username, + typing_state_to_string(typing)); + foreach_nullprpl_gc(notify_typing, gc, (gpointer)typing); + return 0; +} + +static void nullprpl_get_info(PurpleConnection *gc, const char *username) { + const char *body; + PurpleNotifyUserInfo *info = purple_notify_user_info_new(); + PurpleAccount *acct; + + purple_debug_info("nullprpl", "Fetching %s's user info for %s\n", username, + gc->account->username); + + if (!get_nullprpl_gc(username)) { + char *msg = g_strdup_printf(_("%s is not logged in."), username); + purple_notify_error(gc, _("User Info"), _("User info not available. "), msg); + g_free(msg); + } + + acct = purple_accounts_find(username, NULLPRPL_ID); + if (acct) + body = purple_account_get_user_info(acct); + else + body = _("No user info."); + purple_notify_user_info_add_pair(info, "Info", body); + + /* show a buddy's user info in a nice dialog box */ + purple_notify_userinfo(gc, /* connection the buddy info came through */ + username, /* buddy's username */ + info, /* body */ + NULL, /* callback called when dialog closed */ + NULL); /* userdata for callback */ +} + +static void nullprpl_set_status(PurpleAccount *acct, PurpleStatus *status) { + const char *msg = purple_status_get_attr_string(status, "message"); + purple_debug_info("nullprpl", "setting %s's status to %s: %s\n", + acct->username, purple_status_get_name(status), msg); + + foreach_nullprpl_gc(report_status_change, get_nullprpl_gc(acct->username), + NULL); +} + +static void nullprpl_set_idle(PurpleConnection *gc, int idletime) { + purple_debug_info("nullprpl", + "purple reports that %s has been idle for %d seconds\n", + gc->account->username, idletime); +} + +static void nullprpl_change_passwd(PurpleConnection *gc, const char *old_pass, + const char *new_pass) { + purple_debug_info("nullprpl", "%s wants to change their password\n", + gc->account->username); +} + +static void nullprpl_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, + PurpleGroup *group) +{ + char *username = gc->account->username; + PurpleConnection *buddy_gc = get_nullprpl_gc(buddy->name); + + purple_debug_info("nullprpl", "adding %s to %s's buddy list\n", buddy->name, + username); + + if (buddy_gc) { + PurpleAccount *buddy_acct = buddy_gc->account; + + discover_status(gc, buddy_gc, NULL); + + if (purple_find_buddy(buddy_acct, username)) { + purple_debug_info("nullprpl", "%s is already on %s's buddy list\n", + username, buddy->name); + } else { + purple_debug_info("nullprpl", "asking %s if they want to add %s\n", + buddy->name, username); + purple_account_request_add(buddy_acct, + username, + NULL, /* local account id (rarely used) */ + NULL, /* alias */ + NULL); /* message */ + } + } +} + +static void nullprpl_add_buddies(PurpleConnection *gc, GList *buddies, + GList *groups) { + GList *buddy = buddies; + GList *group = groups; + + purple_debug_info("nullprpl", "adding multiple buddies\n"); + + while (buddy && group) { + nullprpl_add_buddy(gc, (PurpleBuddy *)buddy->data, (PurpleGroup *)group->data); + buddy = g_list_next(buddy); + group = g_list_next(group); + } +} + +static void nullprpl_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy, + PurpleGroup *group) +{ + purple_debug_info("nullprpl", "removing %s from %s's buddy list\n", + buddy->name, gc->account->username); +} + +static void nullprpl_remove_buddies(PurpleConnection *gc, GList *buddies, + GList *groups) { + GList *buddy = buddies; + GList *group = groups; + + purple_debug_info("nullprpl", "removing multiple buddies\n"); + + while (buddy && group) { + nullprpl_remove_buddy(gc, (PurpleBuddy *)buddy->data, + (PurpleGroup *)group->data); + buddy = g_list_next(buddy); + group = g_list_next(group); + } +} + +/* + * nullprpl uses purple's local whitelist and blacklist, stored in blist.xml, as + * its authoritative privacy settings, and uses purple's logic (specifically + * purple_privacy_check(), from privacy.h), to determine whether messages are + * allowed or blocked. + */ +static void nullprpl_add_permit(PurpleConnection *gc, const char *name) { + purple_debug_info("nullprpl", "%s adds %s to their allowed list\n", + gc->account->username, name); +} + +static void nullprpl_add_deny(PurpleConnection *gc, const char *name) { + purple_debug_info("nullprpl", "%s adds %s to their blocked list\n", + gc->account->username, name); +} + +static void nullprpl_rem_permit(PurpleConnection *gc, const char *name) { + purple_debug_info("nullprpl", "%s removes %s from their allowed list\n", + gc->account->username, name); +} + +static void nullprpl_rem_deny(PurpleConnection *gc, const char *name) { + purple_debug_info("nullprpl", "%s removes %s from their blocked list\n", + gc->account->username, name); +} + +static void nullprpl_set_permit_deny(PurpleConnection *gc) { + /* this is for synchronizing the local black/whitelist with the server. + * for nullprpl, it's a noop. + */ +} + +static void joined_chat(PurpleConvChat *from, PurpleConvChat *to, + int id, const char *room, gpointer userdata) { + /* tell their chat window that we joined */ + purple_debug_info("nullprpl", "%s sees that %s joined chat room %s\n", + to->nick, from->nick, room); + purple_conv_chat_add_user(to, + from->nick, + NULL, /* user-provided join message, IRC style */ + PURPLE_CBFLAGS_NONE, + TRUE); /* show a join message */ + + if (from != to) { + /* add them to our chat window */ + purple_debug_info("nullprpl", "%s sees that %s is in chat room %s\n", + from->nick, to->nick, room); + purple_conv_chat_add_user(from, + to->nick, + NULL, /* user-provided join message, IRC style */ + PURPLE_CBFLAGS_NONE, + FALSE); /* show a join message */ + } +} + +static void nullprpl_join_chat(PurpleConnection *gc, GHashTable *components) { + char *username = gc->account->username; + char *room = g_hash_table_lookup(components, "room"); + int chat_id = g_str_hash(room); + purple_debug_info("nullprpl", "%s is joining chat room %s\n", username, room); + + if (!purple_find_chat(gc, chat_id)) { + serv_got_joined_chat(gc, chat_id, room); + + /* tell everyone that we joined, and add them if they're already there */ + foreach_gc_in_chat(joined_chat, gc, chat_id, NULL); + } else { + purple_debug_info("nullprpl", "%s is already in chat room %s\n", username, + room); + purple_notify_info(gc, + _("Join chat"), + _("Join chat"), + g_strdup_printf("%s is already in chat room %s.", + username, room)); + } +} + +static void nullprpl_reject_chat(PurpleConnection *gc, GHashTable *components) { + char *invited_by = g_hash_table_lookup(components, "invited_by"); + char *room = g_hash_table_lookup(components, "room"); + char *username = gc->account->username; + PurpleConnection *invited_by_gc = get_nullprpl_gc(invited_by); + char *message = g_strdup_printf( + "%s %s %s.", + username, + _("has rejected your invitation to join the chat room"), + room); + + purple_debug_info("nullprpl", + "%s has rejected %s's invitation to join chat room %s\n", + username, invited_by, room); + + purple_notify_info(invited_by_gc, + _("Chat invitation rejected"), + _("Chat invitation rejected"), + message); +} + +static char *nullprpl_get_chat_name(GHashTable *components) { + char *room = g_hash_table_lookup(components, "room"); + purple_debug_info("nullprpl", "reporting chat room name '%s'\n", room); + return room; +} + +static void nullprpl_chat_invite(PurpleConnection *gc, int id, + const char *message, const char *who) { + char *username = gc->account->username; + PurpleConversation *conv = purple_find_chat(gc, id); + char *room = conv->name; + PurpleAccount *to_acct = purple_accounts_find(who, NULLPRPL_ID); + + purple_debug_info("nullprpl", "%s is inviting %s to join chat room %s\n", + username, who, room); + + if (to_acct) { + PurpleConversation *to_conv = purple_find_chat(to_acct->gc, id); + if (to_conv) { + purple_debug_info("nullprpl", + "%s is already in chat room %s; " + "ignoring invitation from %s\n", + who, room, username); + purple_notify_info(gc, + _("Chat invitation"), + _("Chat invitation"), + g_strdup_printf("%s is already in chat room %s.", + who, room)); + } else { + GHashTable *components; + components = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, free); + g_hash_table_replace(components, "room", g_strdup(room)); + g_hash_table_replace(components, "invited_by", g_strdup(username)); + serv_got_chat_invite(to_acct->gc, room, username, message, components); + } + } +} + +static void left_chat_room(PurpleConvChat *from, PurpleConvChat *to, + int id, const char *room, gpointer userdata) { + if (from != to) { + /* tell their chat window that we left */ + purple_debug_info("nullprpl", "%s sees that %s left chat room %s\n", + to->nick, from->nick, room); + purple_conv_chat_remove_user(to, + from->nick, + NULL); /* user-provided message, IRC style */ + } +} + +static void nullprpl_chat_leave(PurpleConnection *gc, int id) { + PurpleConversation *conv = purple_find_chat(gc, id); + purple_debug_info("nullprpl", "%s is leaving chat room %s\n", + gc->account->username, conv->name); + + /* tell everyone that we left */ + foreach_gc_in_chat(left_chat_room, gc, id, NULL); +} + +static PurpleCmdRet send_whisper(PurpleConversation *conv, const gchar *cmd, + gchar **args, gchar **error, void *userdata) { + const char *to_username; + const char *message; + const char *from_username; + PurpleConvChat *chat; + PurpleConvChatBuddy *chat_buddy; + PurpleConnection *to; + + /* parse args */ + to_username = args[0]; + message = args[1]; + + if (!to_username || strlen(to_username) == 0) { + *error = g_strdup(_("Whisper is missing recipient.")); + return PURPLE_CMD_RET_FAILED; + } else if (!message || strlen(message) == 0) { + *error = g_strdup(_("Whisper is missing message.")); + return PURPLE_CMD_RET_FAILED; + } + + from_username = conv->account->username; + purple_debug_info("nullprpl", "%s whispers to %s in chat room %s: %s\n", + from_username, to_username, conv->name, message); + + chat = purple_conversation_get_chat_data(conv); + chat_buddy = purple_conv_chat_cb_find(chat, to_username); + to = get_nullprpl_gc(to_username); + + if (!chat_buddy) { + /* this will be freed by the caller */ + *error = g_strdup_printf(_("%s is not logged in."), to_username); + return PURPLE_CMD_RET_FAILED; + } else if (!to) { + *error = g_strdup_printf(_("%s is not in this chat room."), to_username); + return PURPLE_CMD_RET_FAILED; + } else { + /* write the whisper in the sender's chat window */ + char *message_to = g_strdup_printf("%s (to %s)", message, to_username); + purple_conv_chat_write(chat, from_username, message_to, + PURPLE_MESSAGE_SEND | PURPLE_MESSAGE_WHISPER, + time(NULL)); + g_free(message_to); + + /* send the whisper */ + serv_chat_whisper(to, chat->id, from_username, message); + + return PURPLE_CMD_RET_OK; + } +} + +static void nullprpl_chat_whisper(PurpleConnection *gc, int id, const char *who, + const char *message) { + char *username = gc->account->username; + PurpleConversation *conv = purple_find_chat(gc, id); + purple_debug_info("nullprpl", + "%s receives whisper from %s in chat room %s: %s\n", + username, who, conv->name, message); + + /* receive whisper on recipient's account */ + serv_got_chat_in(gc, id, who, PURPLE_MESSAGE_RECV | PURPLE_MESSAGE_WHISPER, + message, time(NULL)); +} + +static void receive_chat_message(PurpleConvChat *from, PurpleConvChat *to, + int id, const char *room, gpointer userdata) { + const char *message = (const char *)userdata; + PurpleConnection *to_gc = get_nullprpl_gc(to->nick); + + purple_debug_info("nullprpl", + "%s receives message from %s in chat room %s: %s\n", + to->nick, from->nick, room, message); + serv_got_chat_in(to_gc, id, from->nick, PURPLE_MESSAGE_RECV, message, + time(NULL)); +} + +static int nullprpl_chat_send(PurpleConnection *gc, int id, const char *message, + PurpleMessageFlags flags) { + char *username = gc->account->username; + PurpleConversation *conv = purple_find_chat(gc, id); + + if (conv) { + purple_debug_info("nullprpl", + "%s is sending message to chat room %s: %s\n", username, + conv->name, message); + + /* send message to everyone in the chat room */ + foreach_gc_in_chat(receive_chat_message, gc, id, (gpointer)message); + return 0; + } else { + purple_debug_info("nullprpl", + "tried to send message from %s to chat room #%d: %s\n" + "but couldn't find chat room", + username, id, message); + return -1; + } +} + +static void nullprpl_register_user(PurpleAccount *acct) { + purple_debug_info("nullprpl", "registering account for %s\n", + acct->username); +} + +static void nullprpl_get_cb_info(PurpleConnection *gc, int id, const char *who) { + PurpleConversation *conv = purple_find_chat(gc, id); + purple_debug_info("nullprpl", + "retrieving %s's info for %s in chat room %s\n", who, + gc->account->username, conv->name); + + nullprpl_get_info(gc, who); +} + +static void nullprpl_alias_buddy(PurpleConnection *gc, const char *who, + const char *alias) { + purple_debug_info("nullprpl", "%s sets %'s alias to %s\n", + gc->account->username, who, alias); +} + +static void nullprpl_group_buddy(PurpleConnection *gc, const char *who, + const char *old_group, + const char *new_group) { + purple_debug_info("nullprpl", "%s has moved %s from group %s to group %s\n", + who, old_group, new_group); +} + +static void nullprpl_rename_group(PurpleConnection *gc, const char *old_name, + PurpleGroup *group, GList *moved_buddies) { + purple_debug_info("nullprpl", "%s has renamed group %s to %s\n", + gc->account->username, old_name, group->name); +} + +static void nullprpl_convo_closed(PurpleConnection *gc, const char *who) { + purple_debug_info("nullprpl", "%s's conversation with %s was closed\n", + gc->account->username, who); +} + +/* normalize a username (e.g. remove whitespace, add default domain, etc.) + * for nullprpl, this is a noop. + */ +static const char *nullprpl_normalize(const PurpleAccount *acct, + const char *input) { + return NULL; +} + +static void nullprpl_set_buddy_icon(PurpleConnection *gc, + PurpleStoredImage *img) { + purple_debug_info("nullprpl", "setting %s's buddy icon to %s\n", + gc->account->username, purple_imgstore_get_filename(img)); +} + +static void nullprpl_remove_group(PurpleConnection *gc, PurpleGroup *group) { + purple_debug_info("nullprpl", "%s has removed group %s\n", + gc->account->username, group->name); +} + + +static void set_chat_topic_fn(PurpleConvChat *from, PurpleConvChat *to, + int id, const char *room, gpointer userdata) { + const char *topic = (const char *)userdata; + const char *username = from->conv->account->username; + char *msg; + + purple_conv_chat_set_topic(to, username, topic); + + if (topic && strlen(topic) > 0) + msg = g_strdup_printf(_("%s sets topic to: %s"), username, topic); + else + msg = g_strdup_printf(_("%s clears topic"), username); + + purple_conv_chat_write(to, username, msg, + PURPLE_MESSAGE_SYSTEM | PURPLE_MESSAGE_NO_LOG, + time(NULL)); + g_free(msg); +} + +static void nullprpl_set_chat_topic(PurpleConnection *gc, int id, + const char *topic) { + PurpleConversation *conv = purple_find_chat(gc, id); + PurpleConvChat *chat = purple_conversation_get_chat_data(conv); + const char *last_topic; + + if (!chat) + return; + + purple_debug_info("nullprpl", "%s sets topic of chat room '%s' to '%s'\n", + gc->account->username, conv->name, topic); + + last_topic = purple_conv_chat_get_topic(chat); + if ((!topic && !last_topic) || + (topic && last_topic && !strcmp(topic, last_topic))) + return; /* topic is unchanged, this is a noop */ + + foreach_gc_in_chat(set_chat_topic_fn, gc, id, (gpointer)topic); +} + +static gboolean nullprpl_finish_get_roomlist(gpointer roomlist) { + purple_roomlist_set_in_progress((PurpleRoomlist *)roomlist, FALSE); + return FALSE; +} + +static PurpleRoomlist *nullprpl_roomlist_get_list(PurpleConnection *gc) { + char *username = gc->account->username; + PurpleRoomlist *roomlist = purple_roomlist_new(gc->account); + GList *fields = NULL; + PurpleRoomlistField *field; + GList *chats; + GList *seen_ids = NULL; + + purple_debug_info("nullprpl", "%s asks for room list; returning:\n", username); + + /* set up the room list */ + field = purple_roomlist_field_new(PURPLE_ROOMLIST_FIELD_STRING, "room", + "room", TRUE /* hidden */); + fields = g_list_append(fields, field); + + field = purple_roomlist_field_new(PURPLE_ROOMLIST_FIELD_INT, "Id", "Id", FALSE); + fields = g_list_append(fields, field); + + purple_roomlist_set_fields(roomlist, fields); + + /* add each chat room. the chat ids are cached in seen_ids so that each room + * is only returned once, even if multiple users are in it. */ + for (chats = purple_get_chats(); chats; chats = g_list_next(chats)) { + PurpleConversation *conv = (PurpleConversation *)chats->data; + PurpleRoomlistRoom *room; + char *name = conv->name; + int id = purple_conversation_get_chat_data(conv)->id; + + /* have we already added this room? */ + if (g_list_find_custom(seen_ids, name, (GCompareFunc)strcmp)) + continue; /* yes! try the next one. */ + + seen_ids = g_list_append(seen_ids, name); /* no, it's new. */ + purple_debug_info("nullprpl", "%s (%d), ", name, id); + + room = purple_roomlist_room_new(PURPLE_ROOMLIST_ROOMTYPE_ROOM, name, NULL); + purple_roomlist_room_add_field(roomlist, room, name); + purple_roomlist_room_add_field(roomlist, room, &id); + purple_roomlist_room_add(roomlist, room); + } + + purple_timeout_add(1 /* ms */, nullprpl_finish_get_roomlist, roomlist); + return roomlist; +} + +static void nullprpl_roomlist_cancel(PurpleRoomlist *list) { + purple_debug_info("nullprpl", "%s asked to cancel room list request\n", + list->account->username); +} + +static void nullprpl_roomlist_expand_category(PurpleRoomlist *list, + PurpleRoomlistRoom *category) { + purple_debug_info("nullprpl", "%s asked to expand room list category %s\n", + list->account->username, category->name); +} + +/* nullprpl doesn't support file transfer...yet... */ +static gboolean nullprpl_can_receive_file(PurpleConnection *gc, + const char *who) { + return FALSE; +} + +static gboolean nullprpl_offline_message(const PurpleBuddy *buddy) { + purple_debug_info("nullprpl", + "reporting that offline messages are supported for %s\n", + buddy->name); + return TRUE; +} + + +/* + * prpl stuff. see prpl.h for more information. + */ + +static PurplePluginProtocolInfo prpl_info = +{ + OPT_PROTO_NO_PASSWORD | OPT_PROTO_CHAT_TOPIC, /* options */ + NULL, /* user_splits, initialized in nullprpl_init() */ + NULL, /* protocol_options, initialized in nullprpl_init() */ + { /* icon_spec, a PurpleBuddyIconSpec */ + "png,jpg,gif", /* format */ + 0, /* min_width */ + 0, /* min_height */ + 128, /* max_width */ + 128, /* max_height */ + 10000, /* max_filesize */ + PURPLE_ICON_SCALE_DISPLAY, /* scale_rules */ + }, + nullprpl_list_icon, /* list_icon */ + nullprpl_list_emblem, /* list_emblem */ + nullprpl_status_text, /* status_text */ + nullprpl_tooltip_text, /* tooltip_text */ + nullprpl_status_types, /* status_types */ + nullprpl_blist_node_menu, /* blist_node_menu */ + nullprpl_chat_info, /* chat_info */ + nullprpl_chat_info_defaults, /* chat_info_defaults */ + nullprpl_login, /* login */ + nullprpl_close, /* close */ + nullprpl_send_im, /* send_im */ + nullprpl_set_info, /* set_info */ + nullprpl_send_typing, /* send_typing */ + nullprpl_get_info, /* get_info */ + nullprpl_set_status, /* set_status */ + nullprpl_set_idle, /* set_idle */ + nullprpl_change_passwd, /* change_passwd */ + nullprpl_add_buddy, /* add_buddy */ + nullprpl_add_buddies, /* add_buddies */ + nullprpl_remove_buddy, /* remove_buddy */ + nullprpl_remove_buddies, /* remove_buddies */ + nullprpl_add_permit, /* add_permit */ + nullprpl_add_deny, /* add_deny */ + nullprpl_rem_permit, /* rem_permit */ + nullprpl_rem_deny, /* rem_deny */ + nullprpl_set_permit_deny, /* set_permit_deny */ + nullprpl_join_chat, /* join_chat */ + nullprpl_reject_chat, /* reject_chat */ + nullprpl_get_chat_name, /* get_chat_name */ + nullprpl_chat_invite, /* chat_invite */ + nullprpl_chat_leave, /* chat_leave */ + nullprpl_chat_whisper, /* chat_whisper */ + nullprpl_chat_send, /* chat_send */ + NULL, /* keepalive */ + nullprpl_register_user, /* register_user */ + nullprpl_get_cb_info, /* get_cb_info */ + NULL, /* get_cb_away */ + nullprpl_alias_buddy, /* alias_buddy */ + nullprpl_group_buddy, /* group_buddy */ + nullprpl_rename_group, /* rename_group */ + NULL, /* buddy_free */ + nullprpl_convo_closed, /* convo_closed */ + nullprpl_normalize, /* normalize */ + nullprpl_set_buddy_icon, /* set_buddy_icon */ + nullprpl_remove_group, /* remove_group */ + NULL, /* get_cb_real_name */ + nullprpl_set_chat_topic, /* set_chat_topic */ + NULL, /* find_blist_chat */ + nullprpl_roomlist_get_list, /* roomlist_get_list */ + nullprpl_roomlist_cancel, /* roomlist_cancel */ + nullprpl_roomlist_expand_category, /* roomlist_expand_category */ + nullprpl_can_receive_file, /* can_receive_file */ + NULL, /* send_file */ + NULL, /* new_xfer */ + nullprpl_offline_message, /* offline_message */ + NULL, /* whiteboard_prpl_ops */ + NULL, /* send_raw */ + NULL, /* roomlist_room_serialize */ + NULL, /* padding... */ + NULL, + NULL, + NULL, +}; + +static void nullprpl_init(PurplePlugin *plugin) +{ + /* see accountopt.h for information about user splits and protocol options */ + PurpleAccountUserSplit *split = purple_account_user_split_new( + _("Example user split (unused)"), /* text shown to user */ + "default", /* default value */ + '@'); /* field separator */ + PurpleAccountOption *option = purple_account_option_string_new( + _("Example option (unused)"), /* text shown to user */ + "example", /* pref name */ + "default"); /* default value */ + + purple_debug_info("nullprpl", "starting up\n"); + + prpl_info.user_splits = g_list_append(NULL, split); + prpl_info.protocol_options = g_list_append(NULL, option); + + /* register whisper chat command, /msg */ + purple_cmd_register("msg", + "ws", /* args: recipient and message */ + PURPLE_CMD_P_DEFAULT, /* priority */ + PURPLE_CMD_FLAG_CHAT, + "prpl-null", + send_whisper, + "msg <username> <message>: send a private message, aka a whisper", + NULL); /* userdata */ + + /* get ready to store offline messages */ + goffline_messages = g_hash_table_new_full(g_str_hash, /* hash fn */ + g_str_equal, /* key comparison fn */ + g_free, /* key free fn */ + NULL); /* value free fn */ + + _null_protocol = plugin; +} + +static void nullprpl_destroy(PurplePlugin *plugin) { + purple_debug_info("nullprpl", "shutting down\n"); +} + + +static PurplePluginInfo info = +{ + PURPLE_PLUGIN_MAGIC, /* magic */ + PURPLE_MAJOR_VERSION, /* major_version */ + PURPLE_MINOR_VERSION, /* minor_version */ + PURPLE_PLUGIN_PROTOCOL, /* type */ + NULL, /* ui_requirement */ + 0, /* flags */ + NULL, /* dependencies */ + PURPLE_PRIORITY_DEFAULT, /* priority */ + NULLPRPL_ID, /* id */ + "Nullprpl", /* name */ + "0.3", /* version */ + "Null Protocol Plugin", /* summary */ + "Null Protocol Plugin", /* description */ + "Ryan Barrett <nullprpl@ryanb.org>", /* author */ + "http://snarfed.org/space/pidgin+null+protocol+plugin", /* homepage */ + NULL, /* load */ + NULL, /* unload */ + nullprpl_destroy, /* destroy */ + NULL, /* ui_info */ + &prpl_info, /* extra_info */ + NULL, /* prefs_info */ + nullprpl_actions, /* actions */ + NULL, /* padding... */ + NULL, + NULL, + NULL, +}; + +PURPLE_INIT_PLUGIN(null, nullprpl_init, info);
--- a/libpurple/protocols/oscar/.todo Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/oscar/.todo Mon Jun 18 01:48:35 2007 +0000 @@ -15,16 +15,10 @@ <note priority="veryhigh" time="1036040919"> some way to close direct connect w/out closing convo. </note> - <note priority="low" time="1036040970"> - canceled direct im should still allow new attempt - </note> <note priority="low" time="1036041084"> failed direct im attempt should allow new attempt some way to cancel an attempt that isn't happening </note> </note> - <note priority="low" time="1036041105"> - Colors in Chat room are wrong (using Gold too much) - </note> <note priority="verylow" time="1036041121"> Voice Chat </note> @@ -44,7 +38,7 @@ color support </note> <note priority="high" time="1036041251"> - set status message and of course when gaim can set them, it needs to be able to get the ones it sets. (yes this is redundant. its a reflection of my current mood) + set status message and of course when libpurple can set them, it needs to be able to get the ones it sets. (yes this is redundant. its a reflection of my current mood) </note> <note priority="medium" time="1036041165"> Chat (this is different from aim chat) @@ -66,6 +60,6 @@ </note> </note> <note priority="medium" time="1036040870"> - The order of groups and buddies in the server list is not updated when groups and buddies are re-arranged locally in Gaim. + The order of groups and buddies in the server list is not updated when groups and buddies are re-arranged locally in libpurple. </note> </todo>
--- a/libpurple/protocols/oscar/AUTHORS Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/oscar/AUTHORS Mon Jun 18 01:48:35 2007 +0000 @@ -35,7 +35,7 @@ N: Eric Warmenhoven T: 1998-2001 E: warmenhoven a.t linux d.o.t com -D: Some OFT info, author of the faim interface for gaim +D: Some OFT info, initial author of the libpurple-side of the oscar protocol plugin N: Brock Wilcox T: 1998-2001
--- a/libpurple/protocols/oscar/Makefile.am Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/oscar/Makefile.am Mon Jun 18 01:48:35 2007 +0000 @@ -52,15 +52,10 @@ if STATIC_OSCAR st = -DPURPLE_STATIC_PRPL -noinst_LIBRARIES = liboscar.a libaim.a libicq.a -liboscar_a_SOURCES = $(OSCARSOURCES) -liboscar_a_CFLAGS = $(AM_CFLAGS) +noinst_LIBRARIES = liboscar.a -libaim_a_CFLAGS = $(AM_CFLAGS) -libaim_a_SOURCES = libaim.c - -libicq_a_CFLAGS = $(AM_CFLAGS) -libicq_a_SOURCES = libicq.c +liboscar_a_SOURCES = $(OSCARSOURCES) libaim.c libicq.c +liboscar_a_CFLAGS = $(AM_CFLAGS) else
--- a/libpurple/protocols/oscar/family_admin.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/oscar/family_admin.c Mon Jun 18 01:48:35 2007 +0000 @@ -125,17 +125,17 @@ { FlapFrame *fr; aim_snacid_t snacid; - aim_tlvlist_t *tl = NULL; + GSList *tlvlist = NULL; fr = flap_frame_new(od, 0x02, 10+2+2+strlen(newnick)); snacid = aim_cachesnac(od, 0x0007, 0x0004, 0x0000, NULL, 0); aim_putsnac(&fr->data, 0x0007, 0x0004, 0x0000, snacid); - aim_tlvlist_add_str(&tl, 0x0001, newnick); + aim_tlvlist_add_str(&tlvlist, 0x0001, newnick); - aim_tlvlist_write(&fr->data, &tl); - aim_tlvlist_free(&tl); + aim_tlvlist_write(&fr->data, &tlvlist); + aim_tlvlist_free(tlvlist); flap_connection_send(conn, fr); @@ -151,7 +151,7 @@ aim_admin_changepasswd(OscarData *od, FlapConnection *conn, const char *newpw, const char *curpw) { FlapFrame *fr; - aim_tlvlist_t *tl = NULL; + GSList *tlvlist = NULL; aim_snacid_t snacid; fr = flap_frame_new(od, 0x02, 10+4+strlen(curpw)+4+strlen(newpw)); @@ -160,13 +160,13 @@ aim_putsnac(&fr->data, 0x0007, 0x0004, 0x0000, snacid); /* new password TLV t(0002) */ - aim_tlvlist_add_str(&tl, 0x0002, newpw); + aim_tlvlist_add_str(&tlvlist, 0x0002, newpw); /* current password TLV t(0012) */ - aim_tlvlist_add_str(&tl, 0x0012, curpw); + aim_tlvlist_add_str(&tlvlist, 0x0012, curpw); - aim_tlvlist_write(&fr->data, &tl); - aim_tlvlist_free(&tl); + aim_tlvlist_write(&fr->data, &tlvlist); + aim_tlvlist_free(tlvlist); flap_connection_send(conn, fr); @@ -182,17 +182,17 @@ { FlapFrame *fr; aim_snacid_t snacid; - aim_tlvlist_t *tl = NULL; + GSList *tlvlist = NULL; fr = flap_frame_new(od, 0x02, 10+2+2+strlen(newemail)); snacid = aim_cachesnac(od, 0x0007, 0x0004, 0x0000, NULL, 0); aim_putsnac(&fr->data, 0x0007, 0x0004, 0x0000, snacid); - aim_tlvlist_add_str(&tl, 0x0011, newemail); + aim_tlvlist_add_str(&tlvlist, 0x0011, newemail); - aim_tlvlist_write(&fr->data, &tl); - aim_tlvlist_free(&tl); + aim_tlvlist_write(&fr->data, &tlvlist); + aim_tlvlist_free(tlvlist); flap_connection_send(conn, fr); @@ -223,17 +223,17 @@ int ret = 0; aim_rxcallback_t userfunc; guint16 status; - /* aim_tlvlist_t *tl; */ + /* GSList *tlvlist; */ status = byte_stream_get16(bs); /* Status is 0x0013 if unable to confirm at this time */ - /* tl = aim_tlvlist_read(bs); */ + /* tlvlist = aim_tlvlist_read(bs); */ if ((userfunc = aim_callhandler(od, snac->family, snac->subtype))) ret = userfunc(od, conn, frame, status); - /* aim_tlvlist_free(&tl); */ + /* aim_tlvlist_free(tlvlist); */ return ret; }
--- a/libpurple/protocols/oscar/family_alert.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/oscar/family_alert.c Mon Jun 18 01:48:35 2007 +0000 @@ -98,7 +98,7 @@ int ret = 0; aim_rxcallback_t userfunc; struct aim_emailinfo *new; - aim_tlvlist_t *tlvlist; + GSList *tlvlist; guint8 *cookie8, *cookie16; int tmp, havenewmail = 0; /* Used to tell the client we have _new_ mail */ @@ -152,7 +152,7 @@ if ((userfunc = aim_callhandler(od, snac->family, snac->subtype))) ret = userfunc(od, conn, frame, new, havenewmail, alertitle, (alerturl ? alerturl + 2 : NULL)); - aim_tlvlist_free(&tlvlist); + aim_tlvlist_free(tlvlist); g_free(alertitle); g_free(alerturl);
--- a/libpurple/protocols/oscar/family_auth.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/oscar/family_auth.c Mon Jun 18 01:48:35 2007 +0000 @@ -129,7 +129,7 @@ goddamnicq2(OscarData *od, FlapConnection *conn, const char *sn, const char *password, ClientInfo *ci) { FlapFrame *frame; - aim_tlvlist_t *tl = NULL; + GSList *tlvlist = NULL; int passwdlen; guint8 *password_encoded; @@ -143,24 +143,24 @@ aim_encode_password(password, password_encoded); byte_stream_put32(&frame->data, 0x00000001); /* FLAP Version */ - aim_tlvlist_add_str(&tl, 0x0001, sn); - aim_tlvlist_add_raw(&tl, 0x0002, passwdlen, password_encoded); + aim_tlvlist_add_str(&tlvlist, 0x0001, sn); + aim_tlvlist_add_raw(&tlvlist, 0x0002, passwdlen, password_encoded); if (ci->clientstring) - aim_tlvlist_add_str(&tl, 0x0003, ci->clientstring); - aim_tlvlist_add_16(&tl, 0x0016, (guint16)ci->clientid); - aim_tlvlist_add_16(&tl, 0x0017, (guint16)ci->major); - aim_tlvlist_add_16(&tl, 0x0018, (guint16)ci->minor); - aim_tlvlist_add_16(&tl, 0x0019, (guint16)ci->point); - aim_tlvlist_add_16(&tl, 0x001a, (guint16)ci->build); - aim_tlvlist_add_32(&tl, 0x0014, (guint32)ci->distrib); /* distribution chan */ - aim_tlvlist_add_str(&tl, 0x000f, ci->lang); - aim_tlvlist_add_str(&tl, 0x000e, ci->country); + aim_tlvlist_add_str(&tlvlist, 0x0003, ci->clientstring); + aim_tlvlist_add_16(&tlvlist, 0x0016, (guint16)ci->clientid); + aim_tlvlist_add_16(&tlvlist, 0x0017, (guint16)ci->major); + aim_tlvlist_add_16(&tlvlist, 0x0018, (guint16)ci->minor); + aim_tlvlist_add_16(&tlvlist, 0x0019, (guint16)ci->point); + aim_tlvlist_add_16(&tlvlist, 0x001a, (guint16)ci->build); + aim_tlvlist_add_32(&tlvlist, 0x0014, (guint32)ci->distrib); /* distribution chan */ + aim_tlvlist_add_str(&tlvlist, 0x000f, ci->lang); + aim_tlvlist_add_str(&tlvlist, 0x000e, ci->country); - aim_tlvlist_write(&frame->data, &tl); + aim_tlvlist_write(&frame->data, &tlvlist); g_free(password_encoded); - aim_tlvlist_free(&tl); + aim_tlvlist_free(tlvlist); flap_connection_send(conn, frame); @@ -201,7 +201,7 @@ aim_send_login(OscarData *od, FlapConnection *conn, const char *sn, const char *password, gboolean truncate_pass, ClientInfo *ci, const char *key) { FlapFrame *frame; - aim_tlvlist_t *tl = NULL; + GSList *tlvlist = NULL; guint8 digest[16]; aim_snacid_t snacid; size_t password_len; @@ -220,7 +220,7 @@ snacid = aim_cachesnac(od, 0x0017, 0x0002, 0x0000, NULL, 0); aim_putsnac(&frame->data, 0x0017, 0x0002, 0x0000, snacid); - aim_tlvlist_add_str(&tl, 0x0001, sn); + aim_tlvlist_add_str(&tlvlist, 0x0001, sn); /* Truncate ICQ and AOL passwords, if necessary */ password_len = strlen(password); @@ -231,32 +231,32 @@ aim_encode_password_md5(password, password_len, key, digest); - aim_tlvlist_add_raw(&tl, 0x0025, 16, digest); + aim_tlvlist_add_raw(&tlvlist, 0x0025, 16, digest); #ifndef USE_OLD_MD5 - aim_tlvlist_add_noval(&tl, 0x004c); + aim_tlvlist_add_noval(&tlvlist, 0x004c); #endif if (ci->clientstring) - aim_tlvlist_add_str(&tl, 0x0003, ci->clientstring); - aim_tlvlist_add_16(&tl, 0x0016, (guint16)ci->clientid); - aim_tlvlist_add_16(&tl, 0x0017, (guint16)ci->major); - aim_tlvlist_add_16(&tl, 0x0018, (guint16)ci->minor); - aim_tlvlist_add_16(&tl, 0x0019, (guint16)ci->point); - aim_tlvlist_add_16(&tl, 0x001a, (guint16)ci->build); - aim_tlvlist_add_32(&tl, 0x0014, (guint32)ci->distrib); - aim_tlvlist_add_str(&tl, 0x000f, ci->lang); - aim_tlvlist_add_str(&tl, 0x000e, ci->country); + aim_tlvlist_add_str(&tlvlist, 0x0003, ci->clientstring); + aim_tlvlist_add_16(&tlvlist, 0x0016, (guint16)ci->clientid); + aim_tlvlist_add_16(&tlvlist, 0x0017, (guint16)ci->major); + aim_tlvlist_add_16(&tlvlist, 0x0018, (guint16)ci->minor); + aim_tlvlist_add_16(&tlvlist, 0x0019, (guint16)ci->point); + aim_tlvlist_add_16(&tlvlist, 0x001a, (guint16)ci->build); + aim_tlvlist_add_32(&tlvlist, 0x0014, (guint32)ci->distrib); + aim_tlvlist_add_str(&tlvlist, 0x000f, ci->lang); + aim_tlvlist_add_str(&tlvlist, 0x000e, ci->country); /* * If set, old-fashioned buddy lists will not work. You will need * to use SSI. */ - aim_tlvlist_add_8(&tl, 0x004a, 0x01); + aim_tlvlist_add_8(&tlvlist, 0x004a, 0x01); - aim_tlvlist_write(&frame->data, &tl); + aim_tlvlist_write(&frame->data, &tlvlist); - aim_tlvlist_free(&tl); + aim_tlvlist_free(tlvlist); flap_connection_send(conn, frame); @@ -274,7 +274,7 @@ static int parse(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs) { - aim_tlvlist_t *tlvlist; + GSList *tlvlist; aim_rxcallback_t userfunc; struct aim_authresp_info *info; int ret = 0; @@ -402,7 +402,7 @@ if ((userfunc = aim_callhandler(od, snac ? snac->family : 0x0017, snac ? snac->subtype : 0x0003))) ret = userfunc(od, conn, frame, info); - aim_tlvlist_free(&tlvlist); + aim_tlvlist_free(tlvlist); return ret; } @@ -471,7 +471,7 @@ { FlapFrame *frame; aim_snacid_t snacid; - aim_tlvlist_t *tl = NULL; + GSList *tlvlist = NULL; if (!od || !conn || !sn) return -EINVAL; @@ -486,16 +486,16 @@ snacid = aim_cachesnac(od, 0x0017, 0x0006, 0x0000, NULL, 0); aim_putsnac(&frame->data, 0x0017, 0x0006, 0x0000, snacid); - aim_tlvlist_add_str(&tl, 0x0001, sn); + aim_tlvlist_add_str(&tlvlist, 0x0001, sn); /* Tell the server we support SecurID logins. */ - aim_tlvlist_add_noval(&tl, 0x004b); + aim_tlvlist_add_noval(&tlvlist, 0x004b); /* Unknown. Sent in recent WinAIM clients.*/ - aim_tlvlist_add_noval(&tl, 0x005a); + aim_tlvlist_add_noval(&tlvlist, 0x005a); - aim_tlvlist_write(&frame->data, &tl); - aim_tlvlist_free(&tl); + aim_tlvlist_write(&frame->data, &tlvlist); + aim_tlvlist_free(tlvlist); flap_connection_send(conn, frame); @@ -517,7 +517,7 @@ int keylen, ret = 1; aim_rxcallback_t userfunc; char *keystr; - aim_tlvlist_t *tlvlist; + GSList *tlvlist; gboolean truncate_pass; keylen = byte_stream_get16(bs); @@ -539,7 +539,7 @@ ret = userfunc(od, conn, frame, keystr, (int)truncate_pass); g_free(keystr); - aim_tlvlist_free(&tlvlist); + aim_tlvlist_free(tlvlist); return ret; }
--- a/libpurple/protocols/oscar/family_bos.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/oscar/family_bos.c Mon Jun 18 01:48:35 2007 +0000 @@ -39,7 +39,7 @@ static int rights(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs) { aim_rxcallback_t userfunc; - aim_tlvlist_t *tlvlist; + GSList *tlvlist; guint16 maxpermits = 0, maxdenies = 0; int ret = 0; @@ -63,7 +63,7 @@ if ((userfunc = aim_callhandler(od, snac->family, snac->subtype))) ret = userfunc(od, conn, frame, maxpermits, maxdenies); - aim_tlvlist_free(&tlvlist); + aim_tlvlist_free(tlvlist); return ret; }
--- a/libpurple/protocols/oscar/family_buddy.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/oscar/family_buddy.c Mon Jun 18 01:48:35 2007 +0000 @@ -47,7 +47,7 @@ rights(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs) { aim_rxcallback_t userfunc; - aim_tlvlist_t *tlvlist; + GSList *tlvlist; guint16 maxbuddies = 0, maxwatchers = 0; int ret = 0; @@ -82,7 +82,7 @@ if ((userfunc = aim_callhandler(od, snac->family, snac->subtype))) ret = userfunc(od, conn, frame, maxbuddies, maxwatchers); - aim_tlvlist_free(&tlvlist); + aim_tlvlist_free(tlvlist); return ret; }
--- a/libpurple/protocols/oscar/family_chat.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/oscar/family_chat.c Mon Jun 18 01:48:35 2007 +0000 @@ -159,7 +159,7 @@ char *roomname; struct aim_chat_roominfo roominfo; guint16 tlvcount = 0; - aim_tlvlist_t *tlvlist; + GSList *tlvlist; aim_tlv_t *tlv; char *roomdesc; guint16 flags; @@ -309,7 +309,7 @@ g_free(userinfo); g_free(roomname); g_free(roomdesc); - aim_tlvlist_free(&tlvlist); + aim_tlvlist_free(tlvlist); return ret; } @@ -357,7 +357,7 @@ IcbmCookie *cookie; aim_snacid_t snacid; guint8 ckstr[8]; - aim_tlvlist_t *tlvlist = NULL, *inner_tlvlist = NULL; + GSList *tlvlist = NULL, *inner_tlvlist = NULL; if (!od || !conn || !msg || (msglen <= 0)) return 0; @@ -430,8 +430,8 @@ aim_tlvlist_write(&frame->data, &tlvlist); - aim_tlvlist_free(&inner_tlvlist); - aim_tlvlist_free(&tlvlist); + aim_tlvlist_free(inner_tlvlist); + aim_tlvlist_free(tlvlist); flap_connection_send(conn, frame); @@ -471,7 +471,7 @@ aim_userinfo_t userinfo; guint8 cookie[8]; guint16 channel; - aim_tlvlist_t *tlvlist; + GSList *tlvlist; char *msg = NULL; int len = 0; char *encoding = NULL, *language = NULL; @@ -536,7 +536,7 @@ tlv = aim_tlv_gettlv(tlvlist, 0x0005, 1); if (tlv != NULL) { - aim_tlvlist_t *inner_tlvlist; + GSList *inner_tlvlist; aim_tlv_t *inner_tlv; byte_stream_init(&tbs, tlv->value, tlv->length); @@ -562,7 +562,7 @@ */ language = aim_tlv_getstr(inner_tlvlist, 0x0003, 1); - aim_tlvlist_free(&inner_tlvlist); + aim_tlvlist_free(inner_tlvlist); } if ((userfunc = aim_callhandler(od, snac->family, snac->subtype))) @@ -572,7 +572,7 @@ g_free(msg); g_free(encoding); g_free(language); - aim_tlvlist_free(&tlvlist); + aim_tlvlist_free(tlvlist); return ret; }
--- a/libpurple/protocols/oscar/family_chatnav.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/oscar/family_chatnav.c Mon Jun 18 01:48:35 2007 +0000 @@ -50,7 +50,7 @@ static const char charset[] = {"us-ascii"}; FlapFrame *frame; aim_snacid_t snacid; - aim_tlvlist_t *tl = NULL; + GSList *tlvlist = NULL; frame = flap_frame_new(od, 0x02, 1152); @@ -85,15 +85,15 @@ /* detail level */ byte_stream_put8(&frame->data, 0x01); - aim_tlvlist_add_str(&tl, 0x00d3, name); - aim_tlvlist_add_str(&tl, 0x00d6, charset); - aim_tlvlist_add_str(&tl, 0x00d7, lang); + aim_tlvlist_add_str(&tlvlist, 0x00d3, name); + aim_tlvlist_add_str(&tlvlist, 0x00d6, charset); + aim_tlvlist_add_str(&tlvlist, 0x00d7, lang); /* tlvcount */ - byte_stream_put16(&frame->data, aim_tlvlist_count(&tl)); - aim_tlvlist_write(&frame->data, &tl); + byte_stream_put16(&frame->data, aim_tlvlist_count(tlvlist)); + aim_tlvlist_write(&frame->data, &tlvlist); - aim_tlvlist_free(&tl); + aim_tlvlist_free(tlvlist); flap_connection_send(conn, frame); @@ -109,7 +109,7 @@ int curexchange; aim_tlv_t *exchangetlv; guint8 maxrooms = 0; - aim_tlvlist_t *tlvlist, *innerlist; + GSList *tlvlist, *innerlist; tlvlist = aim_tlvlist_read(bs); @@ -290,7 +290,7 @@ } #endif - aim_tlvlist_free(&innerlist); + aim_tlvlist_free(innerlist); } /* @@ -307,7 +307,7 @@ g_free(exchanges[curexchange].lang2); } g_free(exchanges); - aim_tlvlist_free(&tlvlist); + aim_tlvlist_free(tlvlist); return ret; } @@ -316,7 +316,7 @@ parseinfo_create(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs, aim_snac_t *snac2) { aim_rxcallback_t userfunc; - aim_tlvlist_t *tlvlist, *innerlist; + GSList *tlvlist, *innerlist; char *ck = NULL, *fqcn = NULL, *name = NULL; guint16 exchange = 0, instance = 0, unknown = 0, flags = 0, maxmsglen = 0, maxoccupancy = 0; guint32 createtime = 0; @@ -330,7 +330,7 @@ if (!(bigblock = aim_tlv_gettlv(tlvlist, 0x0004, 1))) { purple_debug_misc("oscar", "no bigblock in top tlv in create room response\n"); - aim_tlvlist_free(&tlvlist); + aim_tlvlist_free(tlvlist); return 0; } @@ -344,7 +344,7 @@ if (detaillevel != 0x02) { purple_debug_misc("oscar", "unknown detaillevel in create room response (0x%02x)\n", detaillevel); - aim_tlvlist_free(&tlvlist); + aim_tlvlist_free(tlvlist); g_free(ck); return 0; } @@ -381,8 +381,8 @@ g_free(ck); g_free(name); g_free(fqcn); - aim_tlvlist_free(&innerlist); - aim_tlvlist_free(&tlvlist); + aim_tlvlist_free(innerlist); + aim_tlvlist_free(tlvlist); return ret; }
--- a/libpurple/protocols/oscar/family_feedbag.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/oscar/family_feedbag.c Mon Jun 18 01:48:35 2007 +0000 @@ -110,7 +110,7 @@ * @param data The additional data for the new item. * @return A pointer to the newly created item. */ -static struct aim_ssi_item *aim_ssi_itemlist_add(struct aim_ssi_item **list, const char *name, guint16 gid, guint16 bid, guint16 type, aim_tlvlist_t *data) +static struct aim_ssi_item *aim_ssi_itemlist_add(struct aim_ssi_item **list, const char *name, guint16 gid, guint16 bid, guint16 type, GSList *data) { gboolean exists; struct aim_ssi_item *cur, *new; @@ -214,7 +214,7 @@ /* Free the removed item */ g_free(del->name); - aim_tlvlist_free(&del->data); + aim_tlvlist_free(del->data); g_free(del); return 0; @@ -610,7 +610,7 @@ del = cur; cur = cur->next; g_free(del->name); - aim_tlvlist_free(&del->data); + aim_tlvlist_free(del->data); g_free(del); } @@ -619,7 +619,7 @@ del = cur; cur = cur->next; g_free(del->name); - aim_tlvlist_free(&del->data); + aim_tlvlist_free(del->data); g_free(del); } @@ -670,7 +670,7 @@ aim_ssi_deldeny(od, NULL); } else if ((cur->type == AIM_SSI_TYPE_BUDDY) && ((cur->gid == 0x0000) || (!aim_ssi_itemlist_find(od->ssi.local, cur->gid, 0x0000)))) { char *alias = aim_ssi_getalias(od->ssi.local, NULL, cur->name); - aim_ssi_addbuddy(od, cur->name, "orphans", alias, NULL, NULL, 0); + aim_ssi_addbuddy(od, cur->name, "orphans", NULL, alias, NULL, NULL, FALSE); aim_ssi_delbuddy(od, cur->name, NULL); g_free(alias); } @@ -721,15 +721,15 @@ * @param od The oscar odion. * @param name The name of the item. * @param group The group of the item. + * @param data A TLV list to use as the additional data for this item. * @param alias The alias/nickname of the item, or NULL. * @param comment The buddy comment for the item, or NULL. * @param smsnum The locally assigned SMS number, or NULL. * @return Return 0 if no errors, otherwise return the error number. */ -int aim_ssi_addbuddy(OscarData *od, const char *name, const char *group, const char *alias, const char *comment, const char *smsnum, int needauth) +int aim_ssi_addbuddy(OscarData *od, const char *name, const char *group, GSList *data, const char *alias, const char *comment, const char *smsnum, gboolean needauth) { struct aim_ssi_item *parent; - aim_tlvlist_t *data = NULL; if (!od || !name || !group) return -EINVAL; @@ -750,16 +750,16 @@ /* Create a TLV list for the new buddy */ if (needauth) aim_tlvlist_add_noval(&data, 0x0066); - if (alias) + if (alias != NULL) aim_tlvlist_add_str(&data, 0x0131, alias); - if (smsnum) + if (smsnum != NULL) aim_tlvlist_add_str(&data, 0x013a, smsnum); - if (comment) + if (comment != NULL) aim_tlvlist_add_str(&data, 0x013c, comment); /* Add that bad boy */ aim_ssi_itemlist_add(&od->ssi.local, name, parent->gid, 0xFFFF, AIM_SSI_TYPE_BUDDY, data); - aim_tlvlist_free(&data); + aim_tlvlist_free(data); /* Modify the parent group */ aim_ssi_itemlist_rebuildgroup(od->ssi.local, group); @@ -920,16 +920,22 @@ */ int aim_ssi_movebuddy(OscarData *od, const char *oldgn, const char *newgn, const char *sn) { - char *alias; - gboolean waitingforauth; + struct aim_ssi_item *buddy; + GSList *data; + + /* Find the buddy */ + buddy = aim_ssi_itemlist_finditem(od->ssi.local, oldgn, sn, AIM_SSI_TYPE_BUDDY); + if (buddy == NULL) + return -EINVAL; - alias = aim_ssi_getalias(od->ssi.local, oldgn, sn); - waitingforauth = aim_ssi_waitingforauth(od->ssi.local, oldgn, sn); + /* Make a copy of the buddy's TLV list */ + data = aim_tlvlist_copy(buddy->data); + /* Delete the old item */ aim_ssi_delbuddy(od, sn, oldgn); - aim_ssi_addbuddy(od, sn, newgn, alias, NULL, NULL, waitingforauth); - g_free(alias); + /* Add the new item using the EXACT SAME TLV list */ + aim_ssi_addbuddy(od, sn, newgn, data, NULL, NULL, NULL, FALSE); return 0; } @@ -1172,7 +1178,7 @@ { int ret = 0, i; aim_rxcallback_t userfunc; - aim_tlvlist_t *tlvlist; + GSList *tlvlist; aim_tlv_t *tlv; ByteStream bstream; guint16 *maxitems; @@ -1182,7 +1188,7 @@ /* TLV 0x0004 contains the maximum number of each item */ if (!(tlv = aim_tlv_gettlv(tlvlist, 0x0004, 1))) { - aim_tlvlist_free(&tlvlist); + aim_tlvlist_free(tlvlist); return 0; } @@ -1196,7 +1202,7 @@ if ((userfunc = aim_callhandler(od, snac->family, snac->subtype))) ret = userfunc(od, conn, frame, tlv->length/2, maxitems); - aim_tlvlist_free(&tlvlist); + aim_tlvlist_free(tlvlist); g_free(maxitems); return ret; @@ -1267,7 +1273,7 @@ guint8 fmtver; /* guess */ guint16 namelen, gid, bid, type; char *name; - aim_tlvlist_t *data; + GSList *data; fmtver = byte_stream_get8(bs); /* Version of ssi data. Should be 0x00 */ od->ssi.numitems += byte_stream_get16(bs); /* # of items in this SSI SNAC */ @@ -1284,7 +1290,7 @@ data = aim_tlvlist_readlen(bs, byte_stream_get16(bs)); aim_ssi_itemlist_add(&od->ssi.official, name, gid, bid, type, data); g_free(name); - aim_tlvlist_free(&data); + aim_tlvlist_free(data); } /* Read in the timestamp */ @@ -1352,7 +1358,7 @@ if (cur->item->name) snaclen += strlen(cur->item->name); if (cur->item->data) - snaclen += aim_tlvlist_size(&cur->item->data); + snaclen += aim_tlvlist_size(cur->item->data); } frame = flap_frame_new(od, 0x02, snaclen); @@ -1367,7 +1373,7 @@ byte_stream_put16(&frame->data, cur->item->gid); byte_stream_put16(&frame->data, cur->item->bid); byte_stream_put16(&frame->data, cur->item->type); - byte_stream_put16(&frame->data, cur->item->data ? aim_tlvlist_size(&cur->item->data) : 0); + byte_stream_put16(&frame->data, cur->item->data ? aim_tlvlist_size(cur->item->data) : 0); if (cur->item->data) aim_tlvlist_write(&frame->data, &cur->item->data); } @@ -1389,7 +1395,7 @@ aim_rxcallback_t userfunc; char *name; guint16 len, gid, bid, type; - aim_tlvlist_t *data; + GSList *data; while (byte_stream_empty(bs)) { if ((len = byte_stream_get16(bs))) @@ -1406,7 +1412,7 @@ aim_ssi_itemlist_add(&od->ssi.local, name, gid, bid, type, data); aim_ssi_itemlist_add(&od->ssi.official, name, gid, bid, type, data); - aim_tlvlist_free(&data); + aim_tlvlist_free(data); if ((userfunc = aim_callhandler(od, snac->family, snac->subtype))) ret = userfunc(od, conn, frame, type, name); @@ -1428,7 +1434,7 @@ aim_rxcallback_t userfunc; char *name; guint16 len, gid, bid, type; - aim_tlvlist_t *data; + GSList *data; struct aim_ssi_item *item; while (byte_stream_empty(bs)) { @@ -1453,7 +1459,7 @@ strcpy(item->name, name); } else item->name = NULL; - aim_tlvlist_free(&item->data); + aim_tlvlist_free(item->data); item->data = aim_tlvlist_copy(data); } @@ -1465,7 +1471,7 @@ strcpy(item->name, name); } else item->name = NULL; - aim_tlvlist_free(&item->data); + aim_tlvlist_free(item->data); item->data = aim_tlvlist_copy(data); } @@ -1473,7 +1479,7 @@ ret = userfunc(od, conn, frame); g_free(name); - aim_tlvlist_free(&data); + aim_tlvlist_free(data); } return ret; @@ -1561,7 +1567,7 @@ strcpy(cur->item->name, cur1->name); } else cur->item->name = NULL; - aim_tlvlist_free(&cur->item->data); + aim_tlvlist_free(cur->item->data); cur->item->data = aim_tlvlist_copy(cur1->data); } } else @@ -1595,7 +1601,7 @@ strcpy(cur1->name, cur->item->name); } else cur1->name = NULL; - aim_tlvlist_free(&cur1->data); + aim_tlvlist_free(cur1->data); cur1->data = aim_tlvlist_copy(cur->item->data); } } else
--- a/libpurple/protocols/oscar/family_icbm.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/oscar/family_icbm.c Mon Jun 18 01:48:35 2007 +0000 @@ -451,7 +451,7 @@ IcbmCookie *msgcookie; struct aim_invite_priv *priv; guchar cookie[8]; - aim_tlvlist_t *otl = NULL, *itl = NULL; + GSList *outer_tlvlist = NULL, *inner_tlvlist = NULL; ByteStream hdrbs; if (!od || !(conn = flap_connection_findbygroup(od, 0x0004))) @@ -498,19 +498,19 @@ byte_stream_putraw(&hdrbs, cookie, sizeof(cookie)); /* I think... */ byte_stream_putcaps(&hdrbs, OSCAR_CAPABILITY_CHAT); - aim_tlvlist_add_16(&itl, 0x000a, 0x0001); - aim_tlvlist_add_noval(&itl, 0x000f); - aim_tlvlist_add_str(&itl, 0x000c, msg); - aim_tlvlist_add_chatroom(&itl, 0x2711, exchange, roomname, instance); - aim_tlvlist_write(&hdrbs, &itl); - - aim_tlvlist_add_raw(&otl, 0x0005, byte_stream_curpos(&hdrbs), hdrbs.data); + aim_tlvlist_add_16(&inner_tlvlist, 0x000a, 0x0001); + aim_tlvlist_add_noval(&inner_tlvlist, 0x000f); + aim_tlvlist_add_str(&inner_tlvlist, 0x000c, msg); + aim_tlvlist_add_chatroom(&inner_tlvlist, 0x2711, exchange, roomname, instance); + aim_tlvlist_write(&hdrbs, &inner_tlvlist); + + aim_tlvlist_add_raw(&outer_tlvlist, 0x0005, byte_stream_curpos(&hdrbs), hdrbs.data); g_free(hdrbs.data); - aim_tlvlist_write(&frame->data, &otl); - - aim_tlvlist_free(&itl); - aim_tlvlist_free(&otl); + aim_tlvlist_write(&frame->data, &outer_tlvlist); + + aim_tlvlist_free(inner_tlvlist); + aim_tlvlist_free(outer_tlvlist); flap_connection_send(conn, frame); @@ -689,7 +689,7 @@ FlapConnection *conn; FlapFrame *frame; aim_snacid_t snacid; - aim_tlvlist_t *tl = NULL, *itl = NULL; + GSList *outer_tlvlist = NULL, *inner_tlvlist = NULL; ByteStream hdrbs; od = peer_conn->od; @@ -705,7 +705,7 @@ /* ICBM header */ aim_im_puticbm(&frame->data, peer_conn->cookie, 0x0002, peer_conn->sn); - aim_tlvlist_add_noval(&tl, 0x0003); + aim_tlvlist_add_noval(&outer_tlvlist, 0x0003); byte_stream_new(&hdrbs, 64); @@ -714,16 +714,16 @@ byte_stream_putcaps(&hdrbs, peer_conn->type); /* This TLV means "cancel!" */ - aim_tlvlist_add_16(&itl, 0x000b, 0x0001); - aim_tlvlist_write(&hdrbs, &itl); - - aim_tlvlist_add_raw(&tl, 0x0005, byte_stream_curpos(&hdrbs), hdrbs.data); + aim_tlvlist_add_16(&inner_tlvlist, 0x000b, 0x0001); + aim_tlvlist_write(&hdrbs, &inner_tlvlist); + + aim_tlvlist_add_raw(&outer_tlvlist, 0x0005, byte_stream_curpos(&hdrbs), hdrbs.data); g_free(hdrbs.data); - aim_tlvlist_write(&frame->data, &tl); - - aim_tlvlist_free(&itl); - aim_tlvlist_free(&tl); + aim_tlvlist_write(&frame->data, &outer_tlvlist); + + aim_tlvlist_free(inner_tlvlist); + aim_tlvlist_free(outer_tlvlist); flap_connection_send(conn, frame); } @@ -775,7 +775,7 @@ FlapConnection *conn; FlapFrame *frame; aim_snacid_t snacid; - aim_tlvlist_t *tl = NULL, *itl = NULL; + GSList *outer_tlvlist = NULL, *inner_tlvlist = NULL; ByteStream hdrbs; conn = flap_connection_findbygroup(od, 0x0004); @@ -790,7 +790,7 @@ /* ICBM header */ aim_im_puticbm(&frame->data, cookie, 0x0002, sn); - aim_tlvlist_add_noval(&tl, 0x0003); + aim_tlvlist_add_noval(&outer_tlvlist, 0x0003); byte_stream_new(&hdrbs, 128); @@ -798,20 +798,20 @@ byte_stream_putraw(&hdrbs, cookie, 8); byte_stream_putcaps(&hdrbs, OSCAR_CAPABILITY_DIRECTIM); - aim_tlvlist_add_raw(&itl, 0x0002, 4, ip); - aim_tlvlist_add_raw(&itl, 0x0003, 4, ip); - aim_tlvlist_add_16(&itl, 0x0005, port); - aim_tlvlist_add_16(&itl, 0x000a, requestnumber); - aim_tlvlist_add_noval(&itl, 0x000f); - aim_tlvlist_write(&hdrbs, &itl); - - aim_tlvlist_add_raw(&tl, 0x0005, byte_stream_curpos(&hdrbs), hdrbs.data); + aim_tlvlist_add_raw(&inner_tlvlist, 0x0002, 4, ip); + aim_tlvlist_add_raw(&inner_tlvlist, 0x0003, 4, ip); + aim_tlvlist_add_16(&inner_tlvlist, 0x0005, port); + aim_tlvlist_add_16(&inner_tlvlist, 0x000a, requestnumber); + aim_tlvlist_add_noval(&inner_tlvlist, 0x000f); + aim_tlvlist_write(&hdrbs, &inner_tlvlist); + + aim_tlvlist_add_raw(&outer_tlvlist, 0x0005, byte_stream_curpos(&hdrbs), hdrbs.data); g_free(hdrbs.data); - aim_tlvlist_write(&frame->data, &tl); - - aim_tlvlist_free(&itl); - aim_tlvlist_free(&tl); + aim_tlvlist_write(&frame->data, &outer_tlvlist); + + aim_tlvlist_free(inner_tlvlist); + aim_tlvlist_free(outer_tlvlist); flap_connection_send(conn, frame); } @@ -826,7 +826,7 @@ FlapConnection *conn; FlapFrame *frame; aim_snacid_t snacid; - aim_tlvlist_t *tl = NULL, *itl = NULL; + GSList *outer_tlvlist = NULL, *inner_tlvlist = NULL; ByteStream hdrbs; guint8 ip_comp[4]; @@ -842,7 +842,7 @@ /* ICBM header */ aim_im_puticbm(&frame->data, cookie, 0x0002, sn); - aim_tlvlist_add_noval(&tl, 0x0003); + aim_tlvlist_add_noval(&outer_tlvlist, 0x0003); byte_stream_new(&hdrbs, 128); @@ -850,30 +850,30 @@ byte_stream_putraw(&hdrbs, cookie, 8); byte_stream_putcaps(&hdrbs, OSCAR_CAPABILITY_DIRECTIM); - aim_tlvlist_add_raw(&itl, 0x0002, 4, ip); - aim_tlvlist_add_raw(&itl, 0x0003, 4, ip); - aim_tlvlist_add_16(&itl, 0x0005, pin); - aim_tlvlist_add_16(&itl, 0x000a, requestnumber); - aim_tlvlist_add_noval(&itl, 0x000f); - aim_tlvlist_add_noval(&itl, 0x0010); + aim_tlvlist_add_raw(&inner_tlvlist, 0x0002, 4, ip); + aim_tlvlist_add_raw(&inner_tlvlist, 0x0003, 4, ip); + aim_tlvlist_add_16(&inner_tlvlist, 0x0005, pin); + aim_tlvlist_add_16(&inner_tlvlist, 0x000a, requestnumber); + aim_tlvlist_add_noval(&inner_tlvlist, 0x000f); + aim_tlvlist_add_noval(&inner_tlvlist, 0x0010); /* Send the bitwise complement of the port and ip. As a check? */ ip_comp[0] = ~ip[0]; ip_comp[1] = ~ip[1]; ip_comp[2] = ~ip[2]; ip_comp[3] = ~ip[3]; - aim_tlvlist_add_raw(&itl, 0x0016, 4, ip_comp); - aim_tlvlist_add_16(&itl, 0x0017, ~pin); - - aim_tlvlist_write(&hdrbs, &itl); - - aim_tlvlist_add_raw(&tl, 0x0005, byte_stream_curpos(&hdrbs), hdrbs.data); + aim_tlvlist_add_raw(&inner_tlvlist, 0x0016, 4, ip_comp); + aim_tlvlist_add_16(&inner_tlvlist, 0x0017, ~pin); + + aim_tlvlist_write(&hdrbs, &inner_tlvlist); + + aim_tlvlist_add_raw(&outer_tlvlist, 0x0005, byte_stream_curpos(&hdrbs), hdrbs.data); g_free(hdrbs.data); - aim_tlvlist_write(&frame->data, &tl); - - aim_tlvlist_free(&itl); - aim_tlvlist_free(&tl); + aim_tlvlist_write(&frame->data, &outer_tlvlist); + + aim_tlvlist_free(inner_tlvlist); + aim_tlvlist_free(outer_tlvlist); flap_connection_send(conn, frame); } @@ -888,7 +888,7 @@ FlapConnection *conn; FlapFrame *frame; aim_snacid_t snacid; - aim_tlvlist_t *tl = NULL, *itl = NULL; + GSList *outer_tlvlist = NULL, *inner_tlvlist = NULL; ByteStream hdrbs; conn = flap_connection_findbygroup(od, 0x0004); @@ -903,7 +903,7 @@ /* ICBM header */ aim_im_puticbm(&frame->data, cookie, 0x0002, sn); - aim_tlvlist_add_noval(&tl, 0x0003); + aim_tlvlist_add_noval(&outer_tlvlist, 0x0003); byte_stream_new(&hdrbs, 512); @@ -911,11 +911,11 @@ byte_stream_putraw(&hdrbs, cookie, 8); byte_stream_putcaps(&hdrbs, OSCAR_CAPABILITY_SENDFILE); - aim_tlvlist_add_raw(&itl, 0x0002, 4, ip); - aim_tlvlist_add_raw(&itl, 0x0003, 4, ip); - aim_tlvlist_add_16(&itl, 0x0005, port); - aim_tlvlist_add_16(&itl, 0x000a, requestnumber); - aim_tlvlist_add_noval(&itl, 0x000f); + aim_tlvlist_add_raw(&inner_tlvlist, 0x0002, 4, ip); + aim_tlvlist_add_raw(&inner_tlvlist, 0x0003, 4, ip); + aim_tlvlist_add_16(&inner_tlvlist, 0x0005, port); + aim_tlvlist_add_16(&inner_tlvlist, 0x000a, requestnumber); + aim_tlvlist_add_noval(&inner_tlvlist, 0x000f); /* TODO: Send 0x0016 and 0x0017 */ #if 0 @@ -924,9 +924,9 @@ * redirect for a file receive (same conditions for * sending 0x000f above) */ - aim_tlvlist_add_raw(&itl, 0x000e, 2, "en"); - aim_tlvlist_add_raw(&itl, 0x000d, 8, "us-ascii"); - aim_tlvlist_add_raw(&itl, 0x000c, 24, "Please accept this file."); + aim_tlvlist_add_raw(&inner_tlvlist, 0x000e, 2, "en"); + aim_tlvlist_add_raw(&inner_tlvlist, 0x000d, 8, "us-ascii"); + aim_tlvlist_add_raw(&inner_tlvlist, 0x000c, 24, "Please accept this file."); #endif if (filename != NULL) @@ -943,19 +943,19 @@ byte_stream_putstr(&bs, filename); byte_stream_put8(&bs, 0x00); - aim_tlvlist_add_raw(&itl, 0x2711, bs.len, bs.data); + aim_tlvlist_add_raw(&inner_tlvlist, 0x2711, bs.len, bs.data); g_free(bs.data); /* End TLV t(2711) */ } - aim_tlvlist_write(&hdrbs, &itl); - aim_tlvlist_add_raw(&tl, 0x0005, byte_stream_curpos(&hdrbs), hdrbs.data); + aim_tlvlist_write(&hdrbs, &inner_tlvlist); + aim_tlvlist_add_raw(&outer_tlvlist, 0x0005, byte_stream_curpos(&hdrbs), hdrbs.data); g_free(hdrbs.data); - aim_tlvlist_write(&frame->data, &tl); - - aim_tlvlist_free(&itl); - aim_tlvlist_free(&tl); + aim_tlvlist_write(&frame->data, &outer_tlvlist); + + aim_tlvlist_free(inner_tlvlist); + aim_tlvlist_free(outer_tlvlist); flap_connection_send(conn, frame); } @@ -970,7 +970,7 @@ FlapConnection *conn; FlapFrame *frame; aim_snacid_t snacid; - aim_tlvlist_t *tl = NULL, *itl = NULL; + GSList *outer_tlvlist = NULL, *inner_tlvlist = NULL; ByteStream hdrbs; guint8 ip_comp[4]; @@ -986,7 +986,7 @@ /* ICBM header */ aim_im_puticbm(&frame->data, cookie, 0x0002, sn); - aim_tlvlist_add_noval(&tl, 0x0003); + aim_tlvlist_add_noval(&outer_tlvlist, 0x0003); byte_stream_new(&hdrbs, 512); @@ -994,20 +994,20 @@ byte_stream_putraw(&hdrbs, cookie, 8); byte_stream_putcaps(&hdrbs, OSCAR_CAPABILITY_SENDFILE); - aim_tlvlist_add_raw(&itl, 0x0002, 4, ip); - aim_tlvlist_add_raw(&itl, 0x0003, 4, ip); - aim_tlvlist_add_16(&itl, 0x0005, pin); - aim_tlvlist_add_16(&itl, 0x000a, requestnumber); - aim_tlvlist_add_noval(&itl, 0x000f); - aim_tlvlist_add_noval(&itl, 0x0010); + aim_tlvlist_add_raw(&inner_tlvlist, 0x0002, 4, ip); + aim_tlvlist_add_raw(&inner_tlvlist, 0x0003, 4, ip); + aim_tlvlist_add_16(&inner_tlvlist, 0x0005, pin); + aim_tlvlist_add_16(&inner_tlvlist, 0x000a, requestnumber); + aim_tlvlist_add_noval(&inner_tlvlist, 0x000f); + aim_tlvlist_add_noval(&inner_tlvlist, 0x0010); /* Send the bitwise complement of the port and ip. As a check? */ ip_comp[0] = ~ip[0]; ip_comp[1] = ~ip[1]; ip_comp[2] = ~ip[2]; ip_comp[3] = ~ip[3]; - aim_tlvlist_add_raw(&itl, 0x0016, 4, ip_comp); - aim_tlvlist_add_16(&itl, 0x0017, ~pin); + aim_tlvlist_add_raw(&inner_tlvlist, 0x0016, 4, ip_comp); + aim_tlvlist_add_16(&inner_tlvlist, 0x0017, ~pin); #if 0 /* TODO: If the following is ever enabled, ensure that it is @@ -1015,9 +1015,9 @@ * redirect for a file receive (same conditions for * sending 0x000f above) */ - aim_tlvlist_add_raw(&itl, 0x000e, 2, "en"); - aim_tlvlist_add_raw(&itl, 0x000d, 8, "us-ascii"); - aim_tlvlist_add_raw(&itl, 0x000c, 24, "Please accept this file."); + aim_tlvlist_add_raw(&inner_tlvlist, 0x000e, 2, "en"); + aim_tlvlist_add_raw(&inner_tlvlist, 0x000d, 8, "us-ascii"); + aim_tlvlist_add_raw(&inner_tlvlist, 0x000c, 24, "Please accept this file."); #endif if (filename != NULL) @@ -1034,20 +1034,20 @@ byte_stream_putstr(&bs, filename); byte_stream_put8(&bs, 0x00); - aim_tlvlist_add_raw(&itl, 0x2711, bs.len, bs.data); + aim_tlvlist_add_raw(&inner_tlvlist, 0x2711, bs.len, bs.data); g_free(bs.data); /* End TLV t(2711) */ } - aim_tlvlist_write(&hdrbs, &itl); - - aim_tlvlist_add_raw(&tl, 0x0005, byte_stream_curpos(&hdrbs), hdrbs.data); + aim_tlvlist_write(&hdrbs, &inner_tlvlist); + + aim_tlvlist_add_raw(&outer_tlvlist, 0x0005, byte_stream_curpos(&hdrbs), hdrbs.data); g_free(hdrbs.data); - aim_tlvlist_write(&frame->data, &tl); - - aim_tlvlist_free(&itl); - aim_tlvlist_free(&tl); + aim_tlvlist_write(&frame->data, &outer_tlvlist); + + aim_tlvlist_free(inner_tlvlist); + aim_tlvlist_free(outer_tlvlist); flap_connection_send(conn, frame); } @@ -1226,7 +1226,7 @@ aim_rxcallback_t userfunc; guchar cookie[8]; guint16 channel; - aim_tlvlist_t *tlvlist; + GSList *tlvlist; char *sn; int snlen; guint16 icbmflags = 0; @@ -1281,7 +1281,7 @@ g_free(sn); g_free(msg); - aim_tlvlist_free(&tlvlist); + aim_tlvlist_free(tlvlist); return ret; } @@ -1874,11 +1874,11 @@ typedef void (*ch2_args_destructor_t)(OscarData *od, IcbmArgsCh2 *args); -static int incomingim_ch2(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, guint16 channel, aim_userinfo_t *userinfo, aim_tlvlist_t *tlvlist, guint8 *cookie) +static int incomingim_ch2(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, guint16 channel, aim_userinfo_t *userinfo, GSList *tlvlist, guint8 *cookie) { aim_rxcallback_t userfunc; aim_tlv_t *block1, *servdatatlv; - aim_tlvlist_t *list2; + GSList *list2; aim_tlv_t *tlv; IcbmArgsCh2 args; ByteStream bbs, sdbs, *sdbsptr = NULL; @@ -2078,12 +2078,12 @@ g_free((char *)args.encoding); g_free((char *)args.language); - aim_tlvlist_free(&list2); + aim_tlvlist_free(list2); return ret; } -static int incomingim_ch4(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, guint16 channel, aim_userinfo_t *userinfo, aim_tlvlist_t *tlvlist, guint8 *cookie) +static int incomingim_ch4(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, guint16 channel, aim_userinfo_t *userinfo, GSList *tlvlist, guint8 *cookie) { ByteStream meat; aim_rxcallback_t userfunc; @@ -2186,7 +2186,7 @@ ret = incomingim_ch1(od, conn, mod, frame, snac, channel, &userinfo, bs, cookie); } else if (channel == 2) { - aim_tlvlist_t *tlvlist; + GSList *tlvlist; /* * Read block of TLVs (not including the userinfo data). All @@ -2196,14 +2196,14 @@ ret = incomingim_ch2(od, conn, mod, frame, snac, channel, &userinfo, tlvlist, cookie); - aim_tlvlist_free(&tlvlist); + aim_tlvlist_free(tlvlist); } else if (channel == 4) { - aim_tlvlist_t *tlvlist; + GSList *tlvlist; tlvlist = aim_tlvlist_read(bs); ret = incomingim_ch4(od, conn, mod, frame, snac, channel, &userinfo, tlvlist, cookie); - aim_tlvlist_free(&tlvlist); + aim_tlvlist_free(tlvlist); } else { purple_debug_misc("oscar", "icbm: ICBM received on an unsupported channel. Ignoring. (chan = %04x)\n", channel); @@ -2284,7 +2284,7 @@ FlapConnection *conn; FlapFrame *frame; aim_snacid_t snacid; - aim_tlvlist_t *tl = NULL; + GSList *tlvlist = NULL; if (!od || !(conn = flap_connection_findbygroup(od, 0x0004))) return -EINVAL; @@ -2300,9 +2300,9 @@ byte_stream_put8(&frame->data, strlen(sn)); byte_stream_putstr(&frame->data, sn); - aim_tlvlist_add_16(&tl, 0x0003, code); - aim_tlvlist_write(&frame->data, &tl); - aim_tlvlist_free(&tl); + aim_tlvlist_add_16(&tlvlist, 0x0003, code); + aim_tlvlist_write(&frame->data, &tlvlist); + aim_tlvlist_free(tlvlist); flap_connection_send(conn, frame);
--- a/libpurple/protocols/oscar/family_icq.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/oscar/family_icq.c Mon Jun 18 01:48:35 2007 +0000 @@ -474,14 +474,14 @@ icqresponse(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs) { int ret = 0; - aim_tlvlist_t *tl; + GSList *tlvlist; aim_tlv_t *datatlv; ByteStream qbs; guint32 ouruin; guint16 cmdlen, cmd, reqid; - if (!(tl = aim_tlvlist_read(bs)) || !(datatlv = aim_tlv_gettlv(tl, 0x0001, 1))) { - aim_tlvlist_free(&tl); + if (!(tlvlist = aim_tlvlist_read(bs)) || !(datatlv = aim_tlv_gettlv(tlvlist, 0x0001, 1))) { + aim_tlvlist_free(tlvlist); purple_debug_misc("oscar", "corrupt ICQ response\n"); return 0; } @@ -661,7 +661,7 @@ } } - aim_tlvlist_free(&tl); + aim_tlvlist_free(tlvlist); return ret; }
--- a/libpurple/protocols/oscar/family_locate.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/oscar/family_locate.c Mon Jun 18 01:48:35 2007 +0000 @@ -930,7 +930,7 @@ int aim_putuserinfo(ByteStream *bs, aim_userinfo_t *info) { - aim_tlvlist_t *tlvlist = NULL; + GSList *tlvlist = NULL; if (!bs || !info) return -EINVAL; @@ -965,9 +965,9 @@ if (info->present & AIM_USERINFO_PRESENT_SESSIONLEN) aim_tlvlist_add_32(&tlvlist, (guint16)((info->flags & AIM_FLAG_AOL) ? 0x0010 : 0x000f), info->sessionlen); - byte_stream_put16(bs, aim_tlvlist_count(&tlvlist)); + byte_stream_put16(bs, aim_tlvlist_count(tlvlist)); aim_tlvlist_write(bs, &tlvlist); - aim_tlvlist_free(&tlvlist); + aim_tlvlist_free(tlvlist); return 0; } @@ -1050,7 +1050,7 @@ static int rights(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs) { - aim_tlvlist_t *tlvlist; + GSList *tlvlist; aim_rxcallback_t userfunc; int ret = 0; guint16 maxsiglen = 0; @@ -1063,7 +1063,7 @@ if ((userfunc = aim_callhandler(od, snac->family, snac->subtype))) ret = userfunc(od, conn, frame, maxsiglen); - aim_tlvlist_free(&tlvlist); + aim_tlvlist_free(tlvlist); return ret; } @@ -1096,7 +1096,7 @@ FlapConnection *conn; FlapFrame *frame; aim_snacid_t snacid; - aim_tlvlist_t *tl = NULL; + GSList *tlvlist = NULL; char *encoding; static const char defencoding[] = {"text/aolrtf; charset=\"%s\""}; @@ -1115,8 +1115,8 @@ /* no + 1 here because of %s */ encoding = g_malloc(strlen(defencoding) + strlen(profile_encoding)); snprintf(encoding, strlen(defencoding) + strlen(profile_encoding), defencoding, profile_encoding); - aim_tlvlist_add_str(&tl, 0x0001, encoding); - aim_tlvlist_add_raw(&tl, 0x0002, profile_len, (const guchar *)profile); + aim_tlvlist_add_str(&tlvlist, 0x0001, encoding); + aim_tlvlist_add_raw(&tlvlist, 0x0002, profile_len, (const guchar *)profile); g_free(encoding); } @@ -1132,20 +1132,20 @@ if (awaymsg_len) { encoding = g_malloc(strlen(defencoding) + strlen(awaymsg_encoding)); snprintf(encoding, strlen(defencoding) + strlen(awaymsg_encoding), defencoding, awaymsg_encoding); - aim_tlvlist_add_str(&tl, 0x0003, encoding); - aim_tlvlist_add_raw(&tl, 0x0004, awaymsg_len, (const guchar *)awaymsg); + aim_tlvlist_add_str(&tlvlist, 0x0003, encoding); + aim_tlvlist_add_raw(&tlvlist, 0x0004, awaymsg_len, (const guchar *)awaymsg); g_free(encoding); } else - aim_tlvlist_add_noval(&tl, 0x0004); + aim_tlvlist_add_noval(&tlvlist, 0x0004); } - frame = flap_frame_new(od, 0x02, 10 + aim_tlvlist_size(&tl)); + frame = flap_frame_new(od, 0x02, 10 + aim_tlvlist_size(tlvlist)); snacid = aim_cachesnac(od, 0x0002, 0x0004, 0x0000, NULL, 0); aim_putsnac(&frame->data, 0x0002, 0x004, 0x0000, snacid); - aim_tlvlist_write(&frame->data, &tl); - aim_tlvlist_free(&tl); + aim_tlvlist_write(&frame->data, &tlvlist); + aim_tlvlist_free(tlvlist); flap_connection_send(conn, frame); @@ -1161,20 +1161,20 @@ FlapConnection *conn; FlapFrame *frame; aim_snacid_t snacid; - aim_tlvlist_t *tl = NULL; + GSList *tlvlist = NULL; if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_LOCATE))) return -EINVAL; - aim_tlvlist_add_caps(&tl, 0x0005, caps); + aim_tlvlist_add_caps(&tlvlist, 0x0005, caps); - frame = flap_frame_new(od, 0x02, 10 + aim_tlvlist_size(&tl)); + frame = flap_frame_new(od, 0x02, 10 + aim_tlvlist_size(tlvlist)); snacid = aim_cachesnac(od, 0x0002, 0x0004, 0x0000, NULL, 0); aim_putsnac(&frame->data, 0x0002, 0x004, 0x0000, snacid); - aim_tlvlist_write(&frame->data, &tl); - aim_tlvlist_free(&tl); + aim_tlvlist_write(&frame->data, &tlvlist); + aim_tlvlist_free(tlvlist); flap_connection_send(conn, frame); @@ -1221,7 +1221,7 @@ int ret = 0; aim_rxcallback_t userfunc; aim_userinfo_t *userinfo, *userinfo2; - aim_tlvlist_t *tlvlist; + GSList *tlvlist; aim_tlv_t *tlv = NULL; int was_explicit; @@ -1252,7 +1252,7 @@ userinfo->capabilities = aim_locate_getcaps(od, &cbs, tlv->length); userinfo->present = AIM_USERINFO_PRESENT_CAPABILITIES; } - aim_tlvlist_free(&tlvlist); + aim_tlvlist_free(tlvlist); aim_locate_adduserinfo(od, userinfo); userinfo2 = aim_locate_finduserinfo(od, userinfo->sn); @@ -1284,42 +1284,42 @@ FlapConnection *conn; FlapFrame *frame; aim_snacid_t snacid; - aim_tlvlist_t *tl = NULL; + GSList *tlvlist = NULL; if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_LOCATE))) return -EINVAL; - aim_tlvlist_add_16(&tl, 0x000a, privacy); + aim_tlvlist_add_16(&tlvlist, 0x000a, privacy); if (first) - aim_tlvlist_add_str(&tl, 0x0001, first); + aim_tlvlist_add_str(&tlvlist, 0x0001, first); if (last) - aim_tlvlist_add_str(&tl, 0x0002, last); + aim_tlvlist_add_str(&tlvlist, 0x0002, last); if (middle) - aim_tlvlist_add_str(&tl, 0x0003, middle); + aim_tlvlist_add_str(&tlvlist, 0x0003, middle); if (maiden) - aim_tlvlist_add_str(&tl, 0x0004, maiden); + aim_tlvlist_add_str(&tlvlist, 0x0004, maiden); if (state) - aim_tlvlist_add_str(&tl, 0x0007, state); + aim_tlvlist_add_str(&tlvlist, 0x0007, state); if (city) - aim_tlvlist_add_str(&tl, 0x0008, city); + aim_tlvlist_add_str(&tlvlist, 0x0008, city); if (nickname) - aim_tlvlist_add_str(&tl, 0x000c, nickname); + aim_tlvlist_add_str(&tlvlist, 0x000c, nickname); if (zip) - aim_tlvlist_add_str(&tl, 0x000d, zip); + aim_tlvlist_add_str(&tlvlist, 0x000d, zip); if (street) - aim_tlvlist_add_str(&tl, 0x0021, street); + aim_tlvlist_add_str(&tlvlist, 0x0021, street); - frame = flap_frame_new(od, 0x02, 10+aim_tlvlist_size(&tl)); + frame = flap_frame_new(od, 0x02, 10+aim_tlvlist_size(tlvlist)); snacid = aim_cachesnac(od, 0x0002, 0x0009, 0x0000, NULL, 0); aim_putsnac(&frame->data, 0x0002, 0x0009, 0x0000, snacid); - aim_tlvlist_write(&frame->data, &tl); - aim_tlvlist_free(&tl); + aim_tlvlist_write(&frame->data, &tlvlist); + aim_tlvlist_free(tlvlist); flap_connection_send(conn, frame); @@ -1365,32 +1365,32 @@ FlapConnection *conn; FlapFrame *frame; aim_snacid_t snacid; - aim_tlvlist_t *tl = NULL; + GSList *tlvlist = NULL; if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_LOCATE))) return -EINVAL; /* ?? privacy ?? */ - aim_tlvlist_add_16(&tl, 0x000a, privacy); + aim_tlvlist_add_16(&tlvlist, 0x000a, privacy); if (interest1) - aim_tlvlist_add_str(&tl, 0x0000b, interest1); + aim_tlvlist_add_str(&tlvlist, 0x0000b, interest1); if (interest2) - aim_tlvlist_add_str(&tl, 0x0000b, interest2); + aim_tlvlist_add_str(&tlvlist, 0x0000b, interest2); if (interest3) - aim_tlvlist_add_str(&tl, 0x0000b, interest3); + aim_tlvlist_add_str(&tlvlist, 0x0000b, interest3); if (interest4) - aim_tlvlist_add_str(&tl, 0x0000b, interest4); + aim_tlvlist_add_str(&tlvlist, 0x0000b, interest4); if (interest5) - aim_tlvlist_add_str(&tl, 0x0000b, interest5); + aim_tlvlist_add_str(&tlvlist, 0x0000b, interest5); - frame = flap_frame_new(od, 0x02, 10+aim_tlvlist_size(&tl)); + frame = flap_frame_new(od, 0x02, 10+aim_tlvlist_size(tlvlist)); snacid = aim_cachesnac(od, 0x0002, 0x000f, 0x0000, NULL, 0); aim_putsnac(&frame->data, 0x0002, 0x000f, 0x0000, 0); - aim_tlvlist_write(&frame->data, &tl); - aim_tlvlist_free(&tl); + aim_tlvlist_write(&frame->data, &tlvlist); + aim_tlvlist_free(tlvlist); flap_connection_send(conn, frame);
--- a/libpurple/protocols/oscar/family_odir.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/oscar/family_odir.c Mon Jun 18 01:48:35 2007 +0000 @@ -43,22 +43,22 @@ FlapConnection *conn; FlapFrame *frame; aim_snacid_t snacid; - aim_tlvlist_t *tl = NULL; + GSList *tlvlist = NULL; if (!od || !(conn = flap_connection_findbygroup(od, 0x000f)) || !region || !email) return -EINVAL; /* Create a TLV chain, write it to the outgoing frame, then free the chain */ - aim_tlvlist_add_str(&tl, 0x001c, region); - aim_tlvlist_add_16(&tl, 0x000a, 0x0001); /* Type of search */ - aim_tlvlist_add_str(&tl, 0x0005, email); + aim_tlvlist_add_str(&tlvlist, 0x001c, region); + aim_tlvlist_add_16(&tlvlist, 0x000a, 0x0001); /* Type of search */ + aim_tlvlist_add_str(&tlvlist, 0x0005, email); - frame = flap_frame_new(od, 0x02, 10+aim_tlvlist_size(&tl)); + frame = flap_frame_new(od, 0x02, 10+aim_tlvlist_size(tlvlist)); snacid = aim_cachesnac(od, 0x000f, 0x0002, 0x0000, NULL, 0); aim_putsnac(&frame->data, 0x000f, 0x0002, 0x0000, snacid); - aim_tlvlist_write(&frame->data, &tl); - aim_tlvlist_free(&tl); + aim_tlvlist_write(&frame->data, &tlvlist); + aim_tlvlist_free(tlvlist); flap_connection_send(conn, frame); @@ -91,41 +91,41 @@ FlapConnection *conn; FlapFrame *frame; aim_snacid_t snacid; - aim_tlvlist_t *tl = NULL; + GSList *tlvlist = NULL; if (!od || !(conn = flap_connection_findbygroup(od, 0x000f)) || !region) return -EINVAL; /* Create a TLV chain, write it to the outgoing frame, then free the chain */ - aim_tlvlist_add_str(&tl, 0x001c, region); - aim_tlvlist_add_16(&tl, 0x000a, 0x0000); /* Type of search */ + aim_tlvlist_add_str(&tlvlist, 0x001c, region); + aim_tlvlist_add_16(&tlvlist, 0x000a, 0x0000); /* Type of search */ if (first) - aim_tlvlist_add_str(&tl, 0x0001, first); + aim_tlvlist_add_str(&tlvlist, 0x0001, first); if (last) - aim_tlvlist_add_str(&tl, 0x0002, last); + aim_tlvlist_add_str(&tlvlist, 0x0002, last); if (middle) - aim_tlvlist_add_str(&tl, 0x0003, middle); + aim_tlvlist_add_str(&tlvlist, 0x0003, middle); if (maiden) - aim_tlvlist_add_str(&tl, 0x0004, maiden); + aim_tlvlist_add_str(&tlvlist, 0x0004, maiden); if (country) - aim_tlvlist_add_str(&tl, 0x0006, country); + aim_tlvlist_add_str(&tlvlist, 0x0006, country); if (state) - aim_tlvlist_add_str(&tl, 0x0007, state); + aim_tlvlist_add_str(&tlvlist, 0x0007, state); if (city) - aim_tlvlist_add_str(&tl, 0x0008, city); + aim_tlvlist_add_str(&tlvlist, 0x0008, city); if (nick) - aim_tlvlist_add_str(&tl, 0x000c, nick); + aim_tlvlist_add_str(&tlvlist, 0x000c, nick); if (zip) - aim_tlvlist_add_str(&tl, 0x000d, zip); + aim_tlvlist_add_str(&tlvlist, 0x000d, zip); if (address) - aim_tlvlist_add_str(&tl, 0x0021, address); + aim_tlvlist_add_str(&tlvlist, 0x0021, address); - frame = flap_frame_new(od, 0x02, 10+aim_tlvlist_size(&tl)); + frame = flap_frame_new(od, 0x02, 10+aim_tlvlist_size(tlvlist)); snacid = aim_cachesnac(od, 0x000f, 0x0002, 0x0000, NULL, 0); aim_putsnac(&frame->data, 0x000f, 0x0002, 0x0000, snacid); - aim_tlvlist_write(&frame->data, &tl); - aim_tlvlist_free(&tl); + aim_tlvlist_write(&frame->data, &tlvlist); + aim_tlvlist_free(tlvlist); flap_connection_send(conn, frame); @@ -145,23 +145,23 @@ FlapConnection *conn; FlapFrame *frame; aim_snacid_t snacid; - aim_tlvlist_t *tl = NULL; + GSList *tlvlist = NULL; if (!od || !(conn = flap_connection_findbygroup(od, 0x000f)) || !region) return -EINVAL; /* Create a TLV chain, write it to the outgoing frame, then free the chain */ - aim_tlvlist_add_str(&tl, 0x001c, region); - aim_tlvlist_add_16(&tl, 0x000a, 0x0001); /* Type of search */ + aim_tlvlist_add_str(&tlvlist, 0x001c, region); + aim_tlvlist_add_16(&tlvlist, 0x000a, 0x0001); /* Type of search */ if (interest) - aim_tlvlist_add_str(&tl, 0x0001, interest); + aim_tlvlist_add_str(&tlvlist, 0x0001, interest); - frame = flap_frame_new(od, 0x02, 10+aim_tlvlist_size(&tl)); + frame = flap_frame_new(od, 0x02, 10+aim_tlvlist_size(tlvlist)); snacid = aim_cachesnac(od, 0x000f, 0x0002, 0x0000, NULL, 0); aim_putsnac(&frame->data, 0x000f, 0x0002, 0x0000, snacid); - aim_tlvlist_write(&frame->data, &tl); - aim_tlvlist_free(&tl); + aim_tlvlist_write(&frame->data, &tlvlist); + aim_tlvlist_free(tlvlist); flap_connection_send(conn, frame); @@ -189,22 +189,22 @@ /* Allocate a linked list, 1 node per result */ while (numresults) { struct aim_odir *new; - aim_tlvlist_t *tl = aim_tlvlist_readnum(bs, byte_stream_get16(bs)); + GSList *tlvlist = aim_tlvlist_readnum(bs, byte_stream_get16(bs)); new = (struct aim_odir *)g_malloc(sizeof(struct aim_odir)); - new->first = aim_tlv_getstr(tl, 0x0001, 1); - new->last = aim_tlv_getstr(tl, 0x0002, 1); - new->middle = aim_tlv_getstr(tl, 0x0003, 1); - new->maiden = aim_tlv_getstr(tl, 0x0004, 1); - new->email = aim_tlv_getstr(tl, 0x0005, 1); - new->country = aim_tlv_getstr(tl, 0x0006, 1); - new->state = aim_tlv_getstr(tl, 0x0007, 1); - new->city = aim_tlv_getstr(tl, 0x0008, 1); - new->sn = aim_tlv_getstr(tl, 0x0009, 1); - new->interest = aim_tlv_getstr(tl, 0x000b, 1); - new->nick = aim_tlv_getstr(tl, 0x000c, 1); - new->zip = aim_tlv_getstr(tl, 0x000d, 1); - new->region = aim_tlv_getstr(tl, 0x001c, 1); - new->address = aim_tlv_getstr(tl, 0x0021, 1); + new->first = aim_tlv_getstr(tlvlist, 0x0001, 1); + new->last = aim_tlv_getstr(tlvlist, 0x0002, 1); + new->middle = aim_tlv_getstr(tlvlist, 0x0003, 1); + new->maiden = aim_tlv_getstr(tlvlist, 0x0004, 1); + new->email = aim_tlv_getstr(tlvlist, 0x0005, 1); + new->country = aim_tlv_getstr(tlvlist, 0x0006, 1); + new->state = aim_tlv_getstr(tlvlist, 0x0007, 1); + new->city = aim_tlv_getstr(tlvlist, 0x0008, 1); + new->sn = aim_tlv_getstr(tlvlist, 0x0009, 1); + new->interest = aim_tlv_getstr(tlvlist, 0x000b, 1); + new->nick = aim_tlv_getstr(tlvlist, 0x000c, 1); + new->zip = aim_tlv_getstr(tlvlist, 0x000d, 1); + new->region = aim_tlv_getstr(tlvlist, 0x001c, 1); + new->address = aim_tlv_getstr(tlvlist, 0x0021, 1); new->next = results; results = new; numresults--;
--- a/libpurple/protocols/oscar/family_oservice.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/oscar/family_oservice.c Mon Jun 18 01:48:35 2007 +0000 @@ -123,7 +123,7 @@ FlapConnection *conn; FlapFrame *frame; aim_snacid_t snacid; - aim_tlvlist_t *tl = NULL; + GSList *tlvlist = NULL; struct chatsnacinfo csi; conn = flap_connection_findbygroup(od, SNAC_FAMILY_BOS); @@ -145,9 +145,9 @@ */ byte_stream_put16(&frame->data, 0x000e); - aim_tlvlist_add_chatroom(&tl, 0x0001, exchange, roomname, instance); - aim_tlvlist_write(&frame->data, &tl); - aim_tlvlist_free(&tl); + aim_tlvlist_add_chatroom(&tlvlist, 0x0001, exchange, roomname, instance); + aim_tlvlist_write(&frame->data, &tlvlist); + aim_tlvlist_free(tlvlist); flap_connection_send(conn, frame); @@ -160,7 +160,7 @@ { struct aim_redirect_data redir; aim_rxcallback_t userfunc; - aim_tlvlist_t *tlvlist; + GSList *tlvlist; aim_snac_t *origsnac = NULL; int ret = 0; @@ -171,7 +171,7 @@ if (!aim_tlv_gettlv(tlvlist, 0x000d, 1) || !aim_tlv_gettlv(tlvlist, 0x0005, 1) || !aim_tlv_gettlv(tlvlist, 0x0006, 1)) { - aim_tlvlist_free(&tlvlist); + aim_tlvlist_free(tlvlist); return 0; } @@ -201,7 +201,7 @@ g_free(origsnac->data); g_free(origsnac); - aim_tlvlist_free(&tlvlist); + aim_tlvlist_free(tlvlist); return ret; } @@ -606,7 +606,7 @@ aim_rxcallback_t userfunc; int ret = 0; guint16 groupcount, i; - aim_tlvlist_t *tl; + GSList *tlvlist; char *ip = NULL; aim_tlv_t *cktlv; @@ -630,17 +630,17 @@ purple_debug_misc("oscar", "bifurcated migration unsupported -- group 0x%04x\n", group); } - tl = aim_tlvlist_read(bs); + tlvlist = aim_tlvlist_read(bs); - if (aim_tlv_gettlv(tl, 0x0005, 1)) - ip = aim_tlv_getstr(tl, 0x0005, 1); + if (aim_tlv_gettlv(tlvlist, 0x0005, 1)) + ip = aim_tlv_getstr(tlvlist, 0x0005, 1); - cktlv = aim_tlv_gettlv(tl, 0x0006, 1); + cktlv = aim_tlv_gettlv(tlvlist, 0x0006, 1); if ((userfunc = aim_callhandler(od, snac->family, snac->subtype))) ret = userfunc(od, conn, frame, ip, cktlv ? cktlv->value : NULL); - aim_tlvlist_free(&tl); + aim_tlvlist_free(tlvlist); g_free(ip); return ret; @@ -653,7 +653,7 @@ aim_rxcallback_t userfunc; char *msg = NULL; int ret = 0; - aim_tlvlist_t *tlvlist; + GSList *tlvlist; guint16 id; /* @@ -681,7 +681,7 @@ g_free(msg); - aim_tlvlist_free(&tlvlist); + aim_tlvlist_free(tlvlist); return ret; } @@ -805,24 +805,24 @@ FlapConnection *conn; FlapFrame *frame; aim_snacid_t snacid; - aim_tlvlist_t *tl = NULL; + GSList *tlvlist = NULL; if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICBM))) return -EINVAL; if (seticqstatus) { - aim_tlvlist_add_32(&tl, 0x0006, icqstatus | + aim_tlvlist_add_32(&tlvlist, 0x0006, icqstatus | AIM_ICQ_STATE_HIDEIP | AIM_ICQ_STATE_DIRECTREQUIREAUTH); } #if 0 if (other_stuff_that_isnt_implemented) { - aim_tlvlist_add_raw(&tl, 0x000c, 0x0025, + aim_tlvlist_add_raw(&tlvlist, 0x000c, 0x0025, chunk_of_x25_bytes_with_ip_address_etc); - aim_tlvlist_add_raw(&tl, 0x0011, 0x0005, unknown 0x01 61 10 f6 41); - aim_tlvlist_add_16(&tl, 0x0012, unknown 0x00 00); + aim_tlvlist_add_raw(&tlvlist, 0x0011, 0x0005, unknown 0x01 61 10 f6 41); + aim_tlvlist_add_16(&tlvlist, 0x0012, unknown 0x00 00); } #endif @@ -851,18 +851,18 @@ byte_stream_putstr(&tmpbs, itmsurl); byte_stream_put16(&tmpbs, 0x0000); - aim_tlvlist_add_raw(&tl, 0x001d, + aim_tlvlist_add_raw(&tlvlist, 0x001d, byte_stream_curpos(&tmpbs), tmpbs.data); g_free(tmpbs.data); } - frame = flap_frame_new(od, 0x02, 10 + aim_tlvlist_size(&tl)); + frame = flap_frame_new(od, 0x02, 10 + aim_tlvlist_size(tlvlist)); snacid = aim_cachesnac(od, 0x0001, 0x001e, 0x0000, NULL, 0); aim_putsnac(&frame->data, 0x0001, 0x001e, 0x0000, snacid); - aim_tlvlist_write(&frame->data, &tl); - aim_tlvlist_free(&tl); + aim_tlvlist_write(&frame->data, &tlvlist); + aim_tlvlist_free(tlvlist); flap_connection_send(conn, frame); @@ -913,14 +913,14 @@ int ret = 0; aim_rxcallback_t userfunc; guint32 offset, len; - aim_tlvlist_t *list; + GSList *tlvlist; char *modname; offset = byte_stream_get32(bs); len = byte_stream_get32(bs); - list = aim_tlvlist_read(bs); + tlvlist = aim_tlvlist_read(bs); - modname = aim_tlv_getstr(list, 0x0001, 1); + modname = aim_tlv_getstr(tlvlist, 0x0001, 1); purple_debug_info("oscar", "Got memory request for data at 0x%08lx (%d bytes) of requested %s\n", offset, len, modname ? modname : "aim.exe"); @@ -928,7 +928,7 @@ ret = userfunc(od, conn, frame, offset, len, modname); g_free(modname); - aim_tlvlist_free(&list); + aim_tlvlist_free(tlvlist); return ret; }
--- a/libpurple/protocols/oscar/family_popup.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/oscar/family_popup.c Mon Jun 18 01:48:35 2007 +0000 @@ -37,23 +37,23 @@ parsepopup(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs) { aim_rxcallback_t userfunc; - aim_tlvlist_t *tl; + GSList *tlvlist; int ret = 0; char *msg, *url; guint16 width, height, delay; - tl = aim_tlvlist_read(bs); + tlvlist = aim_tlvlist_read(bs); - msg = aim_tlv_getstr(tl, 0x0001, 1); - url = aim_tlv_getstr(tl, 0x0002, 1); - width = aim_tlv_get16(tl, 0x0003, 1); - height = aim_tlv_get16(tl, 0x0004, 1); - delay = aim_tlv_get16(tl, 0x0005, 1); + msg = aim_tlv_getstr(tlvlist, 0x0001, 1); + url = aim_tlv_getstr(tlvlist, 0x0002, 1); + width = aim_tlv_get16(tlvlist, 0x0003, 1); + height = aim_tlv_get16(tlvlist, 0x0004, 1); + delay = aim_tlv_get16(tlvlist, 0x0005, 1); if ((userfunc = aim_callhandler(od, snac->family, snac->subtype))) ret = userfunc(od, conn, frame, msg, url, width, height, delay); - aim_tlvlist_free(&tl); + aim_tlvlist_free(tlvlist); g_free(msg); g_free(url);
--- a/libpurple/protocols/oscar/family_userlookup.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/oscar/family_userlookup.c Mon Jun 18 01:48:35 2007 +0000 @@ -89,7 +89,7 @@ static int reply(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs) { int j = 0, m, ret = 0; - aim_tlvlist_t *tlvlist; + GSList *tlvlist; char *cur = NULL, *buf = NULL; aim_rxcallback_t userfunc; aim_snac_t *snac2; @@ -99,7 +99,7 @@ searchaddr = (const char *)snac2->data; tlvlist = aim_tlvlist_read(bs); - m = aim_tlvlist_count(&tlvlist); + m = aim_tlvlist_count(tlvlist); /* XXX uhm. * This is the only place that uses something other than 1 for the 3rd @@ -116,7 +116,7 @@ } g_free(cur); - aim_tlvlist_free(&tlvlist); + aim_tlvlist_free(tlvlist); if ((userfunc = aim_callhandler(od, snac->family, snac->subtype))) ret = userfunc(od, conn, frame, searchaddr, j, buf);
--- a/libpurple/protocols/oscar/flap_connection.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/oscar/flap_connection.c Mon Jun 18 01:48:35 2007 +0000 @@ -61,13 +61,13 @@ flap_connection_send_version_with_cookie(OscarData *od, FlapConnection *conn, guint16 length, const guint8 *chipsahoy) { FlapFrame *frame; - aim_tlvlist_t *tl = NULL; + GSList *tlvlist = NULL; frame = flap_frame_new(od, 0x01, 4 + 2 + 2 + length); byte_stream_put32(&frame->data, 0x00000001); - aim_tlvlist_add_raw(&tl, 0x0006, length, chipsahoy); - aim_tlvlist_write(&frame->data, &tl); - aim_tlvlist_free(&tl); + aim_tlvlist_add_raw(&tlvlist, 0x0006, length, chipsahoy); + aim_tlvlist_write(&frame->data, &tlvlist); + aim_tlvlist_free(tlvlist); flap_connection_send(conn, frame); } @@ -303,7 +303,7 @@ } } - if (conn->fd != -1) + if (conn->fd >= 0) { if (conn->type == SNAC_FAMILY_LOCATE) flap_connection_send_close(od, conn); @@ -693,7 +693,7 @@ static void parse_flap_ch4(OscarData *od, FlapConnection *conn, FlapFrame *frame) { - aim_tlvlist_t *tlvlist; + GSList *tlvlist; char *msg = NULL; guint16 code = 0; aim_rxcallback_t userfunc; @@ -721,7 +721,7 @@ if ((userfunc = aim_callhandler(od, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR))) userfunc(od, conn, frame, code, msg); - aim_tlvlist_free(&tlvlist); + aim_tlvlist_free(tlvlist); g_free(msg); } @@ -792,7 +792,7 @@ } /* If there was an error then close the connection */ - if (read == -1) + if (read < 0) { if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) /* No worries */ @@ -853,7 +853,7 @@ break; } - if (read == -1) + if (read < 0) { if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) /* No worries */ @@ -902,7 +902,7 @@ ret = send(conn->fd, conn->buffer_outgoing->outptr, writelen, 0); if (ret <= 0) { - if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) + if (ret < 0 && ((errno == EAGAIN) || (errno == EWOULDBLOCK))) /* No worries */ return; @@ -936,7 +936,7 @@ purple_circ_buffer_append(conn->buffer_outgoing, bs->data, count); /* If we haven't already started writing stuff, then start the cycle */ - if ((conn->watcher_outgoing == 0) && (conn->fd != -1)) + if ((conn->watcher_outgoing == 0) && (conn->fd >= 0)) { conn->watcher_outgoing = purple_input_add(conn->fd, PURPLE_INPUT_WRITE, send_cb, conn);
--- a/libpurple/protocols/oscar/odc.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/oscar/odc.c Mon Jun 18 01:48:35 2007 +0000 @@ -447,7 +447,7 @@ return; } - if (read == -1) + if (read < 0) { if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) /* No worries */
--- a/libpurple/protocols/oscar/oscar.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/oscar/oscar.c Mon Jun 18 01:48:35 2007 +0000 @@ -298,7 +298,7 @@ } gchar * -oscar_encoding_to_utf8(const char *encoding, const char *text, int textlen) +oscar_encoding_to_utf8(PurpleAccount *account, const char *encoding, const char *text, int textlen) { gchar *utf8 = NULL; @@ -311,7 +311,25 @@ { utf8 = g_convert(text, textlen, "UTF-8", "Windows-1252", NULL, NULL, NULL); } else if (!g_ascii_strcasecmp(encoding, "unicode-2-0")) { - utf8 = g_convert(text, textlen, "UTF-8", "UCS-2BE", NULL, NULL, NULL); + /* Some official ICQ clients are apparently total crack, + * and have been known to save a UTF-8 string converted + * from the locale character set to UCS-2 (not from UTF-8 + * to UCS-2!) in the away message. This hack should find + * and do something (un)reasonable with that, and not + * mess up too much else. */ + const gchar *charset = purple_account_get_string(account, "encoding", NULL); + if (charset) { + gsize len; + utf8 = g_convert(text, textlen, charset, "UCS-2BE", &len, NULL, NULL); + if (!utf8 || len != textlen || !g_utf8_validate(utf8, -1, NULL)) { + g_free(utf8); + utf8 = NULL; + } else { + purple_debug_info("oscar", "Used broken ICQ fallback encoding\n"); + } + } + if (!utf8) + utf8 = g_convert(text, textlen, "UTF-8", "UCS-2BE", NULL, NULL, NULL); } else if (g_ascii_strcasecmp(encoding, "utf-8")) { purple_debug_warning("oscar", "Unrecognized character encoding \"%s\", " "attempting to convert to UTF-8 anyway\n", encoding); @@ -1604,8 +1622,7 @@ straight_to_hell, pos) == NULL) { char buf[256]; - if (pos->modname) - g_free(pos->modname); + g_free(pos->modname); g_free(pos); g_snprintf(buf, sizeof(buf), _("You may be disconnected shortly. " "Check %s for updates."), PURPLE_WEBSITE); @@ -1775,7 +1792,7 @@ { have_status_message = TRUE; if (info->status[0] != '\0') - message = oscar_encoding_to_utf8(info->status_encoding, + message = oscar_encoding_to_utf8(account, info->status_encoding, info->status, info->status_len); } @@ -1791,7 +1808,7 @@ if ((status_id == OSCAR_STATUS_ID_AVAILABLE) && (info->itmsurl != NULL)) { char *itmsurl; - itmsurl = oscar_encoding_to_utf8(info->itmsurl_encoding, + itmsurl = oscar_encoding_to_utf8(account, info->itmsurl_encoding, info->itmsurl, info->itmsurl_len); purple_prpl_got_user_status(account, info->sn, status_id, "message", message, "itmsurl", itmsurl, NULL); @@ -1826,9 +1843,8 @@ signon = time(NULL) - info->sessionlen; if (!aim_sncmp(purple_account_get_username(account), info->sn)) { purple_connection_set_display_name(gc, info->sn); - od->timeoffset = signon - purple_presence_get_login_time(presence); - } - purple_prpl_got_user_login_time(account, info->sn, signon - od->timeoffset); + } + purple_prpl_got_user_login_time(account, info->sn, signon); /* Idle time stuff */ /* info->idletime is the number of minutes that this user has been idle */ @@ -2049,7 +2065,8 @@ { char *encoding = NULL; encoding = oscar_encoding_extract(args->encoding); - message = oscar_encoding_to_utf8(encoding, args->msg, args->msglen); + message = oscar_encoding_to_utf8(account, encoding, args->msg, + args->msglen); g_free(encoding); } else { if (g_utf8_validate(args->msg, args->msglen, NULL)) @@ -2067,7 +2084,7 @@ return 1; } encoding = args->encoding ? oscar_encoding_extract(args->encoding) : NULL; - utf8name = oscar_encoding_to_utf8(encoding, + utf8name = oscar_encoding_to_utf8(account, encoding, args->info.chat.roominfo.name, args->info.chat.roominfo.namelen); g_free(encoding); @@ -2202,7 +2219,7 @@ buddy->name, group->name); aim_ssi_sendauthrequest(od, data->name, msg ? msg : _("Please authorize me so I can add you to my buddy list.")); if (!aim_ssi_itemlist_finditem(od->ssi.local, group->name, buddy->name, AIM_SSI_TYPE_BUDDY)) - aim_ssi_addbuddy(od, buddy->name, group->name, purple_buddy_get_alias_only(buddy), NULL, NULL, 1); + aim_ssi_addbuddy(od, buddy->name, group->name, NULL, purple_buddy_get_alias_only(buddy), NULL, NULL, TRUE); } } @@ -2850,12 +2867,12 @@ g_free(tmp); if (userinfo->present & AIM_USERINFO_PRESENT_ONLINESINCE) { - time_t t = userinfo->onlinesince - od->timeoffset; + time_t t = userinfo->onlinesince; oscar_user_info_add_pair(user_info, _("Online Since"), purple_date_format_full(localtime(&t))); } if (userinfo->present & AIM_USERINFO_PRESENT_MEMBERSINCE) { - time_t t = userinfo->membersince - od->timeoffset; + time_t t = userinfo->membersince; oscar_user_info_add_pair(user_info, _("Member Since"), purple_date_format_full(localtime(&t))); } @@ -2877,12 +2894,12 @@ if ((userinfo->status != NULL) && !(userinfo->flags & AIM_FLAG_AWAY)) { if (userinfo->status[0] != '\0') - tmp = oscar_encoding_to_utf8(userinfo->status_encoding, + tmp = oscar_encoding_to_utf8(account, userinfo->status_encoding, userinfo->status, userinfo->status_len); #if defined (_WIN32) || defined (__APPLE__) if (userinfo->itmsurl && (userinfo->itmsurl[0] != '\0')) { gchar *itmsurl, *tmp2; - itmsurl = oscar_encoding_to_utf8(userinfo->itmsurl_encoding, + itmsurl = oscar_encoding_to_utf8(account, userinfo->itmsurl_encoding, userinfo->itmsurl, userinfo->itmsurl_len); tmp2 = g_strdup_printf("<a href=\"%s\">%s</a>", itmsurl, tmp); @@ -2898,7 +2915,8 @@ /* Away message */ if ((userinfo->flags & AIM_FLAG_AWAY) && (userinfo->away_len > 0) && (userinfo->away != NULL) && (userinfo->away_encoding != NULL)) { tmp = oscar_encoding_extract(userinfo->away_encoding); - away_utf8 = oscar_encoding_to_utf8(tmp, userinfo->away, userinfo->away_len); + away_utf8 = oscar_encoding_to_utf8(account, tmp, userinfo->away, + userinfo->away_len); g_free(tmp); if (away_utf8 != NULL) { tmp = purple_str_sub_away_formatters(away_utf8, purple_account_get_username(account)); @@ -2912,7 +2930,8 @@ /* Info */ if ((userinfo->info_len > 0) && (userinfo->info != NULL) && (userinfo->info_encoding != NULL)) { tmp = oscar_encoding_extract(userinfo->info_encoding); - info_utf8 = oscar_encoding_to_utf8(tmp, userinfo->info, userinfo->info_len); + info_utf8 = oscar_encoding_to_utf8(account, tmp, userinfo->info, + userinfo->info_len); g_free(tmp); if (info_utf8 != NULL) { tmp = purple_str_sub_away_formatters(info_utf8, purple_account_get_username(account)); @@ -2932,6 +2951,7 @@ static int purple_got_infoblock(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) { PurpleConnection *gc = od->gc; + PurpleAccount *account = purple_connection_get_account(gc); PurpleBuddy *b; PurplePresence *presence; PurpleStatus *status; @@ -2944,7 +2964,7 @@ userinfo = va_arg(ap, aim_userinfo_t *); va_end(ap); - b = purple_find_buddy(purple_connection_get_account(gc), userinfo->sn); + b = purple_find_buddy(account, userinfo->sn); if (b == NULL) return 1; @@ -2964,7 +2984,9 @@ if ((userinfo->flags & AIM_FLAG_AWAY) && (userinfo->away_len > 0) && (userinfo->away != NULL) && (userinfo->away_encoding != NULL)) { gchar *charset = oscar_encoding_extract(userinfo->away_encoding); - message = oscar_encoding_to_utf8(charset, userinfo->away, userinfo->away_len); + message = oscar_encoding_to_utf8(account, charset, + userinfo->away, + userinfo->away_len); g_free(charset); purple_status_set_attr_string(status, "message", message); g_free(message); @@ -3160,6 +3182,7 @@ static int purple_conv_chat_incoming_msg(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) { PurpleConnection *gc = od->gc; + PurpleAccount *account = purple_connection_get_account(gc); struct chat_connection *ccon = find_oscar_chat_by_conn(gc, conn); gchar *utf8; va_list ap; @@ -3178,7 +3201,7 @@ charset = va_arg(ap, char *); va_end(ap); - utf8 = oscar_encoding_to_utf8(charset, msg, len); + utf8 = oscar_encoding_to_utf8(account, charset, msg, len); if (utf8 == NULL) /* The conversion failed! */ utf8 = g_strdup(_("[Unable to display a message from this user because it contained invalid characters.]")); @@ -4168,6 +4191,7 @@ PeerConnection *conn; int ret; char *tmp1, *tmp2; + gboolean is_html; od = (OscarData *)gc->proto_data; account = purple_connection_get_account(gc); @@ -4186,7 +4210,6 @@ } else { struct buddyinfo *bi; struct aim_sendimext_args args; - gsize len; PurpleConversation *conv; PurpleStoredImage *img; @@ -4277,22 +4300,43 @@ if (aim_sn_is_sms(name)) { /* Messaging an SMS (mobile) user */ tmp2 = purple_markup_strip_html(tmp1); + is_html = FALSE; } else if (aim_sn_is_icq(purple_account_get_username(account))) { - if (aim_sn_is_icq(name)) + if (aim_sn_is_icq(name)) { /* From ICQ to ICQ */ tmp2 = purple_markup_strip_html(tmp1); - else + is_html = FALSE; + } else { /* From ICQ to AIM */ tmp2 = g_strdup(tmp1); + is_html = TRUE; + } } else { /* From AIM to AIM and AIM to ICQ */ tmp2 = g_strdup(tmp1); + is_html = TRUE; } g_free(tmp1); tmp1 = tmp2; - len = strlen(tmp1); purple_plugin_oscar_convert_to_best_encoding(gc, name, tmp1, (char **)&args.msg, &args.msglen, &args.charset, &args.charsubset); + if (is_html && (args.msglen > MAXMSGLEN)) { + /* If the length was too long, try stripping the HTML and then running it back through + * purple_strdup_withhtml() and the encoding process. The result may be shorter. */ + g_free((char *)args.msg); + + tmp2 = purple_markup_strip_html(tmp1); + g_free(tmp1); + + tmp1 = purple_strdup_withhtml(tmp2); + g_free(tmp2); + + purple_plugin_oscar_convert_to_best_encoding(gc, name, tmp1, (char **)&args.msg, &args.msglen, &args.charset, &args.charsubset); + + purple_debug_info("oscar", "Sending %s as %s because the original was too long.", + message, (char *)args.msg); + } + purple_debug_info("oscar", "Sending IM, charset=0x%04hx, charsubset=0x%04hx, length=%d\n", args.charset, args.charsubset, args.msglen); ret = aim_im_sendch1_ext(od, &args); @@ -4387,7 +4431,7 @@ if (purple_account_get_bool(account, "web_aware", OSCAR_DEFAULT_WEB_AWARE)) data |= AIM_ICQ_STATE_WEBAWARE; - if (!strcmp(status_id, OSCAR_STATUS_ID_AVAILABLE) || !strcmp(status_id, OSCAR_STATUS_ID_AVAILABLE)) + if (!strcmp(status_id, OSCAR_STATUS_ID_AVAILABLE)) data |= AIM_ICQ_STATE_NORMAL; else if (!strcmp(status_id, OSCAR_STATUS_ID_AWAY)) data |= AIM_ICQ_STATE_AWAY; @@ -4592,7 +4636,7 @@ if ((od->ssi.received_data) && !(aim_ssi_itemlist_finditem(od->ssi.local, group->name, buddy->name, AIM_SSI_TYPE_BUDDY))) { purple_debug_info("oscar", "ssi: adding buddy %s to group %s\n", buddy->name, group->name); - aim_ssi_addbuddy(od, buddy->name, group->name, purple_buddy_get_alias_only(buddy), NULL, NULL, 0); + aim_ssi_addbuddy(od, buddy->name, group->name, NULL, purple_buddy_get_alias_only(buddy), NULL, NULL, 0); } /* XXX - Should this be done from AIM accounts, as well? */ @@ -5324,7 +5368,7 @@ OscarData *od = (OscarData *)gc->proto_data; PurpleConversation *conv = NULL; struct chat_connection *c = NULL; - char *buf, *buf2; + char *buf, *buf2, *buf3; guint16 charset, charsubset; char *charsetstr = NULL; int len; @@ -5336,7 +5380,6 @@ return -EINVAL; buf = purple_strdup_withhtml(message); - len = strlen(buf); if (strstr(buf, "<IMG ")) purple_conversation_write(conv, "", @@ -5350,8 +5393,28 @@ * visible characters" and not "number of bytes" */ if ((len > c->maxlen) || (len > c->maxvis)) { + /* If the length was too long, try stripping the HTML and then running it back through + * purple_strdup_withhtml() and the encoding process. The result may be shorter. */ g_free(buf2); - return -E2BIG; + + buf3 = purple_markup_strip_html(buf); + g_free(buf); + + buf = purple_strdup_withhtml(buf3); + g_free(buf3); + + purple_plugin_oscar_convert_to_best_encoding(gc, NULL, buf, &buf2, &len, &charset, &charsubset); + + if ((len > c->maxlen) || (len > c->maxvis)) { + purple_debug_warning("oscar", "Could not send %s because (%i > maxlen %i) or (%i > maxvis %i)", + buf2, len, c->maxlen, len, c->maxvis); + g_free(buf); + g_free(buf2); + return -E2BIG; + } + + purple_debug_info("oscar", "Sending %s as %s because the original was too long.", + message, buf2); } if (charset == AIM_CHARSET_ASCII) @@ -5362,6 +5425,7 @@ charsetstr = "iso-8859-1"; aim_chat_send_im(od, c->conn, 0, buf2, len, charsetstr, "en"); g_free(buf2); + g_free(buf); return 0; }
--- a/libpurple/protocols/oscar/oscar.h Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/oscar/oscar.h Mon Jun 18 01:48:35 2007 +0000 @@ -447,7 +447,6 @@ guint icontimer; guint getblisttimer; guint getinfotimer; - gint timeoffset; struct { guint maxwatchers; /* max users who can watch you */ @@ -935,7 +934,7 @@ /* 0x0014 */ int aim_im_sendmtn(OscarData *od, guint16 type1, const char *sn, guint16 type2); void aim_icbm_makecookie(guchar* cookie); gchar *oscar_encoding_extract(const char *encoding); -gchar *oscar_encoding_to_utf8(const char *encoding, const char *text, int textlen); +gchar *oscar_encoding_to_utf8(PurpleAccount *account, const char *encoding, const char *text, int textlen); gchar *purple_plugin_oscar_decode_im_part(PurpleAccount *account, const char *sourcesn, guint16 charset, guint16 charsubset, const gchar *data, gsize datalen); @@ -1172,7 +1171,7 @@ guint16 gid; guint16 bid; guint16 type; - struct aim_tlvlist_s *data; + GSList *data; struct aim_ssi_item *next; }; @@ -1208,7 +1207,7 @@ gboolean aim_ssi_waitingforauth(struct aim_ssi_item *list, const char *gn, const char *sn); /* Client functions for changing SSI data */ -int aim_ssi_addbuddy(OscarData *od, const char *name, const char *group, const char *alias, const char *comment, const char *smsnum, int needauth); +int aim_ssi_addbuddy(OscarData *od, const char *name, const char *group, GSList *tlvlist, const char *alias, const char *comment, const char *smsnum, gboolean needauth); int aim_ssi_addpermit(OscarData *od, const char *name); int aim_ssi_adddeny(OscarData *od, const char *name); int aim_ssi_delbuddy(OscarData *od, const char *name, const char *group); @@ -1357,54 +1356,47 @@ guint8 *value; } aim_tlv_t; -/* TLV List structure */ -typedef struct aim_tlvlist_s -{ - aim_tlv_t *tlv; - struct aim_tlvlist_s *next; -} aim_tlvlist_t; - /* TLV handling functions */ char *aim_tlv_getvalue_as_string(aim_tlv_t *tlv); -aim_tlv_t *aim_tlv_gettlv(aim_tlvlist_t *list, guint16 type, const int nth); -int aim_tlv_getlength(aim_tlvlist_t *list, guint16 type, const int nth); -char *aim_tlv_getstr(aim_tlvlist_t *list, const guint16 type, const int nth); -guint8 aim_tlv_get8(aim_tlvlist_t *list, const guint16 type, const int nth); -guint16 aim_tlv_get16(aim_tlvlist_t *list, const guint16 type, const int nth); -guint32 aim_tlv_get32(aim_tlvlist_t *list, const guint16 type, const int nth); +aim_tlv_t *aim_tlv_gettlv(GSList *list, guint16 type, const int nth); +int aim_tlv_getlength(GSList *list, guint16 type, const int nth); +char *aim_tlv_getstr(GSList *list, const guint16 type, const int nth); +guint8 aim_tlv_get8(GSList *list, const guint16 type, const int nth); +guint16 aim_tlv_get16(GSList *list, const guint16 type, const int nth); +guint32 aim_tlv_get32(GSList *list, const guint16 type, const int nth); /* TLV list handling functions */ -aim_tlvlist_t *aim_tlvlist_read(ByteStream *bs); -aim_tlvlist_t *aim_tlvlist_readnum(ByteStream *bs, guint16 num); -aim_tlvlist_t *aim_tlvlist_readlen(ByteStream *bs, guint16 len); -aim_tlvlist_t *aim_tlvlist_copy(aim_tlvlist_t *orig); +GSList *aim_tlvlist_read(ByteStream *bs); +GSList *aim_tlvlist_readnum(ByteStream *bs, guint16 num); +GSList *aim_tlvlist_readlen(ByteStream *bs, guint16 len); +GSList *aim_tlvlist_copy(GSList *orig); -int aim_tlvlist_count(aim_tlvlist_t **list); -int aim_tlvlist_size(aim_tlvlist_t **list); -int aim_tlvlist_cmp(aim_tlvlist_t *one, aim_tlvlist_t *two); -int aim_tlvlist_write(ByteStream *bs, aim_tlvlist_t **list); -void aim_tlvlist_free(aim_tlvlist_t **list); +int aim_tlvlist_count(GSList *list); +int aim_tlvlist_size(GSList *list); +int aim_tlvlist_cmp(GSList *one, GSList *two); +int aim_tlvlist_write(ByteStream *bs, GSList **list); +void aim_tlvlist_free(GSList *list); -int aim_tlvlist_add_raw(aim_tlvlist_t **list, const guint16 type, const guint16 length, const guint8 *value); -int aim_tlvlist_add_noval(aim_tlvlist_t **list, const guint16 type); -int aim_tlvlist_add_8(aim_tlvlist_t **list, const guint16 type, const guint8 value); -int aim_tlvlist_add_16(aim_tlvlist_t **list, const guint16 type, const guint16 value); -int aim_tlvlist_add_32(aim_tlvlist_t **list, const guint16 type, const guint32 value); -int aim_tlvlist_add_str(aim_tlvlist_t **list, const guint16 type, const char *value); -int aim_tlvlist_add_caps(aim_tlvlist_t **list, const guint16 type, const guint32 caps); -int aim_tlvlist_add_userinfo(aim_tlvlist_t **list, guint16 type, aim_userinfo_t *userinfo); -int aim_tlvlist_add_chatroom(aim_tlvlist_t **list, guint16 type, guint16 exchange, const char *roomname, guint16 instance); -int aim_tlvlist_add_frozentlvlist(aim_tlvlist_t **list, guint16 type, aim_tlvlist_t **tl); +int aim_tlvlist_add_raw(GSList **list, const guint16 type, const guint16 length, const guint8 *value); +int aim_tlvlist_add_noval(GSList **list, const guint16 type); +int aim_tlvlist_add_8(GSList **list, const guint16 type, const guint8 value); +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_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); -int aim_tlvlist_replace_raw(aim_tlvlist_t **list, const guint16 type, const guint16 lenth, const guint8 *value); -int aim_tlvlist_replace_str(aim_tlvlist_t **list, const guint16 type, const char *str); -int aim_tlvlist_replace_noval(aim_tlvlist_t **list, const guint16 type); -int aim_tlvlist_replace_8(aim_tlvlist_t **list, const guint16 type, const guint8 value); -int aim_tlvlist_replace_16(aim_tlvlist_t **list, const guint16 type, const guint16 value); -int aim_tlvlist_replace_32(aim_tlvlist_t **list, const guint16 type, const guint32 value); +int aim_tlvlist_replace_raw(GSList **list, const guint16 type, const guint16 lenth, const guint8 *value); +int aim_tlvlist_replace_str(GSList **list, const guint16 type, const char *str); +int aim_tlvlist_replace_noval(GSList **list, const guint16 type); +int aim_tlvlist_replace_8(GSList **list, const guint16 type, const guint8 value); +int aim_tlvlist_replace_16(GSList **list, const guint16 type, const guint16 value); +int aim_tlvlist_replace_32(GSList **list, const guint16 type, const guint32 value); -void aim_tlvlist_remove(aim_tlvlist_t **list, const guint16 type); +void aim_tlvlist_remove(GSList **list, const guint16 type);
--- a/libpurple/protocols/oscar/peer.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/oscar/peer.c Mon Jun 18 01:48:35 2007 +0000 @@ -173,12 +173,12 @@ purple_input_remove(conn->watcher_outgoing); conn->watcher_outgoing = 0; } - if (conn->listenerfd != -1) + if (conn->listenerfd >= 0) { close(conn->listenerfd); conn->listenerfd = -1; } - if (conn->fd != -1) + if (conn->fd >= 0) { close(conn->fd); conn->fd = -1; @@ -310,7 +310,7 @@ } /* If there was an error then close the connection */ - if (read == -1) + if (read < 0) { if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) /* No worries */ @@ -360,7 +360,7 @@ return; } - if (read == -1) + if (read < 0) { if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) /* No worries */ @@ -422,7 +422,7 @@ wrotelen = send(conn->fd, conn->buffer_outgoing->outptr, writelen, 0); if (wrotelen <= 0) { - if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) + if (wrotelen < 0 && ((errno == EAGAIN) || (errno == EWOULDBLOCK))) /* No worries */ return; @@ -462,7 +462,7 @@ purple_circ_buffer_append(conn->buffer_outgoing, bs->data, bs->len); /* If we haven't already started writing stuff, then start the cycle */ - if ((conn->watcher_outgoing == 0) && (conn->fd != -1)) + if ((conn->watcher_outgoing == 0) && (conn->fd >= 0)) { conn->watcher_outgoing = purple_input_add(conn->fd, PURPLE_INPUT_WRITE, send_cb, conn); @@ -596,7 +596,7 @@ purple_debug_info("oscar", "Accepting connection on listener socket.\n"); conn->fd = accept(conn->listenerfd, &addr, &addrlen); - if (conn->fd == -1) + if (conn->fd < 0) { if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) /* No connection yet--no worries */ @@ -640,7 +640,7 @@ conn = data; conn->listen_data = NULL; - if (listenerfd == -1) + if (listenerfd < 0) { /* Could not open listener socket */ peer_connection_trynext(conn);
--- a/libpurple/protocols/oscar/peer_proxy.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/oscar/peer_proxy.c Mon Jun 18 01:48:35 2007 +0000 @@ -224,7 +224,7 @@ } /* If there was an error then close the connection */ - if (read == -1) + if (read < 0) { if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) /* No worries */ @@ -285,7 +285,8 @@ return; } - if (read == -1) + /* If there was an error then close the connection */ + if (read < 0) { if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) /* No worries */
--- a/libpurple/protocols/oscar/tlv.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/oscar/tlv.c Mon Jun 18 01:48:35 2007 +0000 @@ -18,7 +18,6 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - #include "oscar.h" static aim_tlv_t * @@ -35,17 +34,57 @@ } static void -freetlv(aim_tlv_t **oldtlv) +freetlv(aim_tlv_t *oldtlv) { + g_free(oldtlv->value); + g_free(oldtlv); +} - if (!oldtlv || !*oldtlv) - return; +static GSList * +aim_tlv_read(GSList *list, ByteStream *bs) +{ + guint16 type, length; + aim_tlv_t *tlv; + + type = byte_stream_get16(bs); + length = byte_stream_get16(bs); - g_free((*oldtlv)->value); - g_free(*oldtlv); - *oldtlv = NULL; +#if 0 + /* + * This code hasn't been needed in years. It's been commented + * out since 2003, at the latest. It seems likely that it was + * just a bug in their server code that has since been fixed. + * In any case, here's the orignal comment, kept for historical + * purposes: + * + * Okay, so now AOL has decided that any TLV of + * type 0x0013 can only be two bytes, despite + * what the actual given length is. So here + * we dump any invalid TLVs of that sort. Hopefully + * there's no special cases to this special case. + * - mid (30jun2000) + */ + if ((type == 0x0013) && (length != 0x0002)) { + length = 0x0002; + return list; + } +#endif + if (length > byte_stream_empty(bs)) { + aim_tlvlist_free(list); + return NULL; + } - return; + tlv = createtlv(type, length, NULL); + if (tlv->length > 0) { + tlv->value = byte_stream_getraw(bs, length); + if (!tlv->value) { + freetlv(tlv); + aim_tlvlist_free(list); + return NULL; + } + } + + return g_slist_prepend(list, tlv); } /** @@ -56,7 +95,7 @@ * routines. When done with a TLV chain, aim_tlvlist_free() should * be called to free the dynamic substructures. * - * XXX There should be a flag setable here to have the tlvlist contain + * TODO: There should be a flag setable here to have the tlvlist contain * bstream references, so that at least the ->value portion of each * element doesn't need to be malloc/memcpy'd. This could prove to be * just as efficient as the in-place TLV parsing used in a couple places @@ -65,56 +104,17 @@ * @param bs Input bstream * @return Return the TLV chain read */ -aim_tlvlist_t *aim_tlvlist_read(ByteStream *bs) +GSList *aim_tlvlist_read(ByteStream *bs) { - aim_tlvlist_t *list = NULL, *cur; + GSList *list = NULL; while (byte_stream_empty(bs) > 0) { - guint16 type, length; - - type = byte_stream_get16(bs); - length = byte_stream_get16(bs); - -#if 0 /* temporarily disabled until I know if they're still doing it or not */ - /* - * Okay, so now AOL has decided that any TLV of - * type 0x0013 can only be two bytes, despite - * what the actual given length is. So here - * we dump any invalid TLVs of that sort. Hopefully - * there's no special cases to this special case. - * - mid (30jun2000) - */ - if ((type == 0x0013) && (length != 0x0002)) - length = 0x0002; -#else - if (0) - ; -#endif - else { - - if (length > byte_stream_empty(bs)) { - aim_tlvlist_free(&list); - return NULL; - } - - cur = g_new0(aim_tlvlist_t, 1); - cur->tlv = createtlv(type, length, NULL); - if (cur->tlv->length > 0) { - cur->tlv->value = byte_stream_getraw(bs, length); - if (!cur->tlv->value) { - freetlv(&cur->tlv); - g_free(cur); - aim_tlvlist_free(&list); - return NULL; - } - } - - cur->next = list; - list = cur; - } + list = aim_tlv_read(list, bs); + if (list == NULL) + return NULL; } - return list; + return g_slist_reverse(list); } /** @@ -125,7 +125,7 @@ * routines. When done with a TLV chain, aim_tlvlist_free() should * be called to free the dynamic substructures. * - * XXX There should be a flag setable here to have the tlvlist contain + * TODO: There should be a flag setable here to have the tlvlist contain * bstream references, so that at least the ->value portion of each * element doesn't need to be malloc/memcpy'd. This could prove to be * just as efficient as the in-place TLV parsing used in a couple places @@ -138,40 +138,18 @@ * preceded by the number of TLVs. So you can limit that with this. * @return Return the TLV chain read */ -aim_tlvlist_t *aim_tlvlist_readnum(ByteStream *bs, guint16 num) +GSList *aim_tlvlist_readnum(ByteStream *bs, guint16 num) { - aim_tlvlist_t *list = NULL, *cur; + GSList *list = NULL; while ((byte_stream_empty(bs) > 0) && (num != 0)) { - guint16 type, length; - - type = byte_stream_get16(bs); - length = byte_stream_get16(bs); - - if (length > byte_stream_empty(bs)) { - aim_tlvlist_free(&list); + list = aim_tlv_read(list, bs); + if (list == NULL) return NULL; - } - - cur = g_new0(aim_tlvlist_t, 1); - cur->tlv = createtlv(type, length, NULL); - if (cur->tlv->length > 0) { - cur->tlv->value = byte_stream_getraw(bs, length); - if (!cur->tlv->value) { - freetlv(&cur->tlv); - g_free(cur); - aim_tlvlist_free(&list); - return NULL; - } - } - - if (num > 0) - num--; - cur->next = list; - list = cur; + num--; } - return list; + return g_slist_reverse(list); } /** @@ -182,7 +160,7 @@ * routines. When done with a TLV chain, aim_tlvlist_free() should * be called to free the dynamic substructures. * - * XXX There should be a flag setable here to have the tlvlist contain + * TODO: There should be a flag setable here to have the tlvlist contain * bstream references, so that at least the ->value portion of each * element doesn't need to be malloc/memcpy'd. This could prove to be * just as efficient as the in-place TLV parsing used in a couple places @@ -195,39 +173,19 @@ * preceded by the length of the TLVs. So you can limit that with this. * @return Return the TLV chain read */ -aim_tlvlist_t *aim_tlvlist_readlen(ByteStream *bs, guint16 len) +GSList *aim_tlvlist_readlen(ByteStream *bs, guint16 len) { - aim_tlvlist_t *list = NULL, *cur; + GSList *list = NULL; while ((byte_stream_empty(bs) > 0) && (len > 0)) { - guint16 type, length; - - type = byte_stream_get16(bs); - length = byte_stream_get16(bs); - - if (length > byte_stream_empty(bs)) { - aim_tlvlist_free(&list); + list = aim_tlv_read(list, bs); + if (list == NULL) return NULL; - } - cur = g_new0(aim_tlvlist_t, 1); - cur->tlv = createtlv(type, length, NULL); - if (cur->tlv->length > 0) { - cur->tlv->value = byte_stream_getraw(bs, length); - if (!cur->tlv->value) { - freetlv(&cur->tlv); - g_free(cur); - aim_tlvlist_free(&list); - return NULL; - } - } - - len -= aim_tlvlist_size(&cur); - cur->next = list; - list = cur; + len -= 2 + 2 + ((aim_tlv_t *)list->data)->length; } - return list; + return g_slist_reverse(list); } /** @@ -237,12 +195,14 @@ * @param orig The TLV chain you want to make a copy of. * @return A newly allocated TLV chain. */ -aim_tlvlist_t *aim_tlvlist_copy(aim_tlvlist_t *orig) +GSList *aim_tlvlist_copy(GSList *orig) { - aim_tlvlist_t *new = NULL; + GSList *new = NULL; + aim_tlv_t *tlv; - while (orig) { - aim_tlvlist_add_raw(&new, orig->tlv->type, orig->tlv->length, orig->tlv->value); + while (orig != NULL) { + tlv = orig->data; + aim_tlvlist_add_raw(&new, tlv->type, tlv->length, tlv->value); orig = orig->next; } @@ -257,15 +217,15 @@ * @param two The other TLV chain to compare. * @return Return 0 if the lists are the same, return 1 if they are different. */ -int aim_tlvlist_cmp(aim_tlvlist_t *one, aim_tlvlist_t *two) +int aim_tlvlist_cmp(GSList *one, GSList *two) { ByteStream bs1, bs2; - if (aim_tlvlist_size(&one) != aim_tlvlist_size(&two)) + if (aim_tlvlist_size(one) != aim_tlvlist_size(two)) return 1; - byte_stream_new(&bs1, aim_tlvlist_size(&one)); - byte_stream_new(&bs2, aim_tlvlist_size(&two)); + byte_stream_new(&bs1, aim_tlvlist_size(one)); + byte_stream_new(&bs2, aim_tlvlist_size(two)); aim_tlvlist_write(&bs1, &one); aim_tlvlist_write(&bs2, &two); @@ -291,26 +251,13 @@ * * @param list Chain to be freed */ -void aim_tlvlist_free(aim_tlvlist_t **list) +void aim_tlvlist_free(GSList *list) { - aim_tlvlist_t *cur; - - if (!list || !*list) - return; - - for (cur = *list; cur; ) { - aim_tlvlist_t *tmp; - - freetlv(&cur->tlv); - - tmp = cur->next; - g_free(cur); - cur = tmp; + while (list != NULL) + { + freetlv(list->data); + list = g_slist_delete_link(list, list); } - - list = NULL; - - return; } /** @@ -319,15 +266,15 @@ * @param list Chain to be counted. * @return The number of TLVs stored in the passed chain. */ -int aim_tlvlist_count(aim_tlvlist_t **list) +int aim_tlvlist_count(GSList *list) { - aim_tlvlist_t *cur; + GSList *cur; int count; - if (!list || !*list) + if (list == NULL) return 0; - for (cur = *list, count = 0; cur; cur = cur->next) + for (cur = list, count = 0; cur; cur = cur->next) count++; return count; @@ -340,16 +287,16 @@ * @return The number of bytes that would be needed to * write the passed TLV chain to a data buffer. */ -int aim_tlvlist_size(aim_tlvlist_t **list) +int aim_tlvlist_size(GSList *list) { - aim_tlvlist_t *cur; + GSList *cur; int size; - if (!list || !*list) + if (list == NULL) return 0; - for (cur = *list, size = 0; cur; cur = cur->next) - size += (4 + cur->tlv->length); + for (cur = list, size = 0; cur; cur = cur->next) + size += (4 + ((aim_tlv_t *)cur->data)->length); return size; } @@ -364,27 +311,20 @@ * @param value String to add. * @return The size of the value added. */ -int aim_tlvlist_add_raw(aim_tlvlist_t **list, const guint16 type, const guint16 length, const guint8 *value) +int aim_tlvlist_add_raw(GSList **list, const guint16 type, const guint16 length, const guint8 *value) { - aim_tlvlist_t *newtlv, *cur; + aim_tlv_t *tlv; if (list == NULL) return 0; - newtlv = g_new0(aim_tlvlist_t, 1); - newtlv->tlv = createtlv(type, length, NULL); - if (newtlv->tlv->length > 0) - newtlv->tlv->value = g_memdup(value, length); + tlv = createtlv(type, length, NULL); + if (tlv->length > 0) + tlv->value = g_memdup(value, length); - if (!*list) - *list = newtlv; - else { - for(cur = *list; cur->next; cur = cur->next) - ; - cur->next = newtlv; - } + *list = g_slist_append(*list, tlv); - return newtlv->tlv->length; + return tlv->length; } /** @@ -395,7 +335,7 @@ * @param value Value to add. * @return The size of the value added. */ -int aim_tlvlist_add_8(aim_tlvlist_t **list, const guint16 type, const guint8 value) +int aim_tlvlist_add_8(GSList **list, const guint16 type, const guint8 value) { guint8 v8[1]; @@ -412,7 +352,7 @@ * @param value Value to add. * @return The size of the value added. */ -int aim_tlvlist_add_16(aim_tlvlist_t **list, const guint16 type, const guint16 value) +int aim_tlvlist_add_16(GSList **list, const guint16 type, const guint16 value) { guint8 v16[2]; @@ -429,7 +369,7 @@ * @param value Value to add. * @return The size of the value added. */ -int aim_tlvlist_add_32(aim_tlvlist_t **list, const guint16 type, const guint32 value) +int aim_tlvlist_add_32(GSList **list, const guint16 type, const guint32 value) { guint8 v32[4]; @@ -446,7 +386,7 @@ * @param value Value to add. * @return The size of the value added. */ -int aim_tlvlist_add_str(aim_tlvlist_t **list, const guint16 type, const char *value) +int aim_tlvlist_add_str(GSList **list, const guint16 type, const char *value) { return aim_tlvlist_add_raw(list, type, strlen(value), (guint8 *)value); } @@ -467,12 +407,12 @@ * @param caps Bitfield of capability flags to send * @return The size of the value added. */ -int aim_tlvlist_add_caps(aim_tlvlist_t **list, const guint16 type, const guint32 caps) +int aim_tlvlist_add_caps(GSList **list, const guint16 type, const guint32 caps) { - guint8 buf[16*16]; /* XXX icky fixed length buffer */ + guint8 buf[256]; /* TODO: Don't use a fixed length buffer */ ByteStream bs; - if (!caps) + if (caps == 0) return 0; /* nothing there anyway */ byte_stream_init(&bs, buf, sizeof(buf)); @@ -489,9 +429,9 @@ * @param type TLV type to add. * @return The size of the value added. */ -int aim_tlvlist_add_userinfo(aim_tlvlist_t **list, guint16 type, aim_userinfo_t *userinfo) +int aim_tlvlist_add_userinfo(GSList **list, guint16 type, aim_userinfo_t *userinfo) { - guint8 buf[1024]; /* bleh */ + guint8 buf[1024]; /* TODO: Don't use a fixed length buffer */ ByteStream bs; byte_stream_init(&bs, buf, sizeof(buf)); @@ -510,7 +450,7 @@ * @param instance The instance. * @return The size of the value added. */ -int aim_tlvlist_add_chatroom(aim_tlvlist_t **list, guint16 type, guint16 exchange, const char *roomname, guint16 instance) +int aim_tlvlist_add_chatroom(GSList **list, guint16 type, guint16 exchange, const char *roomname, guint16 instance) { int len; ByteStream bs; @@ -536,7 +476,7 @@ * @param type TLV type to add. * @return The size of the value added. */ -int aim_tlvlist_add_noval(aim_tlvlist_t **list, const guint16 type) +int aim_tlvlist_add_noval(GSList **list, const guint16 type) { return aim_tlvlist_add_raw(list, type, 0, NULL); } @@ -546,7 +486,7 @@ * it is written using this. Or rather, it can be, but updates won't be * made to this. * - * XXX should probably support sublists for real. + * TODO: Should probably support sublists for real. * * This is so neat. * @@ -557,19 +497,19 @@ * 0 is returned if there was an error or if the destination * TLV chain has length 0. */ -int aim_tlvlist_add_frozentlvlist(aim_tlvlist_t **list, guint16 type, aim_tlvlist_t **tl) +int aim_tlvlist_add_frozentlvlist(GSList **list, guint16 type, GSList **tlvlist) { int buflen; ByteStream bs; - buflen = aim_tlvlist_size(tl); + buflen = aim_tlvlist_size(*tlvlist); if (buflen <= 0) return 0; byte_stream_new(&bs, buflen); - aim_tlvlist_write(&bs, tl); + aim_tlvlist_write(&bs, tlvlist); aim_tlvlist_add_raw(list, type, byte_stream_curpos(&bs), bs.data); @@ -589,25 +529,33 @@ * @param value String to add. * @return The length of the TLV. */ -int aim_tlvlist_replace_raw(aim_tlvlist_t **list, const guint16 type, const guint16 length, const guint8 *value) +int aim_tlvlist_replace_raw(GSList **list, const guint16 type, const guint16 length, const guint8 *value) { - aim_tlvlist_t *cur; + GSList *cur; + aim_tlv_t *tlv; if (list == NULL) return 0; - for (cur = *list; ((cur != NULL) && (cur->tlv->type != type)); cur = cur->next); + for (cur = *list; cur != NULL; cur = cur->next) + { + tlv = cur->data; + if (tlv->type == type) + break; + } + if (cur == NULL) + /* TLV does not exist, so add a new one */ return aim_tlvlist_add_raw(list, type, length, value); - g_free(cur->tlv->value); - cur->tlv->length = length; - if (cur->tlv->length > 0) { - cur->tlv->value = g_memdup(value, length); + g_free(tlv->value); + tlv->length = length; + if (tlv->length > 0) { + tlv->value = g_memdup(value, length); } else - cur->tlv->value = NULL; + tlv->value = NULL; - return cur->tlv->length; + return tlv->length; } /** @@ -620,7 +568,7 @@ * @param str String to add. * @return The length of the TLV. */ -int aim_tlvlist_replace_str(aim_tlvlist_t **list, const guint16 type, const char *str) +int aim_tlvlist_replace_str(GSList **list, const guint16 type, const char *str) { return aim_tlvlist_replace_raw(list, type, strlen(str), (const guchar *)str); } @@ -634,7 +582,7 @@ * @param type TLV type. * @return The length of the TLV. */ -int aim_tlvlist_replace_noval(aim_tlvlist_t **list, const guint16 type) +int aim_tlvlist_replace_noval(GSList **list, const guint16 type) { return aim_tlvlist_replace_raw(list, type, 0, NULL); } @@ -649,7 +597,7 @@ * @param value 8 bit value to add. * @return The length of the TLV. */ -int aim_tlvlist_replace_8(aim_tlvlist_t **list, const guint16 type, const guint8 value) +int aim_tlvlist_replace_8(GSList **list, const guint16 type, const guint8 value) { guint8 v8[1]; @@ -668,7 +616,7 @@ * @param value 32 bit value to add. * @return The length of the TLV. */ -int aim_tlvlist_replace_32(aim_tlvlist_t **list, const guint16 type, const guint32 value) +int aim_tlvlist_replace_32(GSList **list, const guint16 type, const guint32 value) { guint8 v32[4]; @@ -678,36 +626,36 @@ } /** - * Remove a TLV of a given type. If you attempt to remove a TLV that - * does not exist, nothing happens. + * Remove all TLVs of a given type. If you attempt to remove a TLV + * that does not exist, nothing happens. * * @param list Desination chain (%NULL pointer if empty). * @param type TLV type. */ -void aim_tlvlist_remove(aim_tlvlist_t **list, const guint16 type) +void aim_tlvlist_remove(GSList **list, const guint16 type) { - aim_tlvlist_t *del; + GSList *cur, *next; + aim_tlv_t *tlv; - if (!list || !(*list)) + if (list == NULL || *list == NULL) return; - /* Remove the item from the list */ - if ((*list)->tlv->type == type) { - del = *list; - *list = (*list)->next; - } else { - aim_tlvlist_t *cur; - for (cur=*list; (cur->next && (cur->next->tlv->type!=type)); cur=cur->next); - if (!cur->next) - return; - del = cur->next; - cur->next = del->next; + cur = *list; + while (cur != NULL) + { + tlv = cur->data; + next = cur->next; + + if (tlv->type == type) + { + /* Delete this TLV */ + *list = g_slist_delete_link(*list, cur); + g_free(tlv->value); + g_free(tlv); + } + + cur = next; } - - /* Free the removed item */ - g_free(del->tlv->value); - g_free(del->tlv); - g_free(del); } /** @@ -718,32 +666,34 @@ * aim_tlvlist_free() must still be called to free up the memory used * by the chain structures. * - * XXX clean this up, make better use of bstreams + * TODO: Clean this up, make better use of bstreams * * @param bs Input bstream * @param list Source TLV chain * @return Return 0 if the destination bstream is too small. */ -int aim_tlvlist_write(ByteStream *bs, aim_tlvlist_t **list) +int aim_tlvlist_write(ByteStream *bs, GSList **list) { int goodbuflen; - aim_tlvlist_t *cur; + GSList *cur; + aim_tlv_t *tlv; /* do an initial run to test total length */ - goodbuflen = aim_tlvlist_size(list); + goodbuflen = aim_tlvlist_size(*list); if (goodbuflen > byte_stream_empty(bs)) return 0; /* not enough buffer */ /* do the real write-out */ for (cur = *list; cur; cur = cur->next) { - byte_stream_put16(bs, cur->tlv->type); - byte_stream_put16(bs, cur->tlv->length); - if (cur->tlv->length) - byte_stream_putraw(bs, cur->tlv->value, cur->tlv->length); + tlv = cur->data; + byte_stream_put16(bs, tlv->type); + byte_stream_put16(bs, tlv->length); + if (tlv->length > 0) + byte_stream_putraw(bs, tlv->value, tlv->length); } - return 1; /* XXX this is a nonsensical return */ + return 1; /* TODO: This is a nonsensical return */ } @@ -760,17 +710,19 @@ * @param nth Index of TLV of type to get. * @return The TLV you were looking for, or NULL if one could not be found. */ -aim_tlv_t *aim_tlv_gettlv(aim_tlvlist_t *list, const guint16 type, const int nth) +aim_tlv_t *aim_tlv_gettlv(GSList *list, const guint16 type, const int nth) { - aim_tlvlist_t *cur; + GSList *cur; + aim_tlv_t *tlv; int i; - for (cur = list, i = 0; cur; cur = cur->next) { - if (cur && cur->tlv) { - if (cur->tlv->type == type) + for (cur = list, i = 0; cur != NULL; cur = cur->next) { + tlv = cur->data; + if (tlv != NULL) { /* TODO: This NULL check shouldn't be needed */ + if (tlv->type == type) i++; if (i >= nth) - return cur->tlv; + return tlv; } } @@ -786,21 +738,15 @@ * @return The length of the data in this TLV, or -1 if the TLV could not be * found. Unless -1 is returned, this value will be 2 bytes. */ -int aim_tlv_getlength(aim_tlvlist_t *list, const guint16 type, const int nth) +int aim_tlv_getlength(GSList *list, const guint16 type, const int nth) { - aim_tlvlist_t *cur; - int i; + aim_tlv_t *tlv; - for (cur = list, i = 0; cur; cur = cur->next) { - if (cur && cur->tlv) { - if (cur->tlv->type == type) - i++; - if (i >= nth) - return cur->tlv->length; - } - } + tlv = aim_tlv_gettlv(list, type, nth); + if (tlv == NULL) + return -1; - return -1; + return tlv->length; } char * @@ -825,11 +771,12 @@ * not be found. This is a dynamic buffer and must be freed by the * caller. */ -char *aim_tlv_getstr(aim_tlvlist_t *list, const guint16 type, const int nth) +char *aim_tlv_getstr(GSList *list, const guint16 type, const int nth) { aim_tlv_t *tlv; - if (!(tlv = aim_tlv_gettlv(list, type, nth))) + tlv = aim_tlv_gettlv(list, type, nth); + if (tlv == NULL) return NULL; return aim_tlv_getvalue_as_string(tlv); @@ -845,12 +792,14 @@ * @return The value the TLV you were looking for, or 0 if one could * not be found. */ -guint8 aim_tlv_get8(aim_tlvlist_t *list, const guint16 type, const int nth) +guint8 aim_tlv_get8(GSList *list, const guint16 type, const int nth) { aim_tlv_t *tlv; - if (!(tlv = aim_tlv_gettlv(list, type, nth))) + tlv = aim_tlv_gettlv(list, type, nth); + if (tlv == NULL) return 0; /* erm */ + return aimutil_get8(tlv->value); } @@ -864,12 +813,14 @@ * @return The value the TLV you were looking for, or 0 if one could * not be found. */ -guint16 aim_tlv_get16(aim_tlvlist_t *list, const guint16 type, const int nth) +guint16 aim_tlv_get16(GSList *list, const guint16 type, const int nth) { aim_tlv_t *tlv; - if (!(tlv = aim_tlv_gettlv(list, type, nth))) + tlv = aim_tlv_gettlv(list, type, nth); + if (tlv == NULL) return 0; /* erm */ + return aimutil_get16(tlv->value); } @@ -883,11 +834,13 @@ * @return The value the TLV you were looking for, or 0 if one could * not be found. */ -guint32 aim_tlv_get32(aim_tlvlist_t *list, const guint16 type, const int nth) +guint32 aim_tlv_get32(GSList *list, const guint16 type, const int nth) { aim_tlv_t *tlv; - if (!(tlv = aim_tlv_gettlv(list, type, nth))) + tlv = aim_tlv_gettlv(list, type, nth); + if (tlv == NULL) return 0; /* erm */ + return aimutil_get32(tlv->value); }
--- a/libpurple/protocols/qq/AUTHORS Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/qq/AUTHORS Mon Jun 18 01:48:35 2007 +0000 @@ -1,7 +1,7 @@ Code Contributors ===== puzzlebird : original author -gfhuang : patches for gaim 2.0.0beta2, maintainer +gfhuang : patches for libpurple 2.0.0beta2, maintainer henryouly : file transfer, udp sock5 proxy and qq_show, maintainer hzhr : maintainer joymarquis : maintainer @@ -10,7 +10,7 @@ yyw : improved performance on PPC linux lvxiang : provided ip to location original code csyfek : faces -markhuetsch : OpenQ merge into gaim, maintainer 2006-2007 +markhuetsch : OpenQ merge into libpurple, maintainer 2006-2007 Acknowledgement =====
--- a/libpurple/protocols/qq/header_info.h Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/qq/header_info.h Mon Jun 18 01:48:35 2007 +0000 @@ -33,7 +33,7 @@ #define QQ_PACKET_TAG 0x02 /* all QQ text packets starts with it */ #define QQ_PACKET_TAIL 0x03 /* all QQ text packets end with it */ -#define QQ_CLIENT 0x0f15 +#define QQ_CLIENT 0x0E1B /* list of known QQ commands */ enum {
--- a/libpurple/protocols/silc/README Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/silc/README Mon Jun 18 01:48:35 2007 +0000 @@ -2,19 +2,19 @@ ================== This is the Purple protocol plugin of the protocol called Secure Internet -Live Conferencing (SILC). The implementation will use the SILC Toolkit, -freely available from the http://silcnet.org/ site, for the actual SILC +Live Conferencing (SILC). The implementation will use the SILC Toolkit, +freely available from the http://silcnet.org/ site, for the actual SILC protocol implementation. -To include SILC into Purple, one needs to first compile and install +To include SILC into Purple, one needs to first compile and install the SILC Toolkit. It is done as follows: - ./configure --enable-shared + ./configure make make install -This will compile shared libraries of the SILC Toolkit. If the --prefix -is not given to ./configure, the binaries are installed into the +This will compile shared libraries of the SILC Toolkit. If the --prefix +is not given to ./configure, the binaries are installed into the /usr/local/silc directory. Once the Toolkit is installed one needs to tell Purple's ./configure
--- a/libpurple/protocols/silc/TODO Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/silc/TODO Mon Jun 18 01:48:35 2007 +0000 @@ -1,14 +1,6 @@ Features TODO (maybe) ===================== -Sending images - - Sending images to channel too, if libpurple allows it. - Preferences - Add joined channels to buddy list automatically (during session) - - Add joined channels to buddy list automatically permanently - -Buddy icon - - After SILC Toolkit 1.0.2 buddy icon support can be added - (SILC_ATTERIBUTE_USER_ICON).
--- a/libpurple/protocols/silc/buddy.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/silc/buddy.c Mon Jun 18 01:48:35 2007 +0000 @@ -4,7 +4,7 @@ Author: Pekka Riikonen <priikone@silcnet.org> - Copyright (C) 2004 Pekka Riikonen + Copyright (C) 2004 - 2007 Pekka Riikonen 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 @@ -17,7 +17,7 @@ */ -#include "silcincludes.h" +#include "silc.h" #include "silcclient.h" #include "silcpurple.h" #include "wb.h" @@ -29,7 +29,7 @@ static void silcpurple_buddy_keyagr_do(PurpleConnection *gc, const char *name, - gboolean force_local); + gboolean force_local); typedef struct { char *nick; @@ -38,10 +38,10 @@ static void silcpurple_buddy_keyagr_resolved(SilcClient client, - SilcClientConnection conn, - SilcClientEntry *clients, - SilcUInt32 clients_count, - void *context) + SilcClientConnection conn, + SilcStatus status, + SilcDList clients, + void *context) { PurpleConnection *gc = client->application; SilcPurpleResolve r = context; @@ -62,21 +62,16 @@ silc_free(r); } -typedef struct { - gboolean responder; -} *SilcPurpleKeyAgr; - static void silcpurple_buddy_keyagr_cb(SilcClient client, - SilcClientConnection conn, - SilcClientEntry client_entry, - SilcKeyAgreementStatus status, - SilcSKEKeyMaterial *key, - void *context) + SilcClientConnection conn, + SilcClientEntry client_entry, + SilcKeyAgreementStatus status, + SilcSKEKeyMaterial key, + void *context) { PurpleConnection *gc = client->application; SilcPurple sg = gc->proto_data; - SilcPurpleKeyAgr a = context; if (!sg->conn) return; @@ -90,13 +85,13 @@ /* Set the private key for this client */ silc_client_del_private_message_key(client, conn, client_entry); silc_client_add_private_message_key_ske(client, conn, client_entry, - NULL, NULL, key, a->responder); + NULL, NULL, key); silc_ske_free_key_material(key); - + /* Open IM window */ convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, - client_entry->nickname, sg->account); + client_entry->nickname, sg->account); if (convo) { /* we don't have windows in the core anymore...but we may want to * provide some method for asking the UI to show the window @@ -104,7 +99,7 @@ */ } else { convo = purple_conversation_new(PURPLE_CONV_TYPE_IM, sg->account, - client_entry->nickname); + client_entry->nickname); } g_snprintf(tmp, sizeof(tmp), "%s [private key]", client_entry->nickname); purple_conversation_set_title(convo, tmp); @@ -113,7 +108,7 @@ case SILC_KEY_AGREEMENT_ERROR: purple_notify_error(gc, _("Key Agreement"), - _("Error occurred during key agreement"), NULL); + _("Error occurred during key agreement"), NULL); break; case SILC_KEY_AGREEMENT_FAILURE: @@ -122,53 +117,48 @@ case SILC_KEY_AGREEMENT_TIMEOUT: purple_notify_error(gc, _("Key Agreement"), - _("Timeout during key agreement"), NULL); + _("Timeout during key agreement"), NULL); break; case SILC_KEY_AGREEMENT_ABORTED: purple_notify_error(gc, _("Key Agreement"), - _("Key agreement was aborted"), NULL); + _("Key agreement was aborted"), NULL); break; case SILC_KEY_AGREEMENT_ALREADY_STARTED: purple_notify_error(gc, _("Key Agreement"), - _("Key agreement is already started"), NULL); + _("Key agreement is already started"), NULL); break; case SILC_KEY_AGREEMENT_SELF_DENIED: purple_notify_error(gc, _("Key Agreement"), - _("Key agreement cannot be started with yourself"), - NULL); + _("Key agreement cannot be started with yourself"), + NULL); break; default: break; } - - silc_free(a); } static void silcpurple_buddy_keyagr_do(PurpleConnection *gc, const char *name, - gboolean force_local) + gboolean force_local) { SilcPurple sg = gc->proto_data; - SilcClientEntry *clients; - SilcUInt32 clients_count; + SilcDList clients; + SilcClientEntry client_entry; + SilcClientConnectionParams params; char *local_ip = NULL, *remote_ip = NULL; gboolean local = TRUE; - char *nickname; - SilcPurpleKeyAgr a; + SilcSocket sock; if (!sg->conn || !name) return; - if (!silc_parse_userfqdn(name, &nickname, NULL)) - return; - /* Find client entry */ - clients = silc_client_get_clients_local(sg->client, sg->conn, nickname, name, - &clients_count); + clients = silc_client_get_clients_local(sg->client, sg->conn, name, + FALSE); if (!clients) { /* Resolve unknown user */ SilcPurpleResolve r = silc_calloc(1, sizeof(*r)); @@ -176,12 +166,14 @@ return; r->nick = g_strdup(name); r->gc = gc; - silc_client_get_clients(sg->client, sg->conn, nickname, NULL, + silc_client_get_clients(sg->client, sg->conn, name, NULL, silcpurple_buddy_keyagr_resolved, r); - silc_free(nickname); return; } + silc_socket_stream_get_info(silc_packet_stream_get_stream(sg->conn->stream), + &sock, NULL, NULL, NULL); + /* Resolve the local IP from the outgoing socket connection. We resolve it to check whether we have a private range IP address or public IP address. If we have public then we will assume that we are not behind @@ -196,14 +188,14 @@ Naturally this algorithm does not always get things right. */ - if (silc_net_check_local_by_sock(sg->conn->sock->sock, NULL, &local_ip)) { + if (silc_net_check_local_by_sock(sock, NULL, &local_ip)) { /* Check if the IP is private */ if (!force_local && silcpurple_ip_is_private(local_ip)) { local = FALSE; /* Local IP is private, resolve the remote server IP to see whether we are talking to Internet or just on LAN. */ - if (silc_net_check_host_by_sock(sg->conn->sock->sock, NULL, + if (silc_net_check_host_by_sock(sock, NULL, &remote_ip)) if (silcpurple_ip_is_private(remote_ip)) /* We assume we are in LAN. Let's provide @@ -218,19 +210,24 @@ if (local && !local_ip) local_ip = silc_net_localip(); - a = silc_calloc(1, sizeof(*a)); - if (!a) - return; - a->responder = local; + silc_dlist_start(clients); + client_entry = silc_dlist_get(clients); + + memset(¶ms, 0, sizeof(params)); + params.timeout_secs = 60; + if (local) + /* Provide connection point */ + params.local_ip = local_ip; /* Send the key agreement request */ - silc_client_send_key_agreement(sg->client, sg->conn, clients[0], - local ? local_ip : NULL, NULL, 0, 60, - silcpurple_buddy_keyagr_cb, a); + silc_client_send_key_agreement(sg->client, sg->conn, client_entry, + ¶ms, sg->public_key, + sg->private_key, + silcpurple_buddy_keyagr_cb, NULL); silc_free(local_ip); silc_free(remote_ip); - silc_free(clients); + silc_client_list_free(sg->client, sg->conn, clients); } typedef struct { @@ -244,8 +241,8 @@ static void silcpurple_buddy_keyagr_request_cb(SilcPurpleKeyAgrAsk a, gint id) { - SilcPurpleKeyAgr ai; SilcClientEntry client_entry; + SilcClientConnectionParams params; if (id != 1) goto out; @@ -255,26 +252,27 @@ &a->client_id); if (!client_entry) { purple_notify_error(a->client->application, _("Key Agreement"), - _("The remote user is not present in the network any more"), - NULL); + _("The remote user is not present in the network any more"), + NULL); goto out; } /* If the hostname was provided by the requestor perform the key agreement now. Otherwise, we will send him a request to connect to us. */ if (a->hostname) { - ai = silc_calloc(1, sizeof(*ai)); - if (!ai) - goto out; - ai->responder = FALSE; - silc_client_perform_key_agreement(a->client, a->conn, client_entry, + memset(¶ms, 0, sizeof(params)); + params.timeout_secs = 60; + silc_client_perform_key_agreement(a->client, a->conn, + client_entry, ¶ms, + a->conn->public_key, + a->conn->private_key, a->hostname, a->port, - silcpurple_buddy_keyagr_cb, ai); + silcpurple_buddy_keyagr_cb, NULL); } else { /* Send request. Force us as the point of connection since requestor did not provide the point of connection. */ silcpurple_buddy_keyagr_do(a->client->application, - client_entry->nickname, TRUE); + client_entry->nickname, TRUE); } out: @@ -283,14 +281,19 @@ } void silcpurple_buddy_keyagr_request(SilcClient client, - SilcClientConnection conn, - SilcClientEntry client_entry, - const char *hostname, SilcUInt16 port) + SilcClientConnection conn, + SilcClientEntry client_entry, + const char *hostname, SilcUInt16 port, + SilcUInt16 protocol) { char tmp[128], tmp2[128]; SilcPurpleKeyAgrAsk a; PurpleConnection *gc = client->application; + /* For now Pidgin don't support UDP key agreement */ + if (protocol == 1) + return; + g_snprintf(tmp, sizeof(tmp), _("Key agreement request received from %s. Would you like to " "perform the key agreement?"), client_entry->nickname); @@ -304,15 +307,15 @@ return; a->client = client; a->conn = conn; - a->client_id = *client_entry->id; + a->client_id = client_entry->id; if (hostname) a->hostname = strdup(hostname); a->port = port; purple_request_action(client->application, _("Key Agreement Request"), tmp, - hostname ? tmp2 : NULL, 1, gc->account, client_entry->nickname, - NULL, a, 2, _("Yes"), G_CALLBACK(silcpurple_buddy_keyagr_request_cb), - _("No"), G_CALLBACK(silcpurple_buddy_keyagr_request_cb)); + hostname ? tmp2 : NULL, 1, gc->account, client_entry->nickname, + NULL, a, 2, _("Yes"), G_CALLBACK(silcpurple_buddy_keyagr_request_cb), + _("No"), G_CALLBACK(silcpurple_buddy_keyagr_request_cb)); } static void @@ -333,9 +336,7 @@ PurpleBuddy *b; PurpleConnection *gc; SilcPurple sg; - char *nickname; - SilcClientEntry *clients; - SilcUInt32 clients_count; + SilcDList clients; g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node)); @@ -343,23 +344,16 @@ gc = purple_account_get_connection(b->account); sg = gc->proto_data; - if (!silc_parse_userfqdn(b->name, &nickname, NULL)) - return; - /* Find client entry */ clients = silc_client_get_clients_local(sg->client, sg->conn, - nickname, b->name, - &clients_count); - if (!clients) { - silc_free(nickname); + b->name, FALSE); + if (!clients) return; - } - clients[0]->prv_resp = FALSE; + silc_dlist_start(clients); silc_client_del_private_message_key(sg->client, sg->conn, - clients[0]); - silc_free(clients); - silc_free(nickname); + silc_dlist_get(clients)); + silc_client_list_free(sg->client, sg->conn, clients); } typedef struct { @@ -386,8 +380,8 @@ &p->client_id); if (!client_entry) { purple_notify_error(p->client->application, _("IM With Password"), - _("The remote user is not present in the network any more"), - NULL); + _("The remote user is not present in the network any more"), + NULL); silc_free(p); return; } @@ -398,21 +392,16 @@ silc_client_add_private_message_key(p->client, p->conn, client_entry, NULL, NULL, (unsigned char *)passphrase, - strlen(passphrase), FALSE, - client_entry->prv_resp); - if (!client_entry->prv_resp) - silc_client_send_private_message_key_request(p->client, - p->conn, - client_entry); + strlen(passphrase)); silc_free(p); } static void silcpurple_buddy_privkey_resolved(SilcClient client, - SilcClientConnection conn, - SilcClientEntry *clients, - SilcUInt32 clients_count, - void *context) + SilcClientConnection conn, + SilcStatus status, + SilcDList clients, + void *context) { char tmp[256]; @@ -434,42 +423,39 @@ silcpurple_buddy_privkey(PurpleConnection *gc, const char *name) { SilcPurple sg = gc->proto_data; - char *nickname; SilcPurplePrivkey p; - SilcClientEntry *clients; - SilcUInt32 clients_count; + SilcDList clients; + SilcClientEntry client_entry; if (!name) return; - if (!silc_parse_userfqdn(name, &nickname, NULL)) - return; /* Find client entry */ clients = silc_client_get_clients_local(sg->client, sg->conn, - nickname, name, - &clients_count); + name, FALSE); if (!clients) { - silc_client_get_clients(sg->client, sg->conn, nickname, NULL, + silc_client_get_clients(sg->client, sg->conn, name, NULL, silcpurple_buddy_privkey_resolved, g_strdup(name)); - silc_free(nickname); return; } + silc_dlist_start(clients); + client_entry = silc_dlist_get(clients); + p = silc_calloc(1, sizeof(*p)); if (!p) return; p->client = sg->client; p->conn = sg->conn; - p->client_id = *clients[0]->id; + p->client_id = client_entry->id; purple_request_input(gc, _("IM With Password"), NULL, _("Set IM Password"), NULL, FALSE, TRUE, NULL, _("OK"), G_CALLBACK(silcpurple_buddy_privkey_cb), _("Cancel"), G_CALLBACK(silcpurple_buddy_privkey_cb), gc->account, NULL, NULL, p); - silc_free(clients); - silc_free(nickname); + silc_client_list_free(sg->client, sg->conn, clients); } static void @@ -498,13 +484,21 @@ static void silcpurple_buddy_getkey(PurpleConnection *gc, const char *name); -static void -silcpurple_buddy_getkey_cb(SilcPurpleBuddyGetkey g, - SilcClientCommandReplyContext cmd) +static SilcBool +silcpurple_buddy_getkey_cb(SilcClient client, SilcClientConnection conn, + SilcCommand command, SilcStatus status, + SilcStatus error, void *context, va_list ap) { SilcClientEntry client_entry; - unsigned char *pk; - SilcUInt32 pk_len; + SilcPurpleBuddyGetkey g = context; + + if (status != SILC_STATUS_OK) { + purple_notify_error(g->client->application, _("Get Public Key"), + _("The remote user is not present in the network any more"), + NULL); + silc_free(g); + return FALSE; + } /* Get the client entry. */ client_entry = silc_client_get_client_by_id(g->client, g->conn, @@ -514,30 +508,28 @@ _("The remote user is not present in the network any more"), NULL); silc_free(g); - return; + return FALSE; } if (!client_entry->public_key) { silc_free(g); - return; + return FALSE; } /* Now verify the public key */ - pk = silc_pkcs_public_key_encode(client_entry->public_key, &pk_len); silcpurple_verify_public_key(g->client, g->conn, client_entry->nickname, - SILC_SOCKET_TYPE_CLIENT, - pk, pk_len, SILC_SKE_PK_TYPE_SILC, - NULL, NULL); - silc_free(pk); + SILC_CONN_CLIENT, client_entry->public_key, + NULL, NULL); silc_free(g); + return TRUE; } static void silcpurple_buddy_getkey_resolved(SilcClient client, - SilcClientConnection conn, - SilcClientEntry *clients, - SilcUInt32 clients_count, - void *context) + SilcClientConnection conn, + SilcStatus status, + SilcDList clients, + void *context) { char tmp[256]; @@ -546,7 +538,7 @@ _("User %s is not present in the network"), (const char *)context); purple_notify_error(client->application, _("Get Public Key"), - _("Cannot fetch the public key"), tmp); + _("Cannot fetch the public key"), tmp); g_free(context); return; } @@ -561,42 +553,38 @@ SilcPurple sg = gc->proto_data; SilcClient client = sg->client; SilcClientConnection conn = sg->conn; - SilcClientEntry *clients; - SilcUInt32 clients_count; + SilcClientEntry client_entry; + SilcDList clients; SilcPurpleBuddyGetkey g; - char *nickname; + SilcUInt16 cmd_ident; if (!name) return; - if (!silc_parse_userfqdn(name, &nickname, NULL)) - return; - /* Find client entry */ - clients = silc_client_get_clients_local(client, conn, nickname, name, - &clients_count); + clients = silc_client_get_clients_local(client, conn, name, FALSE); if (!clients) { - silc_client_get_clients(client, conn, nickname, NULL, + silc_client_get_clients(client, conn, name, NULL, silcpurple_buddy_getkey_resolved, g_strdup(name)); - silc_free(nickname); return; } + silc_dlist_start(clients); + client_entry = silc_dlist_get(clients); + /* Call GETKEY */ g = silc_calloc(1, sizeof(*g)); if (!g) return; g->client = client; g->conn = conn; - g->client_id = *clients[0]->id; - silc_client_command_call(client, conn, NULL, "GETKEY", - clients[0]->nickname, NULL); - silc_client_command_pending(conn, SILC_COMMAND_GETKEY, - conn->cmd_ident, - (SilcCommandCb)silcpurple_buddy_getkey_cb, g); - silc_free(clients); - silc_free(nickname); + g->client_id = client_entry->id; + cmd_ident = silc_client_command_call(client, conn, NULL, "GETKEY", + client_entry->nickname, NULL); + silc_client_command_pending(conn, SILC_COMMAND_GETKEY, cmd_ident, + silcpurple_buddy_getkey_cb, g); + silc_client_list_free(client, conn, clients); } static void @@ -629,8 +617,7 @@ sg = gc->proto_data; pkfile = purple_blist_node_get_string(node, "public-key"); - if (!silc_pkcs_load_public_key(pkfile, &public_key, SILC_PKCS_FILE_PEM) && - !silc_pkcs_load_public_key(pkfile, &public_key, SILC_PKCS_FILE_BIN)) { + if (!silc_pkcs_load_public_key(pkfile, &public_key)) { purple_notify_error(gc, _("Show Public Key"), _("Could not load public key"), NULL); @@ -661,6 +648,7 @@ PurpleBuddy *b; unsigned char *offline_pk; SilcUInt32 offline_pk_len; + SilcPublicKey public_key; unsigned int offline : 1; unsigned int pubkey_search : 1; unsigned int init : 1; @@ -670,10 +658,10 @@ silcpurple_add_buddy_ask_pk_cb(SilcPurpleBuddyRes r, gint id); static void silcpurple_add_buddy_resolved(SilcClient client, - SilcClientConnection conn, - SilcClientEntry *clients, - SilcUInt32 clients_count, - void *context); + SilcClientConnection conn, + SilcStatus status, + SilcDList clients, + void *context); void silcpurple_get_info(PurpleConnection *gc, const char *who) { @@ -735,35 +723,36 @@ g_snprintf(tmp, sizeof(tmp), _("The %s buddy is not trusted"), r->b->name); purple_notify_error(r->client->application, _("Add Buddy"), tmp, - _("You cannot receive buddy notifications until you " - "import his/her public key. You can use the Get Public Key " - "command to get the public key.")); + _("You cannot receive buddy notifications until you " + "import his/her public key. You can use the Get Public Key " + "command to get the public key.")); purple_prpl_got_user_status(purple_buddy_get_account(r->b), purple_buddy_get_name(r->b), SILCPURPLE_STATUS_ID_OFFLINE, NULL); } static void -silcpurple_add_buddy_save(bool success, void *context) +silcpurple_add_buddy_save(SilcBool success, void *context) { SilcPurpleBuddyRes r = context; PurpleBuddy *b = r->b; - SilcClient client = r->client; SilcClientEntry client_entry; SilcAttributePayload attr; SilcAttribute attribute; SilcVCardStruct vcard; - SilcAttributeObjMime message, extension; -#ifdef SILC_ATTRIBUTE_USER_ICON - SilcAttributeObjMime usericon; -#endif + SilcMime message = NULL, extension = NULL; + SilcMime usericon = NULL; SilcAttributeObjPk serverpk, usersign, serversign; gboolean usign_success = TRUE, ssign_success = TRUE; char filename[512], filename2[512], *fingerprint = NULL, *tmp; SilcUInt32 len; + SilcHash hash; int i; if (!success) { /* The user did not trust the public key. */ silcpurple_add_buddy_pk_no(r); + silc_free(r->offline_pk); + if (r->public_key) + silc_pkcs_public_key_free(r->public_key); silc_free(r); return; } @@ -783,6 +772,8 @@ purple_prpl_got_user_status(purple_buddy_get_account(r->b), purple_buddy_get_name(r->b), SILCPURPLE_STATUS_ID_OFFLINE, NULL); silc_free(fingerprint); silc_free(r->offline_pk); + if (r->public_key) + silc_pkcs_public_key_free(r->public_key); silc_free(r); return; } @@ -791,16 +782,15 @@ client_entry = silc_client_get_client_by_id(r->client, r->conn, &r->client_id); if (!client_entry) { + silc_free(r->offline_pk); + silc_pkcs_public_key_free(r->public_key); + if (r->public_key) + silc_pkcs_public_key_free(r->public_key); silc_free(r); return; } memset(&vcard, 0, sizeof(vcard)); - memset(&message, 0, sizeof(message)); - memset(&extension, 0, sizeof(extension)); -#ifdef SILC_ATTRIBUTE_USER_ICON - memset(&usericon, 0, sizeof(usericon)); -#endif memset(&serverpk, 0, sizeof(serverpk)); memset(&usersign, 0, sizeof(usersign)); memset(&serversign, 0, sizeof(serversign)); @@ -822,24 +812,25 @@ break; case SILC_ATTRIBUTE_STATUS_MESSAGE: - if (!silc_attribute_get_object(attr, (void *)&message, - sizeof(message))) + message = silc_mime_alloc(); + if (!silc_attribute_get_object(attr, (void *)message, + sizeof(*message))) continue; break; case SILC_ATTRIBUTE_EXTENSION: - if (!silc_attribute_get_object(attr, (void *)&extension, - sizeof(extension))) + extension = silc_mime_alloc(); + if (!silc_attribute_get_object(attr, (void *)extension, + sizeof(*extension))) continue; break; -#ifdef SILC_ATTRIBUTE_USER_ICON case SILC_ATTRIBUTE_USER_ICON: - if (!silc_attribute_get_object(attr, (void *)&usericon, - sizeof(usericon))) + usericon = silc_mime_alloc(); + if (!silc_attribute_get_object(attr, (void *)usericon, + sizeof(*usericon))) continue; break; -#endif case SILC_ATTRIBUTE_SERVER_PUBLIC_KEY: if (serverpk.type) @@ -872,50 +863,54 @@ } /* Verify the attribute signatures */ + silc_hash_alloc((const unsigned char *)"sha1", &hash); if (usersign.data) { - SilcPKCS pkcs; unsigned char *verifyd; SilcUInt32 verify_len; - silc_pkcs_alloc((unsigned char*)"rsa", &pkcs); verifyd = silc_attribute_get_verify_data(client_entry->attrs, FALSE, &verify_len); - if (verifyd && silc_pkcs_public_key_set(pkcs, client_entry->public_key)){ - if (!silc_pkcs_verify_with_hash(pkcs, client->sha1hash, - usersign.data, - usersign.data_len, - verifyd, verify_len)) - usign_success = FALSE; - } + if (verifyd && !silc_pkcs_verify(client_entry->public_key, + usersign.data, + usersign.data_len, + verifyd, verify_len, hash)) + usign_success = FALSE; silc_free(verifyd); } - if (serversign.data && !strcmp(serverpk.type, "silc-rsa")) { + if (serversign.data) { SilcPublicKey public_key; - SilcPKCS pkcs; + SilcPKCSType type = 0; unsigned char *verifyd; SilcUInt32 verify_len; - if (silc_pkcs_public_key_decode(serverpk.data, serverpk.data_len, - &public_key)) { - silc_pkcs_alloc((unsigned char *)"rsa", &pkcs); + if (!strcmp(serverpk.type, "silc-rsa")) + type = SILC_PKCS_SILC; + else if (!strcmp(serverpk.type, "ssh-rsa")) + type = SILC_PKCS_SSH2; + else if (!strcmp(serverpk.type, "x509v3-sign-rsa")) + type = SILC_PKCS_X509V3; + else if (!strcmp(serverpk.type, "pgp-sign-rsa")) + type = SILC_PKCS_OPENPGP; + + if (silc_pkcs_public_key_alloc(type, serverpk.data, + serverpk.data_len, + &public_key)) { verifyd = silc_attribute_get_verify_data(client_entry->attrs, TRUE, &verify_len); - if (verifyd && silc_pkcs_public_key_set(pkcs, public_key)) { - if (!silc_pkcs_verify_with_hash(pkcs, client->sha1hash, - serversign.data, - serversign.data_len, - verifyd, verify_len)) - ssign_success = FALSE; - } + if (verifyd && !silc_pkcs_verify(public_key, + serversign.data, + serversign.data_len, + verifyd, verify_len, + hash)) + ssign_success = FALSE; silc_pkcs_public_key_free(public_key); silc_free(verifyd); } } - fingerprint = silc_fingerprint(client_entry->fingerprint, - client_entry->fingerprint_len); + fingerprint = silc_fingerprint(client_entry->fingerprint, 20); for (i = 0; i < strlen(fingerprint); i++) if (fingerprint[i] == ' ') fingerprint[i] = '_'; @@ -954,48 +949,45 @@ } /* Save status message */ - if (message.mime) { + if (message) { memset(filename2, 0, sizeof(filename2)); g_snprintf(filename2, sizeof(filename2) - 1, "%s" G_DIR_SEPARATOR_S "status_message.mime", filename); - silc_file_writefile(filename2, (char *)message.mime, - message.mime_len); + tmp = (char *)silc_mime_get_data(message, &len); + silc_file_writefile(filename2, tmp, len); + silc_mime_free(message); } /* Save extension data */ - if (extension.mime) { + if (extension) { memset(filename2, 0, sizeof(filename2)); g_snprintf(filename2, sizeof(filename2) - 1, "%s" G_DIR_SEPARATOR_S "extension.mime", filename); - silc_file_writefile(filename2, (char *)extension.mime, - extension.mime_len); + tmp = (char *)silc_mime_get_data(extension, &len); + silc_file_writefile(filename2, tmp, len); + silc_mime_free(extension); } -#ifdef SILC_ATTRIBUTE_USER_ICON /* Save user icon */ - if (usericon.mime) { - SilcMime m = silc_mime_decode(usericon.mime, - usericon.mime_len); - if (m) { - const char *type = silc_mime_get_field(m, "Content-Type"); - if (!strcmp(type, "image/jpeg") || - !strcmp(type, "image/gif") || - !strcmp(type, "image/bmp") || - !strcmp(type, "image/png")) { - const unsigned char *data; - SilcUInt32 data_len; - data = silc_mime_get_data(m, &data_len); - if (data) { - /* TODO: Check if SILC gives us something to use as the checksum instead */ - purple_buddy_icons_set_for_user(purple_buddy_get_account(r->b), purple_buddy_get_name(r->b), g_memdup(data, data_len), data_len, NULL); - } + if (usericon) { + const char *type = silc_mime_get_field(usericon, "Content-Type"); + if (type && + (!strcmp(type, "image/jpeg") || + !strcmp(type, "image/gif") || + !strcmp(type, "image/bmp") || + !strcmp(type, "image/png"))) { + const unsigned char *data; + SilcUInt32 data_len; + data = silc_mime_get_data(usericon, &data_len); + if (data) { + /* TODO: Check if SILC gives us something to use as the checksum instead */ + purple_buddy_icons_set_for_user(purple_buddy_get_account(r->b), purple_buddy_get_name(r->b), g_memdup(data, data_len), data_len, NULL); } - silc_mime_free(m); } + silc_mime_free(usericon); } -#endif } /* Save the public key path to buddy properties, as it is used @@ -1015,7 +1007,11 @@ silc_client_command_call(r->client, r->conn, NULL, "WATCH", "-pubkey", filename2, NULL); + silc_hash_free(hash); silc_free(fingerprint); + silc_free(r->offline_pk); + if (r->public_key) + silc_pkcs_public_key_free(r->public_key); silc_free(r); } @@ -1023,11 +1019,9 @@ silcpurple_add_buddy_ask_import(void *user_data, const char *name) { SilcPurpleBuddyRes r = (SilcPurpleBuddyRes)user_data; - SilcPublicKey public_key; /* Load the public key */ - if (!silc_pkcs_load_public_key(name, &public_key, SILC_PKCS_FILE_PEM) && - !silc_pkcs_load_public_key(name, &public_key, SILC_PKCS_FILE_BIN)) { + if (!silc_pkcs_load_public_key(name, &r->public_key)) { silcpurple_add_buddy_ask_pk_cb(r, 0); purple_notify_error(r->client->application, _("Add Buddy"), _("Could not load public key"), NULL); @@ -1035,12 +1029,10 @@ } /* Now verify the public key */ - r->offline_pk = silc_pkcs_public_key_encode(public_key, &r->offline_pk_len); + r->offline_pk = silc_pkcs_public_key_encode(r->public_key, &r->offline_pk_len); silcpurple_verify_public_key(r->client, r->conn, r->b->name, - SILC_SOCKET_TYPE_CLIENT, - r->offline_pk, r->offline_pk_len, - SILC_SKE_PK_TYPE_SILC, - silcpurple_add_buddy_save, r); + SILC_CONN_CLIENT, r->public_key, + silcpurple_add_buddy_save, r); } static void @@ -1065,9 +1057,9 @@ /* Open file selector to select the public key. */ purple_request_file(r->client->application, _("Open..."), NULL, FALSE, - G_CALLBACK(silcpurple_add_buddy_ask_import), - G_CALLBACK(silcpurple_add_buddy_ask_pk_cancel), - purple_buddy_get_account(r->b), purple_buddy_get_name(r->b), NULL, r); + G_CALLBACK(silcpurple_add_buddy_ask_import), + G_CALLBACK(silcpurple_add_buddy_ask_pk_cancel), + purple_buddy_get_account(r->b), purple_buddy_get_name(r->b), NULL, r); } @@ -1078,20 +1070,29 @@ g_snprintf(tmp, sizeof(tmp), _("The %s buddy is not present in the network"), r->b->name); purple_request_action(r->client->application, _("Add Buddy"), tmp, - _("To add the buddy you must import his/her public key. " - "Press Import to import a public key."), 0, - purple_buddy_get_account(r->b), purple_buddy_get_name(r->b), NULL, r, 2, - _("Cancel"), G_CALLBACK(silcpurple_add_buddy_ask_pk_cb), - _("_Import..."), G_CALLBACK(silcpurple_add_buddy_ask_pk_cb)); + _("To add the buddy you must import his/her public key. " + "Press Import to import a public key."), 0, + purple_buddy_get_account(r->b), purple_buddy_get_name(r->b), NULL, r, 2, + _("Cancel"), G_CALLBACK(silcpurple_add_buddy_ask_pk_cb), + _("_Import..."), G_CALLBACK(silcpurple_add_buddy_ask_pk_cb)); } -static void -silcpurple_add_buddy_getkey_cb(SilcPurpleBuddyRes r, - SilcClientCommandReplyContext cmd) +static SilcBool +silcpurple_add_buddy_getkey_cb(SilcClient client, SilcClientConnection conn, + SilcCommand command, SilcStatus status, + SilcStatus error, void *context, va_list ap) { + SilcPurpleBuddyRes r = context; SilcClientEntry client_entry; - unsigned char *pk; - SilcUInt32 pk_len; + + if (status != SILC_STATUS_OK) { + /* The buddy is offline/nonexistent. We will require user + to associate a public key with the buddy or the buddy + cannot be added. */ + r->offline = TRUE; + silcpurple_add_buddy_ask_pk(r); + return FALSE; + } /* Get the client entry. */ client_entry = silc_client_get_client_by_id(r->client, r->conn, @@ -1102,16 +1103,14 @@ cannot be added. */ r->offline = TRUE; silcpurple_add_buddy_ask_pk(r); - return; + return FALSE; } /* Now verify the public key */ - pk = silc_pkcs_public_key_encode(client_entry->public_key, &pk_len); silcpurple_verify_public_key(r->client, r->conn, client_entry->nickname, - SILC_SOCKET_TYPE_CLIENT, - pk, pk_len, SILC_SKE_PK_TYPE_SILC, - silcpurple_add_buddy_save, r); - silc_free(pk); + SILC_CONN_CLIENT, client_entry->public_key, + silcpurple_add_buddy_save, r); + return TRUE; } static void @@ -1120,6 +1119,7 @@ PurpleRequestField *f; const GList *list; SilcClientEntry client_entry; + SilcDList clients; f = purple_request_fields_get_field(fields, "list"); list = purple_request_field_list_get_selected(f); @@ -1131,7 +1131,11 @@ } client_entry = purple_request_field_list_get_data(f, list->data); - silcpurple_add_buddy_resolved(r->client, r->conn, &client_entry, 1, r); + clients = silc_dlist_init(); + silc_dlist_add(clients, client_entry); + silcpurple_add_buddy_resolved(r->client, r->conn, SILC_STATUS_OK, + clients, r); + silc_dlist_uninit(clients); } static void @@ -1143,16 +1147,14 @@ } static void -silcpurple_add_buddy_select(SilcPurpleBuddyRes r, - SilcClientEntry *clients, - SilcUInt32 clients_count) +silcpurple_add_buddy_select(SilcPurpleBuddyRes r, SilcDList clients) { PurpleRequestFields *fields; PurpleRequestFieldGroup *g; PurpleRequestField *f; char tmp[512], tmp2[128]; - int i; char *fingerprint; + SilcClientEntry client_entry; fields = purple_request_fields_new(); g = purple_request_field_group_new(NULL); @@ -1161,56 +1163,56 @@ purple_request_field_list_set_multi_select(f, FALSE); purple_request_fields_add_group(fields, g); - for (i = 0; i < clients_count; i++) { + silc_dlist_start(clients); + while ((client_entry = silc_dlist_get(clients))) { fingerprint = NULL; - if (clients[i]->fingerprint) { - fingerprint = silc_fingerprint(clients[i]->fingerprint, - clients[i]->fingerprint_len); + if (*client_entry->fingerprint) { + fingerprint = silc_fingerprint(client_entry->fingerprint, 20); g_snprintf(tmp2, sizeof(tmp2), "\n%s", fingerprint); } g_snprintf(tmp, sizeof(tmp), "%s - %s (%s@%s)%s", - clients[i]->realname, clients[i]->nickname, - clients[i]->username, clients[i]->hostname ? - clients[i]->hostname : "", + client_entry->realname, client_entry->nickname, + client_entry->username, *client_entry->hostname ? + client_entry->hostname : "", fingerprint ? tmp2 : ""); - purple_request_field_list_add(f, tmp, clients[i]); + purple_request_field_list_add(f, tmp, client_entry); silc_free(fingerprint); } purple_request_fields(r->client->application, _("Add Buddy"), - _("Select correct user"), - r->pubkey_search - ? _("More than one user was found with the same public key. Select " - "the correct user from the list to add to the buddy list.") - : _("More than one user was found with the same name. Select " - "the correct user from the list to add to the buddy list."), - fields, - _("OK"), G_CALLBACK(silcpurple_add_buddy_select_cb), - _("Cancel"), G_CALLBACK(silcpurple_add_buddy_select_cancel), - purple_buddy_get_account(r->b), purple_buddy_get_name(r->b), NULL, r); + _("Select correct user"), + r->pubkey_search + ? _("More than one user was found with the same public key. Select " + "the correct user from the list to add to the buddy list.") + : _("More than one user was found with the same name. Select " + "the correct user from the list to add to the buddy list."), + fields, + _("OK"), G_CALLBACK(silcpurple_add_buddy_select_cb), + _("Cancel"), G_CALLBACK(silcpurple_add_buddy_select_cancel), + purple_buddy_get_account(r->b), purple_buddy_get_name(r->b), NULL, r); } static void silcpurple_add_buddy_resolved(SilcClient client, - SilcClientConnection conn, - SilcClientEntry *clients, - SilcUInt32 clients_count, - void *context) + SilcClientConnection conn, + SilcStatus status, + SilcDList clients, + void *context) { SilcPurpleBuddyRes r = context; PurpleBuddy *b = r->b; SilcAttributePayload pub; SilcAttributeObjPk userpk; - unsigned char *pk; - SilcUInt32 pk_len; const char *filename; + SilcClientEntry client_entry = NULL; + SilcUInt16 cmd_ident; filename = purple_blist_node_get_string((PurpleBlistNode *)b, "public-key"); /* If the buddy is offline/nonexistent, we will require user to associate a public key with the buddy or the buddy cannot be added. */ - if (!clients_count) { + if (!clients) { if (r->init) { silc_free(r); return; @@ -1228,33 +1230,37 @@ /* If more than one client was found with nickname, we need to verify from user which one is the correct. */ - if (clients_count > 1 && !r->pubkey_search) { + if (silc_dlist_count(clients) > 1 && !r->pubkey_search) { if (r->init) { silc_free(r); return; } - silcpurple_add_buddy_select(r, clients, clients_count); + silcpurple_add_buddy_select(r, clients); return; } + silc_dlist_start(clients); + client_entry = silc_dlist_get(clients); + /* If we searched using public keys and more than one entry was found the same person is logged on multiple times. */ - if (clients_count > 1 && r->pubkey_search && b->name) { + if (silc_dlist_count(clients) > 1 && r->pubkey_search && b->name) { if (r->init) { /* Find the entry that closest matches to the buddy nickname. */ - int i; - for (i = 0; i < clients_count; i++) { - if (!strncasecmp(b->name, clients[i]->nickname, + SilcClientEntry entry; + silc_dlist_start(clients); + while ((entry = silc_dlist_get(clients))) { + if (!strncasecmp(b->name, entry->nickname, strlen(b->name))) { - clients[0] = clients[i]; + client_entry = entry; break; } } } else { /* Verify from user which one is correct */ - silcpurple_add_buddy_select(r, clients, clients_count); + silcpurple_add_buddy_select(r, clients); return; } } @@ -1262,61 +1268,60 @@ /* The client was found. Now get its public key and verify that before adding the buddy. */ memset(&userpk, 0, sizeof(userpk)); - b->proto_data = silc_memdup(clients[0]->id, sizeof(*clients[0]->id)); - r->client_id = *clients[0]->id; + b->proto_data = silc_memdup(&client_entry->id, sizeof(client_entry->id)); + r->client_id = client_entry->id; /* Get the public key from attributes, if not present then resolve it with GETKEY unless we have it cached already. */ - if (clients[0]->attrs && !clients[0]->public_key) { - pub = silcpurple_get_attr(clients[0]->attrs, - SILC_ATTRIBUTE_USER_PUBLIC_KEY); + if (client_entry->attrs && !client_entry->public_key) { + pub = silcpurple_get_attr(client_entry->attrs, + SILC_ATTRIBUTE_USER_PUBLIC_KEY); if (!pub || !silc_attribute_get_object(pub, (void *)&userpk, sizeof(userpk))) { /* Get public key with GETKEY */ - silc_client_command_call(client, conn, NULL, - "GETKEY", clients[0]->nickname, NULL); + cmd_ident = + silc_client_command_call(client, conn, NULL, + "GETKEY", client_entry->nickname, NULL); silc_client_command_pending(conn, SILC_COMMAND_GETKEY, - conn->cmd_ident, - (SilcCommandCb)silcpurple_add_buddy_getkey_cb, + cmd_ident, + silcpurple_add_buddy_getkey_cb, r); return; } - if (!silc_pkcs_public_key_decode(userpk.data, userpk.data_len, - &clients[0]->public_key)) + if (!silc_pkcs_public_key_alloc(SILC_PKCS_SILC, + userpk.data, userpk.data_len, + &client_entry->public_key)) return; silc_free(userpk.data); - } else if (filename && !clients[0]->public_key) { - if (!silc_pkcs_load_public_key(filename, &clients[0]->public_key, - SILC_PKCS_FILE_PEM) && - !silc_pkcs_load_public_key(filename, &clients[0]->public_key, - SILC_PKCS_FILE_BIN)) { + } else if (filename && !client_entry->public_key) { + if (!silc_pkcs_load_public_key(filename, &client_entry->public_key)) { /* Get public key with GETKEY */ - silc_client_command_call(client, conn, NULL, - "GETKEY", clients[0]->nickname, NULL); + cmd_ident = + silc_client_command_call(client, conn, NULL, + "GETKEY", client_entry->nickname, NULL); silc_client_command_pending(conn, SILC_COMMAND_GETKEY, - conn->cmd_ident, - (SilcCommandCb)silcpurple_add_buddy_getkey_cb, + cmd_ident, + silcpurple_add_buddy_getkey_cb, r); return; } - } else if (!clients[0]->public_key) { + } else if (!client_entry->public_key) { /* Get public key with GETKEY */ - silc_client_command_call(client, conn, NULL, - "GETKEY", clients[0]->nickname, NULL); + cmd_ident = + silc_client_command_call(client, conn, NULL, + "GETKEY", client_entry->nickname, NULL); silc_client_command_pending(conn, SILC_COMMAND_GETKEY, - conn->cmd_ident, - (SilcCommandCb)silcpurple_add_buddy_getkey_cb, + cmd_ident, + silcpurple_add_buddy_getkey_cb, r); return; } /* We have the public key, verify it. */ - pk = silc_pkcs_public_key_encode(clients[0]->public_key, &pk_len); - silcpurple_verify_public_key(client, conn, clients[0]->nickname, - SILC_SOCKET_TYPE_CLIENT, - pk, pk_len, SILC_SKE_PK_TYPE_SILC, - silcpurple_add_buddy_save, r); - silc_free(pk); + silcpurple_verify_public_key(client, conn, client_entry->nickname, + SILC_CONN_CLIENT, + client_entry->public_key, + silcpurple_add_buddy_save, r); } static void @@ -1344,10 +1349,7 @@ SilcPublicKey public_key; SilcAttributeObjPk userpk; - if (!silc_pkcs_load_public_key(filename, &public_key, - SILC_PKCS_FILE_PEM) && - !silc_pkcs_load_public_key(filename, &public_key, - SILC_PKCS_FILE_BIN)) + if (!silc_pkcs_load_public_key(filename, &public_key)) return; /* Get all attributes, and use the public key to search user */ @@ -1361,9 +1363,7 @@ SILC_ATTRIBUTE_PREFERRED_CONTACT, SILC_ATTRIBUTE_TIMEZONE, SILC_ATTRIBUTE_GEOLOCATION, -#ifdef SILC_ATTRIBUTE_USER_ICON SILC_ATTRIBUTE_USER_ICON, -#endif SILC_ATTRIBUTE_DEVICE_INFO, 0); userpk.type = "silc-rsa"; userpk.data = silc_pkcs_public_key_encode(public_key, &userpk.data_len); @@ -1632,12 +1632,13 @@ sg->conn, buddy->proto_data); - if (client_entry && client_entry->send_key) { + if (client_entry && + silc_client_private_message_key_is_set(sg->client, + sg->conn, client_entry)) { act = purple_menu_action_new(_("Reset IM Key"), PURPLE_CALLBACK(silcpurple_buddy_resetkey), NULL, NULL); m = g_list_append(m, act); - } else { act = purple_menu_action_new(_("IM with Key Exchange"), PURPLE_CALLBACK(silcpurple_buddy_keyagr), @@ -1682,7 +1683,6 @@ return m; } -#ifdef SILC_ATTRIBUTE_USER_ICON void silcpurple_buddy_set_icon(PurpleConnection *gc, PurpleStoredImage *img) { SilcPurple sg = gc->proto_data; @@ -1690,9 +1690,7 @@ SilcClientConnection conn = sg->conn; SilcMime mime; char type[32]; - unsigned char *icon; const char *t; - SilcAttributeObjMime obj; /* Remove */ if (!img) { @@ -1717,12 +1715,8 @@ silc_mime_add_field(mime, "Content-Type", type); silc_mime_add_data(mime, purple_imgstore_get_data(img), purple_imgstore_get_size(img)); - obj.mime = icon = silc_mime_encode(mime, &obj.mime_len); - if (obj.mime) - silc_client_attribute_add(client, conn, - SILC_ATTRIBUTE_USER_ICON, &obj, sizeof(obj)); + silc_client_attribute_add(client, conn, + SILC_ATTRIBUTE_USER_ICON, mime, sizeof(*mime)); - silc_free(icon); silc_mime_free(mime); } -#endif
--- a/libpurple/protocols/silc/chat.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/silc/chat.c Mon Jun 18 01:48:35 2007 +0000 @@ -4,7 +4,7 @@ Author: Pekka Riikonen <priikone@silcnet.org> - Copyright (C) 2004 Pekka Riikonen + Copyright (C) 2004 - 2007 Pekka Riikonen 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 @@ -17,7 +17,7 @@ */ -#include "silcincludes.h" +#include "silc.h" #include "silcclient.h" #include "silcpurple.h" #include "wb.h" @@ -61,10 +61,10 @@ static void silcpurple_chat_getinfo_res(SilcClient client, - SilcClientConnection conn, - SilcChannelEntry *channels, - SilcUInt32 channels_count, - void *context) + SilcClientConnection conn, + SilcStatus status, + SilcDList channels, + void *context) { GHashTable *components = context; PurpleConnection *gc = client->application; @@ -134,13 +134,14 @@ } silc_hash_table_list_reset(&htl); - if (channel->channel_key) + if (channel->cipher) g_string_append_printf(s, _("<br><b>Channel Cipher:</b> %s"), - silc_cipher_get_name(channel->channel_key)); + channel->cipher); + if (channel->hmac) /* Definition of HMAC: http://en.wikipedia.org/wiki/HMAC */ g_string_append_printf(s, _("<br><b>Channel HMAC:</b> %s"), - silc_hmac_get_name(channel->hmac)); + channel->hmac); if (channel->topic) { tmp2 = g_markup_escape_text(channel->topic, -1); @@ -211,7 +212,7 @@ SilcPurple sg; SilcChannelEntry channel; PurpleChat *c; - SilcBuffer pubkeys; + SilcDList pubkeys; } *SilcPurpleChauth; static void @@ -227,22 +228,21 @@ SilcUInt32 m; /* Load the public key */ - if (!silc_pkcs_load_public_key(name, &public_key, SILC_PKCS_FILE_PEM) && - !silc_pkcs_load_public_key(name, &public_key, SILC_PKCS_FILE_BIN)) { + if (!silc_pkcs_load_public_key(name, &public_key)) { silcpurple_chat_chauth_show(sgc->sg, sgc->channel, sgc->pubkeys); - silc_buffer_free(sgc->pubkeys); + silc_dlist_uninit(sgc->pubkeys); silc_free(sgc); purple_notify_error(client->application, - _("Add Channel Public Key"), - _("Could not load public key"), NULL); + _("Add Channel Public Key"), + _("Could not load public key"), NULL); return; } - pk = silc_pkcs_public_key_payload_encode(public_key); + pk = silc_public_key_payload_encode(public_key); chpks = silc_buffer_alloc_size(2); SILC_PUT16_MSB(1, chpks->head); chpks = silc_argument_payload_encode_one(chpks, pk->data, - pk->len, 0x00); + silc_buffer_len(pk), 0x00); silc_buffer_free(pk); m = sgc->channel->mode; @@ -250,15 +250,20 @@ /* Send CMODE */ SILC_PUT32_MSB(m, mode); - chidp = silc_id_payload_encode(sgc->channel->id, SILC_ID_CHANNEL); + chidp = silc_id_payload_encode(&sgc->channel->id, SILC_ID_CHANNEL); silc_client_command_send(client, conn, SILC_COMMAND_CMODE, - ++conn->cmd_ident, 3, - 1, chidp->data, chidp->len, + silcpurple_command_reply, NULL, 3, + 1, chidp->data, silc_buffer_len(chidp), 2, mode, sizeof(mode), - 9, chpks->data, chpks->len); + 9, chpks->data, silc_buffer_len(chpks)); silc_buffer_free(chpks); silc_buffer_free(chidp); - silc_buffer_free(sgc->pubkeys); + if (sgc->pubkeys) { + silc_dlist_start(sgc->pubkeys); + while ((public_key = silc_dlist_get(sgc->pubkeys))) + silc_pkcs_public_key_free(public_key); + silc_dlist_uninit(sgc->pubkeys); + } silc_free(sgc); } @@ -266,8 +271,16 @@ silcpurple_chat_chpk_cancel(void *user_data, const char *name) { SilcPurpleChauth sgc = (SilcPurpleChauth)user_data; + SilcPublicKey public_key; + silcpurple_chat_chauth_show(sgc->sg, sgc->channel, sgc->pubkeys); - silc_buffer_free(sgc->pubkeys); + + if (sgc->pubkeys) { + silc_dlist_start(sgc->pubkeys); + while ((public_key = silc_dlist_get(sgc->pubkeys))) + silc_pkcs_public_key_free(public_key); + silc_dlist_uninit(sgc->pubkeys); + } silc_free(sgc); } @@ -289,9 +302,9 @@ if (!purple_request_field_list_get_selected(f)) { /* Add new public key */ purple_request_file(sg->gc, _("Open Public Key..."), NULL, FALSE, - G_CALLBACK(silcpurple_chat_chpk_add), - G_CALLBACK(silcpurple_chat_chpk_cancel), - purple_connection_get_account(sg->gc), NULL, NULL, sgc); + G_CALLBACK(silcpurple_chat_chpk_add), + G_CALLBACK(silcpurple_chat_chpk_cancel), + purple_connection_get_account(sg->gc), NULL, NULL, sgc); return; } @@ -302,13 +315,12 @@ public_key = purple_request_field_list_get_data(f, list->data); if (purple_request_field_list_is_selected(f, list->data)) { /* Delete this public key */ - pk = silc_pkcs_public_key_payload_encode(public_key); + pk = silc_public_key_payload_encode(public_key); chpks = silc_argument_payload_encode_one(chpks, pk->data, - pk->len, 0x01); + silc_buffer_len(pk), 0x01); silc_buffer_free(pk); c++; } - silc_pkcs_public_key_free(public_key); } if (!c) { silc_buffer_free(chpks); @@ -322,15 +334,20 @@ /* Send CMODE */ SILC_PUT32_MSB(m, mode); - chidp = silc_id_payload_encode(sgc->channel->id, SILC_ID_CHANNEL); + chidp = silc_id_payload_encode(&sgc->channel->id, SILC_ID_CHANNEL); silc_client_command_send(client, conn, SILC_COMMAND_CMODE, - ++conn->cmd_ident, 3, - 1, chidp->data, chidp->len, + silcpurple_command_reply, NULL, 3, + 1, chidp->data, silc_buffer_len(chidp), 2, mode, sizeof(mode), - 9, chpks->data, chpks->len); + 9, chpks->data, silc_buffer_len(chpks)); silc_buffer_free(chpks); silc_buffer_free(chidp); - silc_buffer_free(sgc->pubkeys); + if (sgc->pubkeys) { + silc_dlist_start(sgc->pubkeys); + while ((public_key = silc_dlist_get(sgc->pubkeys))) + silc_pkcs_public_key_free(public_key); + silc_dlist_uninit(sgc->pubkeys); + } silc_free(sgc); } @@ -339,6 +356,7 @@ { SilcPurple sg = sgc->sg; PurpleRequestField *f; + SilcPublicKey public_key; const char *curpass, *val; int set; @@ -365,19 +383,23 @@ purple_blist_node_remove_setting((PurpleBlistNode *)sgc->c, "passphrase"); } - silc_buffer_free(sgc->pubkeys); + if (sgc->pubkeys) { + silc_dlist_start(sgc->pubkeys); + while ((public_key = silc_dlist_get(sgc->pubkeys))) + silc_pkcs_public_key_free(public_key); + silc_dlist_uninit(sgc->pubkeys); + } silc_free(sgc); } void silcpurple_chat_chauth_show(SilcPurple sg, SilcChannelEntry channel, - SilcBuffer channel_pubkeys) + SilcDList channel_pubkeys) { - SilcUInt16 argc; - SilcArgumentPayload chpks; + SilcPublicKey public_key; + SilcSILCPublicKey silc_pubkey; unsigned char *pk; - SilcUInt32 pk_len, type; + SilcUInt32 pk_len; char *fingerprint, *babbleprint; - SilcPublicKey pubkey; SilcPublicKeyIdentifier ident; char tmp2[1024], t[512]; PurpleRequestFields *fields; @@ -399,7 +421,7 @@ g = purple_request_field_group_new(NULL); f = purple_request_field_string_new("passphrase", _("Channel Passphrase"), - curpass, FALSE); + curpass, FALSE); purple_request_field_string_set_masked(f, TRUE); purple_request_field_group_add_field(g, f); purple_request_fields_add_group(fields, g); @@ -416,55 +438,49 @@ "is required to be able to join. If channel public keys are set " "then only users whose public keys are listed are able to join.")); - if (!channel_pubkeys) { + if (!channel_pubkeys || !silc_dlist_count(channel_pubkeys)) { f = purple_request_field_list_new("list", NULL); purple_request_field_group_add_field(g, f); purple_request_fields(sg->gc, _("Channel Authentication"), - _("Channel Authentication"), t, fields, - _("Add / Remove"), G_CALLBACK(silcpurple_chat_chpk_cb), - _("OK"), G_CALLBACK(silcpurple_chat_chauth_ok), - purple_connection_get_account(sg->gc), NULL, NULL, sgc); + _("Channel Authentication"), t, fields, + _("Add / Remove"), G_CALLBACK(silcpurple_chat_chpk_cb), + _("OK"), G_CALLBACK(silcpurple_chat_chauth_ok), + purple_connection_get_account(sg->gc), NULL, NULL, sgc); + if (channel_pubkeys) + silc_dlist_uninit(channel_pubkeys); return; } - sgc->pubkeys = silc_buffer_copy(channel_pubkeys); + sgc->pubkeys = channel_pubkeys; g = purple_request_field_group_new(NULL); f = purple_request_field_list_new("list", NULL); purple_request_field_group_add_field(g, f); purple_request_fields_add_group(fields, g); - SILC_GET16_MSB(argc, channel_pubkeys->data); - chpks = silc_argument_payload_parse(channel_pubkeys->data + 2, - channel_pubkeys->len - 2, argc); - if (!chpks) - return; - - pk = silc_argument_get_first_arg(chpks, &type, &pk_len); - while (pk) { + silc_dlist_start(channel_pubkeys); + while ((public_key = silc_dlist_get(channel_pubkeys))) { + pk = silc_pkcs_public_key_encode(public_key, &pk_len); fingerprint = silc_hash_fingerprint(NULL, pk + 4, pk_len - 4); babbleprint = silc_hash_babbleprint(NULL, pk + 4, pk_len - 4); - silc_pkcs_public_key_payload_decode(pk, pk_len, &pubkey); - ident = silc_pkcs_decode_identifier(pubkey->identifier); + + silc_pubkey = silc_pkcs_get_context(SILC_PKCS_SILC, public_key); + ident = &silc_pubkey->identifier; 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(f, tmp2, public_key); silc_free(fingerprint); silc_free(babbleprint); - silc_pkcs_free_identifier(ident); - pk = silc_argument_get_next_arg(chpks, &type, &pk_len); } purple_request_field_list_set_multi_select(f, FALSE); purple_request_fields(sg->gc, _("Channel Authentication"), - _("Channel Authentication"), t, fields, - _("Add / Remove"), G_CALLBACK(silcpurple_chat_chpk_cb), - _("OK"), G_CALLBACK(silcpurple_chat_chauth_ok), - purple_connection_get_account(sg->gc), NULL, NULL, sgc); - - silc_argument_payload_free(chpks); + _("Channel Authentication"), t, fields, + _("Add / Remove"), G_CALLBACK(silcpurple_chat_chpk_cb), + _("OK"), G_CALLBACK(silcpurple_chat_chauth_ok), + purple_connection_get_account(sg->gc), NULL, NULL, sgc); } static void @@ -525,9 +541,9 @@ /* Add private group to buddy list */ g_snprintf(tmp, sizeof(tmp), "%s [Private Group]", name); - comp = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); - g_hash_table_replace(comp, g_strdup("channel"), g_strdup(tmp)); - g_hash_table_replace(comp, g_strdup("passphrase"), g_strdup(passphrase)); + comp = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, g_free); + g_hash_table_replace(comp, "channel", g_strdup(tmp)); + g_hash_table_replace(comp, "passphrase", g_strdup(passphrase)); cn = purple_chat_new(sg->account, alias, comp); g = (PurpleGroup *)p->c->node.parent; @@ -596,9 +612,9 @@ _("Please enter the %s channel private group name and passphrase."), p->channel); purple_request_fields(gc, _("Add Channel Private Group"), NULL, tmp, fields, - _("Add"), G_CALLBACK(silcpurple_chat_prv_add), - _("Cancel"), G_CALLBACK(silcpurple_chat_prv_cancel), - purple_connection_get_account(gc), NULL, NULL, p); + _("Add"), G_CALLBACK(silcpurple_chat_prv_add), + _("Cancel"), G_CALLBACK(silcpurple_chat_prv_cancel), + purple_connection_get_account(gc), NULL, NULL, p); } @@ -907,7 +923,7 @@ m = g_list_append(m, act); } - if (mode & SILC_CHANNEL_UMODE_CHANFO) { + if (chu && mode & SILC_CHANNEL_UMODE_CHANFO) { act = purple_menu_action_new(_("Channel Authentication"), PURPLE_CALLBACK(silcpurple_chat_chauth), NULL, NULL); @@ -926,7 +942,7 @@ } } - if (mode & SILC_CHANNEL_UMODE_CHANOP) { + if (chu && mode & SILC_CHANNEL_UMODE_CHANOP) { act = purple_menu_action_new(_("Set User Limit"), PURPLE_CALLBACK(silcpurple_chat_ulimit), NULL, NULL); @@ -969,7 +985,7 @@ } } - if (channel) { + if (chu && channel) { SilcPurpleChatWb wb; wb = silc_calloc(1, sizeof(*wb)); wb->sg = sg; @@ -986,86 +1002,10 @@ /******************************* Joining Etc. ********************************/ -void silcpurple_chat_join_done(SilcClient client, - SilcClientConnection conn, - SilcClientEntry *clients, - SilcUInt32 clients_count, - void *context) -{ - PurpleConnection *gc = client->application; - SilcPurple sg = gc->proto_data; - SilcChannelEntry channel = context; - PurpleConversation *convo; - SilcUInt32 retry = SILC_PTR_TO_32(channel->context); - SilcHashTableList htl; - SilcChannelUser chu; - GList *users = NULL, *flags = NULL; - char tmp[256]; - - if (!clients && retry < 1) { - /* Resolving users failed, try again. */ - channel->context = SILC_32_TO_PTR(retry + 1); - silc_client_get_clients_by_channel(client, conn, channel, - silcpurple_chat_join_done, channel); - return; - } - - /* Add channel to Purple */ - channel->context = SILC_32_TO_PTR(++sg->channel_ids); - serv_got_joined_chat(gc, sg->channel_ids, channel->channel_name); - convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, - channel->channel_name, sg->account); - if (!convo) - return; - - /* Add all users to channel */ - silc_hash_table_list(channel->user_list, &htl); - while (silc_hash_table_get(&htl, NULL, (void *)&chu)) { - PurpleConvChatBuddyFlags f = PURPLE_CBFLAGS_NONE; - if (!chu->client->nickname) - continue; - chu->context = SILC_32_TO_PTR(sg->channel_ids); - - if (chu->mode & SILC_CHANNEL_UMODE_CHANFO) - f |= PURPLE_CBFLAGS_FOUNDER; - if (chu->mode & SILC_CHANNEL_UMODE_CHANOP) - f |= PURPLE_CBFLAGS_OP; - users = g_list_append(users, g_strdup(chu->client->nickname)); - flags = g_list_append(flags, GINT_TO_POINTER(f)); - - if (chu->mode & SILC_CHANNEL_UMODE_CHANFO) { - if (chu->client == conn->local_entry) - g_snprintf(tmp, sizeof(tmp), - _("You are channel founder on <I>%s</I>"), - channel->channel_name); - else - g_snprintf(tmp, sizeof(tmp), - _("Channel founder on <I>%s</I> is <I>%s</I>"), - channel->channel_name, chu->client->nickname); - - purple_conversation_write(convo, NULL, tmp, - PURPLE_MESSAGE_SYSTEM, time(NULL)); - - } - } - silc_hash_table_list_reset(&htl); - - purple_conv_chat_add_users(PURPLE_CONV_CHAT(convo), users, NULL, flags, FALSE); - g_list_free(users); - g_list_free(flags); - - /* Set topic */ - if (channel->topic) - purple_conv_chat_set_topic(PURPLE_CONV_CHAT(convo), NULL, channel->topic); - - /* Set nick */ - purple_conv_chat_set_nick(PURPLE_CONV_CHAT(convo), conn->local_entry->nickname); -} - char *silcpurple_get_chat_name(GHashTable *data) { return g_strdup(g_hash_table_lookup(data, "channel")); -} +} void silcpurple_chat_join(PurpleConnection *gc, GHashTable *data) { @@ -1073,6 +1013,9 @@ SilcClient client = sg->client; SilcClientConnection conn = sg->conn; const char *channel, *passphrase, *parentch; +#if 0 + PurpleChat *chat; +#endif if (!conn) return; @@ -1128,6 +1071,22 @@ return; } +#if 0 + /* If the channel is not on buddy list, automatically add it there. */ + chat = purple_blist_find_chat(sg->account, channel); + if (!chat) { + data = g_hash_table_new_full(g_str_hash, g_str_equal, + g_free, g_free); + g_hash_table_replace(data, g_strdup("channel"), + g_strdup(channel)); + if (passphrase) + g_hash_table_replace(data, g_strdup("passphrase"), + g_strdup(passphrase)); + chat = purple_chat_new(sg->account, NULL, data); + purple_blist_add_chat(chat, NULL, NULL); + } +#endif + /* XXX We should have other properties here as well: 1. whether to try to authenticate to the channel 1a. with default key, @@ -1150,7 +1109,7 @@ } void silcpurple_chat_invite(PurpleConnection *gc, int id, const char *msg, - const char *name) + const char *name) { SilcPurple sg = gc->proto_data; SilcClient client = sg->client; @@ -1264,7 +1223,8 @@ } } -int silcpurple_chat_send(PurpleConnection *gc, int id, const char *msg, PurpleMessageFlags msgflags) +int silcpurple_chat_send(PurpleConnection *gc, int id, const char *msg, + PurpleMessageFlags msgflags) { SilcPurple sg = gc->proto_data; SilcClient client = sg->client; @@ -1274,10 +1234,11 @@ SilcChannelEntry channel = NULL; SilcChannelPrivateKey key = NULL; SilcUInt32 flags; - int ret; + int ret = 0; char *msg2, *tmp; gboolean found = FALSE; gboolean sign = purple_account_get_bool(sg->account, "sign-verify", FALSE); + SilcDList list; if (!msg || !conn) return 0; @@ -1297,7 +1258,7 @@ } else if (strlen(msg) > 1 && msg[0] == '/') { if (!silc_client_command_call(client, conn, msg + 1)) purple_notify_error(gc, _("Call Command"), _("Cannot call command"), - _("Unknown command")); + _("Unknown command")); g_free(tmp); return 0; } @@ -1346,10 +1307,35 @@ channel = chu->channel; } + /* Check for images */ + if (msgflags & PURPLE_MESSAGE_IMAGES) { + list = silcpurple_image_message(msg, &flags); + if (list) { + /* Send one or more MIME message. If more than one, they + are MIME fragments due to over large message */ + SilcBuffer buf; + + silc_dlist_start(list); + while ((buf = silc_dlist_get(list)) != SILC_LIST_END) + ret = + silc_client_send_channel_message(client, conn, + channel, key, + flags, NULL, + buf->data, + silc_buffer_len(buf)); + silc_mime_partial_free(list); + g_free(tmp); + + if (ret) + serv_got_chat_in(gc, id, purple_connection_get_display_name(gc), 0, msg, time(NULL)); + return ret; + } + } + /* Send channel message */ ret = silc_client_send_channel_message(client, conn, channel, key, - flags, (unsigned char *)msg2, - strlen(msg2), TRUE); + flags, NULL, (unsigned char *)msg2, + strlen(msg2)); if (ret) { serv_got_chat_in(gc, id, purple_connection_get_display_name(gc), 0, msg, time(NULL));
--- a/libpurple/protocols/silc/ft.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/silc/ft.c Mon Jun 18 01:48:35 2007 +0000 @@ -4,7 +4,7 @@ Author: Pekka Riikonen <priikone@silcnet.org> - Copyright (C) 2004 Pekka Riikonen + Copyright (C) 2004 - 2007 Pekka Riikonen 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 @@ -17,7 +17,7 @@ */ -#include "silcincludes.h" +#include "silc.h" #include "silcclient.h" #include "silcpurple.h" @@ -74,11 +74,23 @@ char tmp[256]; if (status == SILC_CLIENT_FILE_MONITOR_CLOSED) { + /* All started sessions terminate here */ + xfer->xfer->data = NULL; purple_xfer_unref(xfer->xfer); silc_free(xfer); return; } + if (status == SILC_CLIENT_FILE_MONITOR_DISCONNECT) { + purple_notify_error(gc, _("Secure File Transfer"), + _("Error during file transfer"), + _("Remote disconnected")); + xfer->xfer->status = PURPLE_XFER_STATUS_CANCEL_REMOTE; + purple_xfer_update_progress(xfer->xfer); + silc_client_file_close(client, conn, session_id); + return; + } + if (status == SILC_CLIENT_FILE_MONITOR_KEY_AGREEMENT) return; @@ -96,17 +108,22 @@ purple_notify_error(gc, _("Secure File Transfer"), _("Error during file transfer"), _("Key agreement failed")); + } else if (error == SILC_CLIENT_FILE_TIMEOUT) { + purple_notify_error(gc, _("Secure File Transfer"), + _("Error during file transfer"), + _("Connection timedout")); + } else if (error == SILC_CLIENT_FILE_CONNECT_FAILED) { + purple_notify_error(gc, _("Secure File Transfer"), + _("Error during file transfer"), + _("Creating connection failed")); } else if (error == SILC_CLIENT_FILE_UNKNOWN_SESSION) { purple_notify_error(gc, _("Secure File Transfer"), _("Error during file transfer"), _("File transfer session does not exist")); - } else { - purple_notify_error(gc, _("Secure File Transfer"), - _("Error during file transfer"), NULL); } + xfer->xfer->status = PURPLE_XFER_STATUS_CANCEL_REMOTE; + purple_xfer_update_progress(xfer->xfer); silc_client_file_close(client, conn, session_id); - purple_xfer_unref(xfer->xfer); - silc_free(xfer); return; } @@ -133,6 +150,10 @@ silcpurple_ftp_cancel(PurpleXfer *x) { SilcPurpleXfer xfer = x->data; + + if (!xfer) + return; + xfer->xfer->status = PURPLE_XFER_STATUS_CANCEL_LOCAL; purple_xfer_update_progress(xfer->xfer); silc_client_file_close(xfer->sg->client, xfer->sg->conn, xfer->session_id); @@ -143,6 +164,9 @@ { SilcPurpleXfer xfer = x->data; + if (!xfer) + return; + /* Cancel the transmission */ xfer->completion(NULL, xfer->completion_context); silc_client_file_close(xfer->sg->client, xfer->sg->conn, xfer->session_id); @@ -154,6 +178,9 @@ SilcPurpleXfer xfer = x->data; const char *name; + if (!xfer) + return; + name = purple_xfer_get_local_filename(x); g_unlink(name); xfer->completion(name, xfer->completion_context); @@ -187,17 +214,57 @@ SilcPurpleXfer xfer = x->data; SilcClientFileError status; PurpleConnection *gc = xfer->sg->gc; + SilcClientConnectionParams params; + gboolean local = xfer->hostname ? FALSE : TRUE; + char *local_ip = NULL, *remote_ip = NULL; + SilcSocket sock; if (purple_xfer_get_status(x) != PURPLE_XFER_STATUS_ACCEPTED) return; + if (!xfer) + return; + + silc_socket_stream_get_info(silc_packet_stream_get_stream(xfer->sg->conn->stream), + &sock, NULL, NULL, NULL); + + if (local) { + /* Do the same magic what we do with key agreement (see silcpurple_buddy.c) + to see if we are behind NAT. */ + if (silc_net_check_local_by_sock(sock, NULL, &local_ip)) { + /* Check if the IP is private */ + if (silcpurple_ip_is_private(local_ip)) { + local = TRUE; + /* Local IP is private, resolve the remote server IP to see whether + we are talking to Internet or just on LAN. */ + if (silc_net_check_host_by_sock(sock, NULL, + &remote_ip)) + if (silcpurple_ip_is_private(remote_ip)) + /* We assume we are in LAN. Let's provide the connection point. */ + local = TRUE; + } + } + + if (local && !local_ip) + local_ip = silc_net_localip(); + } + + memset(¶ms, 0, sizeof(params)); + params.timeout_secs = 60; + if (local) + /* Provide connection point */ + params.local_ip = local_ip; /* Start the file transfer */ status = silc_client_file_receive(xfer->sg->client, xfer->sg->conn, + ¶ms, xfer->sg->public_key, + xfer->sg->private_key, silcpurple_ftp_monitor, xfer, NULL, xfer->session_id, silcpurple_ftp_ask_name, xfer); switch (status) { case SILC_CLIENT_FILE_OK: + silc_free(local_ip); + silc_free(remote_ip); return; break; @@ -227,6 +294,8 @@ purple_xfer_unref(xfer->xfer); g_free(xfer->hostname); silc_free(xfer); + silc_free(local_ip); + silc_free(remote_ip); } static void @@ -236,8 +305,8 @@ } void silcpurple_ftp_request(SilcClient client, SilcClientConnection conn, - SilcClientEntry client_entry, SilcUInt32 session_id, - const char *hostname, SilcUInt16 port) + SilcClientEntry client_entry, SilcUInt32 session_id, + const char *hostname, SilcUInt16 port) { PurpleConnection *gc = client->application; SilcPurple sg = gc->proto_data; @@ -255,7 +324,7 @@ xfer->hostname = g_strdup(hostname); xfer->port = port; xfer->xfer = purple_xfer_new(xfer->sg->account, PURPLE_XFER_RECEIVE, - xfer->client_entry->nickname); + xfer->client_entry->nickname); if (!xfer->xfer) { silc_client_file_close(xfer->sg->client, xfer->sg->conn, xfer->session_id); g_free(xfer->hostname); @@ -277,10 +346,12 @@ silcpurple_ftp_send_cancel(PurpleXfer *x) { SilcPurpleXfer xfer = x->data; + + if (!xfer) + return; + + /* This call will free all resources */ silc_client_file_close(xfer->sg->client, xfer->sg->conn, xfer->session_id); - purple_xfer_unref(xfer->xfer); - g_free(xfer->hostname); - silc_free(xfer); } static void @@ -290,19 +361,26 @@ const char *name; char *local_ip = NULL, *remote_ip = NULL; gboolean local = TRUE; + SilcClientConnectionParams params; + SilcSocket sock; + + if (!xfer) + return; name = purple_xfer_get_local_filename(x); + silc_socket_stream_get_info(silc_packet_stream_get_stream(xfer->sg->conn->stream), + &sock, NULL, NULL, NULL); + /* Do the same magic what we do with key agreement (see silcpurple_buddy.c) to see if we are behind NAT. */ - if (silc_net_check_local_by_sock(xfer->sg->conn->sock->sock, - NULL, &local_ip)) { + if (silc_net_check_local_by_sock(sock, NULL, &local_ip)) { /* Check if the IP is private */ if (silcpurple_ip_is_private(local_ip)) { local = FALSE; /* Local IP is private, resolve the remote server IP to see whether we are talking to Internet or just on LAN. */ - if (silc_net_check_host_by_sock(xfer->sg->conn->sock->sock, NULL, + if (silc_net_check_host_by_sock(sock, NULL, &remote_ip)) if (silcpurple_ip_is_private(remote_ip)) /* We assume we are in LAN. Let's provide the connection point. */ @@ -313,10 +391,17 @@ if (local && !local_ip) local_ip = silc_net_localip(); + memset(¶ms, 0, sizeof(params)); + params.timeout_secs = 60; + if (local) + /* Provide connection point */ + params.local_ip = local_ip; + /* Send the file */ silc_client_file_send(xfer->sg->client, xfer->sg->conn, + xfer->client_entry, ¶ms, + xfer->sg->public_key, xfer->sg->private_key, silcpurple_ftp_monitor, xfer, - local_ip, 0, !local, xfer->client_entry, name, &xfer->session_id); silc_free(local_ip); @@ -325,10 +410,10 @@ static void silcpurple_ftp_send_file_resolved(SilcClient client, - SilcClientConnection conn, - SilcClientEntry *clients, - SilcUInt32 clients_count, - void *context) + SilcClientConnection conn, + SilcStatus status, + SilcDList clients, + void *context) { PurpleConnection *gc = client->application; char tmp[256]; @@ -352,38 +437,29 @@ SilcPurple sg = gc->proto_data; SilcClient client = sg->client; SilcClientConnection conn = sg->conn; - SilcClientEntry *clients; - SilcUInt32 clients_count; + SilcDList clients; SilcPurpleXfer xfer; - char *nickname; g_return_val_if_fail(name != NULL, NULL); - if (!silc_parse_userfqdn(name, &nickname, NULL)) - return NULL; - /* Find client entry */ - clients = silc_client_get_clients_local(client, conn, nickname, name, - &clients_count); + clients = silc_client_get_clients_local(client, conn, name, FALSE); if (!clients) { - silc_client_get_clients(client, conn, nickname, NULL, - silcpurple_ftp_send_file_resolved, - strdup(name)); - silc_free(nickname); + silc_client_get_clients(client, conn, name, NULL, + silcpurple_ftp_send_file_resolved, + strdup(name)); return NULL; } + silc_dlist_start(clients); xfer = silc_calloc(1, sizeof(*xfer)); - g_return_val_if_fail(xfer != NULL, NULL); xfer->sg = sg; - xfer->client_entry = clients[0]; + xfer->client_entry = silc_dlist_get(clients); xfer->xfer = purple_xfer_new(xfer->sg->account, PURPLE_XFER_SEND, - xfer->client_entry->nickname); + xfer->client_entry->nickname); if (!xfer->xfer) { - silc_client_file_close(xfer->sg->client, xfer->sg->conn, xfer->session_id); - g_free(xfer->hostname); silc_free(xfer); return NULL; } @@ -393,7 +469,6 @@ xfer->xfer->data = xfer; silc_free(clients); - silc_free(nickname); return xfer->xfer; }
--- a/libpurple/protocols/silc/ops.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/silc/ops.c Mon Jun 18 01:48:35 2007 +0000 @@ -4,7 +4,7 @@ Author: Pekka Riikonen <priikone@silcnet.org> - Copyright (C) 2004 Pekka Riikonen + Copyright (C) 2004 - 2007 Pekka Riikonen 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 @@ -17,7 +17,7 @@ */ -#include "silcincludes.h" +#include "silc.h" #include "silcclient.h" #include "silcpurple.h" #include "imgstore.h" @@ -26,14 +26,18 @@ static void silc_channel_message(SilcClient client, SilcClientConnection conn, SilcClientEntry sender, SilcChannelEntry channel, - SilcMessagePayload payload, SilcChannelPrivateKey key, - SilcMessageFlags flags, const unsigned char *message, + SilcMessagePayload payload, + SilcChannelPrivateKey key, SilcMessageFlags flags, + const unsigned char *message, SilcUInt32 message_len); static void silc_private_message(SilcClient client, SilcClientConnection conn, SilcClientEntry sender, SilcMessagePayload payload, SilcMessageFlags flags, const unsigned char *message, SilcUInt32 message_len); +static void +silc_ask_passphrase(SilcClient client, SilcClientConnection conn, + SilcAskPassphrase completion, void *context); /* Message sent to the application by library. `conn' associates the message to a specific connection. `conn', however, may be NULL. @@ -41,23 +45,31 @@ The application can for example filter the message according the type. */ -static void -silc_say(SilcClient client, SilcClientConnection conn, - SilcClientMessageType type, char *msg, ...) +void silc_say(SilcClient client, SilcClientConnection conn, + SilcClientMessageType type, char *msg, ...) { - /* Nothing */ + if (type == SILC_CLIENT_MESSAGE_ERROR) { + char tmp[256]; + va_list va; + + va_start(va, msg); + silc_vsnprintf(tmp, sizeof(tmp), msg, va); + purple_notify_error(NULL, _("Error"), _("Error occurred"), tmp); + + va_end(va); + return; + } } -#ifdef HAVE_SILCMIME_H /* Processes incoming MIME message. Can be private message or channel - message. */ + message. Returns TRUE if the message `mime' was displayed. */ -static void +static SilcBool silcpurple_mime_message(SilcClient client, SilcClientConnection conn, - SilcClientEntry sender, SilcChannelEntry channel, - SilcMessagePayload payload, SilcChannelPrivateKey key, - SilcMessageFlags flags, SilcMime mime, - gboolean recursive) + SilcClientEntry sender, SilcChannelEntry channel, + SilcMessagePayload payload, SilcChannelPrivateKey key, + SilcMessageFlags flags, SilcMime mime, + gboolean recursive) { PurpleConnection *gc = client->application; SilcPurple sg = gc->proto_data; @@ -66,9 +78,10 @@ SilcUInt32 data_len; PurpleMessageFlags cflags = 0; PurpleConversation *convo = NULL; + SilcBool ret = FALSE; if (!mime) - return; + return FALSE; /* Check for fragmented MIME message */ if (silc_mime_is_partial(mime)) { @@ -79,12 +92,12 @@ mime = silc_mime_assemble(sg->mimeass, mime); if (!mime) /* More fragments to come */ - return; + return FALSE; /* Process the complete message */ - silcpurple_mime_message(client, conn, sender, channel, - payload, key, flags, mime, FALSE); - return; + return silcpurple_mime_message(client, conn, sender, channel, + payload, key, flags, mime, + FALSE); } /* Check for multipart message */ @@ -92,17 +105,33 @@ SilcMime p; const char *mtype; SilcDList parts = silc_mime_get_multiparts(mime, &mtype); + SilcBool ret; - /* Only "mixed" type supported */ - if (strcmp(mtype, "mixed")) - goto out; + if (!strcmp(mtype, "mixed")) { + /* Contains multiple messages */ + silc_dlist_start(parts); + while ((p = silc_dlist_get(parts)) != SILC_LIST_END) { + /* Recursively process parts */ + ret = silcpurple_mime_message(client, conn, sender, channel, + payload, key, flags, p, TRUE); + } + } - silc_dlist_start(parts); - while ((p = silc_dlist_get(parts)) != SILC_LIST_END) { - /* Recursively process parts */ - silcpurple_mime_message(client, conn, sender, channel, - payload, key, flags, p, TRUE); + if (!strcmp(mtype, "alternative")) { + /* Same message in alternative formats. Kopete sends + these. Go in order from last to first. */ + silc_dlist_end(parts); + while ((p = silc_dlist_get(parts)) != SILC_LIST_END) { + /* Go through the alternatives and display the first + one we support. */ + if (silcpurple_mime_message(client, conn, sender, channel, + payload, key, flags, p, TRUE)) { + ret = TRUE; + break; + } + } } + goto out; } @@ -124,13 +153,14 @@ if (channel) silc_channel_message(client, conn, sender, channel, - payload, key, + payload, key, SILC_MESSAGE_FLAG_UTF8, data, data_len); else silc_private_message(client, conn, sender, payload, SILC_MESSAGE_FLAG_UTF8, data, data_len); + ret = TRUE; goto out; } @@ -157,7 +187,7 @@ } if (channel && !convo) convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, - channel->channel_name, sg->account); + channel->channel_name, sg->account); if (channel && !convo) goto out; @@ -165,11 +195,11 @@ if (imgid) { cflags |= PURPLE_MESSAGE_IMAGES | PURPLE_MESSAGE_RECV; g_snprintf(tmp, sizeof(tmp), "<IMG ID=\"%d\">", imgid); - + if (channel) serv_got_chat_in(gc, purple_conv_chat_get_id(PURPLE_CONV_CHAT(convo)), sender->nickname ? - sender->nickname : + sender->nickname : "<unknown>", cflags, tmp, time(NULL)); else @@ -179,6 +209,7 @@ purple_imgstore_unref_by_id(imgid); cflags = 0; + ret = TRUE; } goto out; } @@ -191,15 +222,16 @@ payload, flags, data, data_len); else silcpurple_wb_receive(client, conn, sender, payload, - flags, data, data_len); + flags, data, data_len); + ret = TRUE; goto out; } out: if (!recursive) silc_mime_free(mime); + return ret; } -#endif /* HAVE_SILCMIME_H */ /* Message for a channel. The `sender' is the sender of the message The `channel' is the channel. The `message' is the message. Note @@ -210,8 +242,9 @@ static void silc_channel_message(SilcClient client, SilcClientConnection conn, SilcClientEntry sender, SilcChannelEntry channel, - SilcMessagePayload payload, SilcChannelPrivateKey key, - SilcMessageFlags flags, const unsigned char *message, + SilcMessagePayload payload, + SilcChannelPrivateKey key, SilcMessageFlags flags, + const unsigned char *message, SilcUInt32 message_len) { PurpleConnection *gc = client->application; @@ -236,7 +269,7 @@ } if (!convo) convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, - channel->channel_name, sg->account); + channel->channel_name, sg->account); if (!convo) return; @@ -247,30 +280,10 @@ if (flags & SILC_MESSAGE_FLAG_DATA) { /* Process MIME message */ -#ifdef HAVE_SILCMIME_H SilcMime mime; - mime = silc_mime_decode(message, message_len); + mime = silc_mime_decode(NULL, message, message_len); silcpurple_mime_message(client, conn, sender, channel, payload, - key, flags, mime, FALSE); -#else - char type[128], enc[128]; - unsigned char *data; - SilcUInt32 data_len; - - memset(type, 0, sizeof(type)); - memset(enc, 0, sizeof(enc)); - - if (!silc_mime_parse(message, message_len, NULL, 0, - type, sizeof(type) - 1, enc, sizeof(enc) - 1, &data, - &data_len)) - return; - - if (!strcmp(type, "application/x-wb") && - !strcmp(enc, "binary") && - !purple_account_get_bool(sg->account, "block-wb", FALSE)) - silcpurple_wb_receive_ch(client, conn, sender, channel, - payload, flags, data, data_len); -#endif + key, flags, mime, FALSE); return; } @@ -283,9 +296,7 @@ tmp = g_markup_escape_text(msg, -1); /* Send to Purple */ serv_got_chat_in(gc, purple_conv_chat_get_id(PURPLE_CONV_CHAT(convo)), - sender->nickname ? - sender->nickname : "<unknown>", 0, - tmp, time(NULL)); + sender->nickname, 0, tmp, time(NULL)); g_free(tmp); g_free(msg); return; @@ -293,9 +304,7 @@ if (flags & SILC_MESSAGE_FLAG_NOTICE) { msg = g_strdup_printf("(notice) <I>%s</I> %s", - sender->nickname ? - sender->nickname : "<unknown>", - (const char *)message); + sender->nickname, (const char *)message); if (!msg) return; @@ -310,9 +319,7 @@ tmp = g_markup_escape_text((const char *)message, -1); /* Send to Purple */ serv_got_chat_in(gc, purple_conv_chat_get_id(PURPLE_CONV_CHAT(convo)), - sender->nickname ? - sender->nickname : "<unknown>", 0, - tmp, time(NULL)); + sender->nickname, 0, tmp, time(NULL)); g_free(tmp); } } @@ -341,7 +348,7 @@ if (sender->nickname) /* XXX - Should this be PURPLE_CONV_TYPE_IM? */ convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_ANY, - sender->nickname, sg->account); + sender->nickname, sg->account); if (flags & SILC_MESSAGE_FLAG_SIGNED && purple_account_get_bool(sg->account, "sign-verify", FALSE)) { @@ -349,31 +356,11 @@ } if (flags & SILC_MESSAGE_FLAG_DATA) { -#ifdef HAVE_SILCMIME_H /* Process MIME message */ SilcMime mime; - mime = silc_mime_decode(message, message_len); + mime = silc_mime_decode(NULL, message, message_len); silcpurple_mime_message(client, conn, sender, NULL, payload, NULL, flags, mime, FALSE); -#else - char type[128], enc[128]; - unsigned char *data; - SilcUInt32 data_len; - - memset(type, 0, sizeof(type)); - memset(enc, 0, sizeof(enc)); - - if (!silc_mime_parse(message, message_len, NULL, 0, - type, sizeof(type) - 1, enc, sizeof(enc) - 1, &data, - &data_len)) - return; - - if (!strcmp(type, "application/x-wb") && - !strcmp(enc, "binary") && - !purple_account_get_bool(sg->account, "block-wb", FALSE)) - silcpurple_wb_receive(client, conn, sender, payload, - flags, data, data_len); -#endif return; } @@ -383,11 +370,9 @@ if (!msg) return; + /* Send to Purple */ tmp = g_markup_escape_text(msg, -1); - /* Send to Purple */ - serv_got_im(gc, sender->nickname ? - sender->nickname : "<unknown>", - tmp, 0, time(NULL)); + serv_got_im(gc, sender->nickname, tmp, 0, time(NULL)); g_free(msg); g_free(tmp); return; @@ -395,15 +380,13 @@ if (flags & SILC_MESSAGE_FLAG_NOTICE && convo) { msg = g_strdup_printf("(notice) <I>%s</I> %s", - sender->nickname ? - sender->nickname : "<unknown>", - (const char *)message); + sender->nickname, (const char *)message); if (!msg) return; /* Send to Purple */ purple_conversation_write(convo, NULL, (const char *)msg, - PURPLE_MESSAGE_SYSTEM, time(NULL)); + PURPLE_MESSAGE_SYSTEM, time(NULL)); g_free(msg); return; } @@ -411,9 +394,7 @@ if (flags & SILC_MESSAGE_FLAG_UTF8) { tmp = g_markup_escape_text((const char *)message, -1); /* Send to Purple */ - serv_got_im(gc, sender->nickname ? - sender->nickname : "<unknown>", - tmp, 0, time(NULL)); + serv_got_im(gc, sender->nickname, tmp, 0, time(NULL)); g_free(tmp); } } @@ -447,6 +428,7 @@ char buf[512], buf2[512], *tmp, *name; SilcNotifyType notify; PurpleBuddy *b; + SilcDList list; int i; va_start(va, type); @@ -460,7 +442,7 @@ case SILC_NOTIFY_TYPE_INVITE: { GHashTable *components; - va_arg(va, SilcChannelEntry); + (void)va_arg(va, SilcChannelEntry); name = va_arg(va, char *); client_entry = va_arg(va, SilcClientEntry); @@ -479,7 +461,7 @@ break; convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, - channel->channel_name, sg->account); + channel->channel_name, sg->account); if (!convo) break; @@ -487,7 +469,7 @@ g_snprintf(buf, sizeof(buf), "%s@%s", client_entry->username, client_entry->hostname); purple_conv_chat_add_user(PURPLE_CONV_CHAT(convo), - g_strdup(client_entry->nickname), buf, PURPLE_CBFLAGS_NONE, TRUE); + g_strdup(client_entry->nickname), buf, PURPLE_CBFLAGS_NONE, TRUE); break; @@ -496,13 +478,13 @@ channel = va_arg(va, SilcChannelEntry); convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, - channel->channel_name, sg->account); + channel->channel_name, sg->account); if (!convo) break; /* Remove user from channel */ purple_conv_chat_remove_user(PURPLE_CONV_CHAT(convo), - client_entry->nickname, NULL); + client_entry->nickname, NULL); break; @@ -510,19 +492,16 @@ client_entry = va_arg(va, SilcClientEntry); tmp = va_arg(va, char *); - if (!client_entry->nickname) - break; - /* Remove from all channels */ silc_hash_table_list(client_entry->channels, &htl); while (silc_hash_table_get(&htl, NULL, (void *)&chu)) { convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, - chu->channel->channel_name, sg->account); + chu->channel->channel_name, sg->account); if (!convo) continue; purple_conv_chat_remove_user(PURPLE_CONV_CHAT(convo), - client_entry->nickname, - tmp); + client_entry->nickname, + tmp); } silc_hash_table_list_reset(&htl); @@ -537,7 +516,7 @@ channel = va_arg(va, SilcChannelEntry); convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, - channel->channel_name, sg->account); + channel->channel_name, sg->account); if (!convo) break; @@ -586,22 +565,22 @@ } case SILC_NOTIFY_TYPE_NICK_CHANGE: client_entry = va_arg(va, SilcClientEntry); - client_entry2 = va_arg(va, SilcClientEntry); + tmp = va_arg(va, char *); /* Old nick */ + name = va_arg(va, char *); /* New nick */ - if (!strcmp(client_entry->nickname, client_entry2->nickname)) + if (!strcmp(tmp, name)) break; /* Change nick on all channels */ - silc_hash_table_list(client_entry2->channels, &htl); + silc_hash_table_list(client_entry->channels, &htl); while (silc_hash_table_get(&htl, NULL, (void *)&chu)) { convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, - chu->channel->channel_name, sg->account); + chu->channel->channel_name, sg->account); if (!convo) continue; if (purple_conv_chat_find_user(PURPLE_CONV_CHAT(convo), client_entry->nickname)) purple_conv_chat_rename_user(PURPLE_CONV_CHAT(convo), - client_entry->nickname, - client_entry2->nickname); + tmp, name); } silc_hash_table_list_reset(&htl); @@ -615,11 +594,11 @@ (void)va_arg(va, char *); (void)va_arg(va, char *); (void)va_arg(va, SilcPublicKey); - (void)va_arg(va, SilcBuffer); + (void)va_arg(va, SilcDList); channel = va_arg(va, SilcChannelEntry); convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, - channel->channel_name, sg->account); + channel->channel_name, sg->account); if (!convo) break; @@ -643,7 +622,7 @@ channel->channel_name); } purple_conv_chat_write(PURPLE_CONV_CHAT(convo), channel->channel_name, - buf, PURPLE_MESSAGE_SYSTEM, time(NULL)); + buf, PURPLE_MESSAGE_SYSTEM, time(NULL)); break; case SILC_NOTIFY_TYPE_CUMODE_CHANGE: @@ -656,7 +635,7 @@ channel = va_arg(va, SilcChannelEntry); convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, - channel->channel_name, sg->account); + channel->channel_name, sg->account); if (!convo) break; @@ -672,19 +651,19 @@ if (mode) { silcpurple_get_chumode_string(mode, buf2, sizeof(buf2)); g_snprintf(buf, sizeof(buf), - _("<I>%s</I> set <I>%s's</I> modes to: %s"), name, - client_entry2->nickname, buf2); + _("<I>%s</I> set <I>%s's</I> modes to: %s"), name, + client_entry2->nickname, buf2); if (mode & SILC_CHANNEL_UMODE_CHANFO) flags |= PURPLE_CBFLAGS_FOUNDER; if (mode & SILC_CHANNEL_UMODE_CHANOP) flags |= PURPLE_CBFLAGS_OP; } else { g_snprintf(buf, sizeof(buf), - _("<I>%s</I> removed all <I>%s's</I> modes"), name, - client_entry2->nickname); + _("<I>%s</I> removed all <I>%s's</I> modes"), name, + client_entry2->nickname); } purple_conv_chat_write(PURPLE_CONV_CHAT(convo), channel->channel_name, - buf, PURPLE_MESSAGE_SYSTEM, time(NULL)); + buf, PURPLE_MESSAGE_SYSTEM, time(NULL)); purple_conv_chat_user_set_flags(PURPLE_CONV_CHAT(convo), client_entry2->nickname, flags); break; } @@ -702,7 +681,7 @@ channel = va_arg(va, SilcChannelEntry); convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, - channel->channel_name, sg->account); + channel->channel_name, sg->account); if (!convo) break; @@ -713,15 +692,15 @@ channel->channel_name, client_entry2->nickname, tmp ? tmp : ""); purple_conv_chat_write(PURPLE_CONV_CHAT(convo), client_entry->nickname, - buf, PURPLE_MESSAGE_SYSTEM, time(NULL)); + buf, PURPLE_MESSAGE_SYSTEM, time(NULL)); serv_got_chat_left(gc, purple_conv_chat_get_id(PURPLE_CONV_CHAT(convo))); } else { /* Remove user from channel */ g_snprintf(buf, sizeof(buf), _("Kicked by %s (%s)"), client_entry2->nickname, tmp ? tmp : ""); purple_conv_chat_remove_user(PURPLE_CONV_CHAT(convo), - client_entry->nickname, - buf); + client_entry->nickname, + buf); } break; @@ -732,9 +711,6 @@ idtype = va_arg(va, int); entry = va_arg(va, SilcClientEntry); - if (!client_entry->nickname) - break; - if (client_entry == conn->local_entry) { if (idtype == SILC_ID_CLIENT) { client_entry2 = (SilcClientEntry)entry; @@ -761,7 +737,7 @@ if (!convo) continue; purple_conv_chat_write(PURPLE_CONV_CHAT(convo), client_entry->nickname, - buf, PURPLE_MESSAGE_SYSTEM, time(NULL)); + buf, PURPLE_MESSAGE_SYSTEM, time(NULL)); serv_got_chat_left(gc, purple_conv_chat_get_id(PURPLE_CONV_CHAT(convo))); } silc_hash_table_list_reset(&htl); @@ -792,7 +768,7 @@ if (!convo) continue; purple_conv_chat_remove_user(PURPLE_CONV_CHAT(convo), - client_entry->nickname, tmp); + client_entry->nickname, tmp); } silc_hash_table_list_reset(&htl); } @@ -803,33 +779,23 @@ break; case SILC_NOTIFY_TYPE_SERVER_SIGNOFF: - { - int i; - SilcClientEntry *clients; - SilcUInt32 clients_count; - - (void)va_arg(va, void *); - clients = va_arg(va, SilcClientEntry *); - clients_count = va_arg(va, SilcUInt32); - - for (i = 0; i < clients_count; i++) { - if (!clients[i]->nickname) - break; + (void)va_arg(va, void *); + list = va_arg(va, SilcDList); - /* Remove from all channels */ - silc_hash_table_list(clients[i]->channels, &htl); - while (silc_hash_table_get(&htl, NULL, (void *)&chu)) { - convo = - purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, - chu->channel->channel_name, sg->account); - if (!convo) - continue; - purple_conv_chat_remove_user(PURPLE_CONV_CHAT(convo), - clients[i]->nickname, - _("Server signoff")); - } - silc_hash_table_list_reset(&htl); + silc_dlist_start(list); + while ((client_entry = silc_dlist_get(list))) { + /* Remove from all channels */ + silc_hash_table_list(client_entry->channels, &htl); + while (silc_hash_table_get(&htl, NULL, (void *)&chu)) { + convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, + chu->channel->channel_name, sg->account); + if (!convo) + continue; + purple_conv_chat_remove_user(PURPLE_CONV_CHAT(convo), + client_entry->nickname, + _("Server signoff")); } + silc_hash_table_list_reset(&htl); } break; @@ -837,8 +803,8 @@ { SilcStatus error = va_arg(va, int); purple_notify_error(gc, "Error Notify", - silc_get_status_message(error), - NULL); + silc_get_status_message(error), + NULL); } break; @@ -909,8 +875,8 @@ } silc_free(b->proto_data); - b->proto_data = silc_memdup(client_entry->id, - sizeof(*client_entry->id)); + b->proto_data = silc_memdup(&client_entry->id, + sizeof(client_entry->id)); if (notify == SILC_NOTIFY_TYPE_NICK_CHANGE) { break; } else if (notify == SILC_NOTIFY_TYPE_UMODE_CHANGE) { @@ -955,19 +921,20 @@ } -/* Command handler. This function is called always in the command function. - If error occurs it will be called as well. `conn' is the associated - client connection. `cmd_context' is the command context that was - originally sent to the command. `success' is FALSE if error occurred - during command. `command' is the command being processed. It must be - noted that this is not reply from server. This is merely called just - after application has called the command. Just to tell application - that the command really was processed. */ +/* Command handler. This function is called always after application has + called a command. It will be called to indicate that the command + was processed. It will also be called if error occurs while processing + the command. The `success' indicates whether the command was sent + or if error occurred. The `status' indicates the actual error. + The `argc' and `argv' are the command line arguments sent to the + command by application. Note that, this is not reply to the command + from server, this is merely and indication to application that the + command was processed. */ static void silc_command(SilcClient client, SilcClientConnection conn, - SilcClientCommandContext cmd_context, bool success, - SilcCommand command, SilcStatus status) + SilcBool success, SilcCommand command, SilcStatus status, + SilcUInt32 argc, unsigned char **argv) { PurpleConnection *gc = client->application; SilcPurple sg = gc->proto_data; @@ -975,8 +942,7 @@ switch (command) { case SILC_COMMAND_CMODE: - if (cmd_context->argc == 3 && - !strcmp((char *)cmd_context->argv[2], "+C")) + if (argc == 3 && !strcmp((char *)argv[2], "+C")) sg->chpk = TRUE; else sg->chpk = FALSE; @@ -1090,53 +1056,96 @@ } #endif -/* Command reply handler. This function is called always in the command reply - function. If error occurs it will be called as well. Normal scenario - is that it will be called after the received command data has been parsed - and processed. The function is used to pass the received command data to - the application. - `conn' is the associated client connection. `cmd_payload' is the command - payload data received from server and it can be ignored. It is provided - if the application would like to re-parse the received command data, - however, it must be noted that the data is parsed already by the library - thus the payload can be ignored. `success' is FALSE if error occurred. - In this case arguments are not sent to the application. The `status' is - the command reply status server returned. The `command' is the command - reply being processed. The function has variable argument list and each - command defines the number and type of arguments it passes to the - application (on error they are not sent). */ +/* Command reply handler. Delivers a reply to command that was sent + earlier. The `conn' is the associated client connection. The `command' + indicates the command reply type. If the `status' other than + SILC_STATUS_OK an error occurred. In this case the `error' will indicate + the error. It is possible to receive list of command replies and list + of errors. In this case the `status' will indicate it is an list entry + (the `status' is SILC_STATUS_LIST_START, SILC_STATUS_LIST_ITEM and/or + SILC_STATUS_LIST_END). + + The arguments received in `ap' are command specific. See a separate + documentation in the Toolkit Reference Manual for the command reply + arguments. */ static void silc_command_reply(SilcClient client, SilcClientConnection conn, - SilcCommandPayload cmd_payload, bool success, - SilcCommand command, SilcStatus status, ...) + SilcCommand command, SilcStatus status, + SilcStatus error, va_list ap) { PurpleConnection *gc = client->application; SilcPurple sg = gc->proto_data; PurpleConversation *convo; - va_list vp; - - va_start(vp, status); switch (command) { case SILC_COMMAND_JOIN: { - SilcChannelEntry channel_entry; + SilcChannelEntry channel; + PurpleConversation *convo; + SilcHashTableList *user_list; + SilcChannelUser chu; + GList *users = NULL, *flags = NULL; + char tmp[256], *topic; - if (!success) { + if (status != SILC_STATUS_OK) { purple_notify_error(gc, _("Join Chat"), _("Cannot join channel"), - silc_get_status_message(status)); + silc_get_status_message(error)); return; } - (void)va_arg(vp, char *); - channel_entry = va_arg(vp, SilcChannelEntry); + (void)va_arg(ap, char *); + channel = va_arg(ap, SilcChannelEntry); + (void)va_arg(ap, SilcUInt32); + user_list = va_arg(ap, SilcHashTableList *); + topic = va_arg(ap, char *); + + /* Add channel to Purple */ + channel->context = SILC_32_TO_PTR(++sg->channel_ids); + serv_got_joined_chat(gc, sg->channel_ids, channel->channel_name); + convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, + channel->channel_name, sg->account); + if (!convo) + return; + + /* Add all users to channel */ + while (silc_hash_table_get(user_list, NULL, (void *)&chu)) { + PurpleConvChatBuddyFlags f = PURPLE_CBFLAGS_NONE; + chu->context = SILC_32_TO_PTR(sg->channel_ids); + + if (chu->mode & SILC_CHANNEL_UMODE_CHANFO) + f |= PURPLE_CBFLAGS_FOUNDER; + if (chu->mode & SILC_CHANNEL_UMODE_CHANOP) + f |= PURPLE_CBFLAGS_OP; + users = g_list_append(users, g_strdup(chu->client->nickname)); + flags = g_list_append(flags, GINT_TO_POINTER(f)); - /* Resolve users on channel */ - silc_client_get_clients_by_channel(client, conn, channel_entry, - silcpurple_chat_join_done, - channel_entry); + if (chu->mode & SILC_CHANNEL_UMODE_CHANFO) { + if (chu->client == conn->local_entry) + g_snprintf(tmp, sizeof(tmp), + _("You are channel founder on <I>%s</I>"), + channel->channel_name); + else + g_snprintf(tmp, sizeof(tmp), + _("Channel founder on <I>%s</I> is <I>%s</I>"), + channel->channel_name, chu->client->nickname); + + purple_conversation_write(convo, NULL, tmp, + PURPLE_MESSAGE_SYSTEM, time(NULL)); + } + } + + purple_conv_chat_add_users(PURPLE_CONV_CHAT(convo), users, NULL, flags, FALSE); + g_list_free(users); + g_list_free(flags); + + /* Set topic */ + if (topic) + purple_conv_chat_set_topic(PURPLE_CONV_CHAT(convo), NULL, topic); + + /* Set nick */ + purple_conv_chat_set_nick(PURPLE_CONV_CHAT(convo), conn->local_entry->nickname); } break; @@ -1148,31 +1157,29 @@ case SILC_COMMAND_WHOIS: { - SilcUInt32 idle, mode; - SilcBuffer channels, user_modes; + SilcUInt32 idle, *user_modes; + SilcDList channels; SilcClientEntry client_entry; char tmp[1024], *tmp2; char *moodstr, *statusstr, *contactstr, *langstr, *devicestr, *tzstr, *geostr; PurpleNotifyUserInfo *user_info; - if (!success) { + if (status != SILC_STATUS_OK) { purple_notify_error(gc, _("User Information"), _("Cannot get user information"), - silc_get_status_message(status)); + silc_get_status_message(error)); break; } - client_entry = va_arg(vp, SilcClientEntry); - if (!client_entry->nickname) - break; - (void)va_arg(vp, char *); - (void)va_arg(vp, char *); - (void)va_arg(vp, char *); - channels = va_arg(vp, SilcBuffer); - mode = va_arg(vp, SilcUInt32); - idle = va_arg(vp, SilcUInt32); - (void)va_arg(vp, unsigned char *); - user_modes = va_arg(vp, SilcBuffer); + client_entry = va_arg(ap, SilcClientEntry); + (void)va_arg(ap, char *); + (void)va_arg(ap, char *); + (void)va_arg(ap, char *); + channels = va_arg(ap, SilcDList); + (void)va_arg(ap, SilcUInt32); + idle = va_arg(ap, SilcUInt32); + (void)va_arg(ap, unsigned char *); + user_modes = va_arg(ap, SilcUInt32 *); user_info = purple_notify_user_info_new(); tmp2 = g_markup_escape_text(client_entry->nickname, -1); @@ -1183,22 +1190,20 @@ purple_notify_user_info_add_pair(user_info, _("Real Name"), tmp2); g_free(tmp2); } - if (client_entry->username) { - tmp2 = g_markup_escape_text(client_entry->username, -1); - if (client_entry->hostname) { - gchar *tmp3; - tmp3 = g_strdup_printf("%s@%s", tmp2, client_entry->hostname); - purple_notify_user_info_add_pair(user_info, _("Username"), tmp3); - g_free(tmp3); - } else - purple_notify_user_info_add_pair(user_info, _("Username"), tmp2); - g_free(tmp2); - } + tmp2 = g_markup_escape_text(client_entry->username, -1); + if (*client_entry->hostname) { + gchar *tmp3; + tmp3 = g_strdup_printf("%s@%s", tmp2, client_entry->hostname); + purple_notify_user_info_add_pair(user_info, _("Username"), tmp3); + g_free(tmp3); + } else + purple_notify_user_info_add_pair(user_info, _("Username"), tmp2); + g_free(tmp2); if (client_entry->mode) { memset(tmp, 0, sizeof(tmp)); silcpurple_get_umode_string(client_entry->mode, - tmp, sizeof(tmp) - strlen(tmp)); + tmp, sizeof(tmp) - strlen(tmp)); purple_notify_user_info_add_pair(user_info, _("User Modes"), tmp); } @@ -1240,39 +1245,28 @@ g_free(geostr); } - if (client_entry->server) + if (*client_entry->server) purple_notify_user_info_add_pair(user_info, _("Server"), client_entry->server); if (channels && user_modes) { - SilcUInt32 *umodes; - SilcDList list = - silc_channel_payload_parse_list(channels->data, - channels->len); - if (list && silc_get_mode_list(user_modes, - silc_dlist_count(list), - &umodes)) { - SilcChannelPayload entry; - int i = 0; + SilcChannelPayload entry; + int i = 0; - memset(tmp, 0, sizeof(tmp)); - silc_dlist_start(list); - while ((entry = silc_dlist_get(list)) - != SILC_LIST_END) { - SilcUInt32 name_len; - char *m = silc_client_chumode_char(umodes[i++]); - char *name = (char *)silc_channel_get_name(entry, &name_len); - if (m) - silc_strncat(tmp, sizeof(tmp) - 1, m, strlen(m)); - silc_strncat(tmp, sizeof(tmp) - 1, name, name_len); - silc_strncat(tmp, sizeof(tmp) - 1, " ", 1); - silc_free(m); - - } - tmp2 = g_markup_escape_text(tmp, -1); - purple_notify_user_info_add_pair(user_info, _("Currently on"), tmp2); - g_free(tmp2); - silc_free(umodes); + memset(tmp, 0, sizeof(tmp)); + silc_dlist_start(channels); + while ((entry = silc_dlist_get(channels))) { + SilcUInt32 name_len; + char *m = silc_client_chumode_char(user_modes[i++]); + char *name = (char *)silc_channel_get_name(entry, &name_len); + if (m) + silc_strncat(tmp, sizeof(tmp) - 1, m, strlen(m)); + silc_strncat(tmp, sizeof(tmp) - 1, name, name_len); + silc_strncat(tmp, sizeof(tmp) - 1, " ", 1); + silc_free(m); } + tmp2 = g_markup_escape_text(tmp, -1); + purple_notify_user_info_add_pair(user_info, _("Currently on"), tmp2); + g_free(tmp2); } if (client_entry->public_key) { @@ -1297,7 +1291,7 @@ _("OK"), G_CALLBACK(silcpurple_whois_more), _("_More..."), G_CALLBACK(silcpurple_whois_more), gc->account, NULL, NULL); else -#endif +#endif /* 0 */ purple_notify_userinfo(gc, client_entry->nickname, user_info, NULL, NULL); purple_notify_user_info_destroy(user_info); } @@ -1309,17 +1303,17 @@ char *nickname, *realname, *username, *tmp; PurpleNotifyUserInfo *user_info; - if (!success) { + if (status != SILC_STATUS_OK) { purple_notify_error(gc, _("User Information"), _("Cannot get user information"), - silc_get_status_message(status)); + silc_get_status_message(error)); break; } - client_entry = va_arg(vp, SilcClientEntry); - nickname = va_arg(vp, char *); - username = va_arg(vp, char *); - realname = va_arg(vp, char *); + client_entry = va_arg(ap, SilcClientEntry); + nickname = va_arg(ap, char *); + username = va_arg(ap, char *); + realname = va_arg(ap, char *); if (!nickname) break; @@ -1334,7 +1328,7 @@ } if (username) { tmp = g_markup_escape_text(username, -1); - if (client_entry && client_entry->hostname) { + if (client_entry && *client_entry->hostname) { gchar *tmp3; tmp3 = g_strdup_printf("%s@%s", tmp, client_entry->hostname); purple_notify_user_info_add_pair(user_info, _("Username"), tmp3); @@ -1343,7 +1337,7 @@ purple_notify_user_info_add_pair(user_info, _("Username"), tmp); g_free(tmp); } - if (client_entry && client_entry->server) + if (client_entry && *client_entry->server) purple_notify_user_info_add_pair(user_info, _("Server"), client_entry->server); @@ -1367,10 +1361,23 @@ break; case SILC_COMMAND_DETACH: - if (!success) { - purple_notify_error(gc, _("Detach From Server"), _("Cannot detach"), - silc_get_status_message(status)); - return; + { + const char *file; + SilcBuffer detach_data; + + if (status != SILC_STATUS_OK) { + purple_notify_error(gc, _("Detach From Server"), _("Cannot detach"), + silc_get_status_message(error)); + return; + } + + detach_data = va_arg(ap, SilcBuffer); + + /* Save the detachment data to file. */ + file = silcpurple_session_file(purple_account_get_username(sg->account)); + g_unlink(file); + silc_file_writefile(file, (const char *)silc_buffer_data(detach_data), + silc_buffer_len(detach_data)); } break; @@ -1378,19 +1385,19 @@ { SilcChannelEntry channel; - if (!success) { + if (status != SILC_STATUS_OK) { purple_notify_error(gc, _("Topic"), _("Cannot set topic"), - silc_get_status_message(status)); + silc_get_status_message(error)); return; } - channel = va_arg(vp, SilcChannelEntry); + channel = va_arg(ap, SilcChannelEntry); convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, - channel->channel_name, sg->account); + channel->channel_name, sg->account); if (!convo) { purple_debug_error("silc", "Got a topic for %s, which doesn't exist\n", - channel->channel_name); + channel->channel_name); break; } @@ -1402,39 +1409,37 @@ case SILC_COMMAND_NICK: { - /* I don't think we should need to do this because the server should - * be sending a SILC_NOTIFY_TYPE_NICK_CHANGE when we change our own - * nick, but it isn't, so we deal with it here instead. Stu. */ SilcClientEntry local_entry; SilcHashTableList htl; SilcChannelUser chu; - const char *oldnick; + const char *oldnick, *newnick; - if (!success) { + if (status != SILC_STATUS_OK) { purple_notify_error(gc, _("Nick"), _("Failed to change nickname"), - silc_get_status_message(status)); + silc_get_status_message(error)); return; } - local_entry = va_arg(vp, SilcClientEntry); + local_entry = va_arg(ap, SilcClientEntry); + newnick = va_arg(ap, char *); /* Change nick on all channels */ silc_hash_table_list(local_entry->channels, &htl); while (silc_hash_table_get(&htl, NULL, (void *)&chu)) { convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, - chu->channel->channel_name, sg->account); + chu->channel->channel_name, sg->account); if (!convo) continue; oldnick = purple_conv_chat_get_nick(PURPLE_CONV_CHAT(convo)); - if (strcmp(oldnick, purple_normalize(purple_conversation_get_account(convo), local_entry->nickname))) { + if (strcmp(oldnick, purple_normalize(purple_conversation_get_account(convo), newnick))) { purple_conv_chat_rename_user(PURPLE_CONV_CHAT(convo), - oldnick, local_entry->nickname); - purple_conv_chat_set_nick(PURPLE_CONV_CHAT(convo), local_entry->nickname); + oldnick, newnick); + purple_conv_chat_set_nick(PURPLE_CONV_CHAT(convo), newnick); } } silc_hash_table_list_reset(&htl); - purple_connection_set_display_name(gc, local_entry->nickname); + purple_connection_set_display_name(gc, newnick); } break; @@ -1447,34 +1452,34 @@ if (sg->roomlist_canceled) break; - if (!success) { + if (error != SILC_STATUS_OK) { purple_notify_error(gc, _("Error"), _("Error retrieving room list"), - silc_get_status_message(status)); + silc_get_status_message(error)); purple_roomlist_set_in_progress(sg->roomlist, FALSE); purple_roomlist_unref(sg->roomlist); sg->roomlist = NULL; return; } - (void)va_arg(vp, SilcChannelEntry); - name = va_arg(vp, char *); + (void)va_arg(ap, SilcChannelEntry); + name = va_arg(ap, char *); if (!name) { purple_notify_error(gc, _("Roomlist"), _("Cannot get room list"), - silc_get_status_message(status)); + _("Network is empty")); purple_roomlist_set_in_progress(sg->roomlist, FALSE); purple_roomlist_unref(sg->roomlist); sg->roomlist = NULL; return; } - topic = va_arg(vp, char *); - usercount = va_arg(vp, int); + topic = va_arg(ap, char *); + usercount = va_arg(ap, int); room = purple_roomlist_room_new(PURPLE_ROOMLIST_ROOMTYPE_ROOM, name, NULL); purple_roomlist_room_add_field(sg->roomlist, room, name); purple_roomlist_room_add_field(sg->roomlist, room, - SILC_32_TO_PTR(usercount)); + SILC_32_TO_PTR(usercount)); purple_roomlist_room_add_field(sg->roomlist, room, - topic ? topic : ""); + topic ? topic : ""); purple_roomlist_room_add(sg->roomlist, room); if (status == SILC_STATUS_LIST_END || @@ -1490,21 +1495,21 @@ { SilcPublicKey public_key; - if (!success) { + if (status != SILC_STATUS_OK) { purple_notify_error(gc, _("Get Public Key"), - _("Cannot fetch the public key"), - silc_get_status_message(status)); + _("Cannot fetch the public key"), + silc_get_status_message(error)); return; } - (void)va_arg(vp, SilcUInt32); - (void)va_arg(vp, void *); - public_key = va_arg(vp, SilcPublicKey); + (void)va_arg(ap, SilcUInt32); + (void)va_arg(ap, void *); + public_key = va_arg(ap, SilcPublicKey); if (!public_key) purple_notify_error(gc, _("Get Public Key"), - _("Cannot fetch the public key"), - _("No public key was received")); + _("Cannot fetch the public key"), + _("No public key was received")); } break; @@ -1515,16 +1520,16 @@ char *server_info; char tmp[256]; - if (!success) { + if (status != SILC_STATUS_OK) { purple_notify_error(gc, _("Server Information"), - _("Cannot get server information"), - silc_get_status_message(status)); + _("Cannot get server information"), + silc_get_status_message(error)); return; } - (void)va_arg(vp, SilcServerEntry); - server_name = va_arg(vp, char *); - server_info = va_arg(vp, char *); + (void)va_arg(ap, SilcServerEntry); + server_name = va_arg(ap, char *); + server_info = va_arg(ap, char *); if (server_name && server_info) { g_snprintf(tmp, sizeof(tmp), "Server: %s\n%s", @@ -1536,94 +1541,73 @@ case SILC_COMMAND_STATS: { - SilcUInt32 starttime, uptime, my_clients, my_channels, my_server_ops, - my_router_ops, cell_clients, cell_channels, cell_servers, - clients, channels, servers, routers, server_ops, router_ops; - SilcUInt32 buffer_length; - SilcBufferStruct buf; - - unsigned char *server_stats; + SilcClientStats *stats; char *msg; - if (!success) { + if (status != SILC_STATUS_OK) { purple_notify_error(gc, _("Server Statistics"), - _("Cannot get server statistics"), - silc_get_status_message(status)); + _("Cannot get server statistics"), + silc_get_status_message(error)); return; } - server_stats = va_arg(vp, unsigned char *); - buffer_length = va_arg(vp, SilcUInt32); - if (!server_stats || !buffer_length) { - purple_notify_error(gc, _("Server Statistics"), - _("No server statistics available"), NULL); - break; - } - silc_buffer_set(&buf, server_stats, buffer_length); - silc_buffer_unformat(&buf, - SILC_STR_UI_INT(&starttime), - SILC_STR_UI_INT(&uptime), - SILC_STR_UI_INT(&my_clients), - SILC_STR_UI_INT(&my_channels), - SILC_STR_UI_INT(&my_server_ops), - SILC_STR_UI_INT(&my_router_ops), - SILC_STR_UI_INT(&cell_clients), - SILC_STR_UI_INT(&cell_channels), - SILC_STR_UI_INT(&cell_servers), - SILC_STR_UI_INT(&clients), - SILC_STR_UI_INT(&channels), - SILC_STR_UI_INT(&servers), - SILC_STR_UI_INT(&routers), - SILC_STR_UI_INT(&server_ops), - SILC_STR_UI_INT(&router_ops), - SILC_STR_END); + stats = va_arg(ap, SilcClientStats *); msg = g_strdup_printf(_("Local server start time: %s\n" - "Local server uptime: %s\n" - "Local server clients: %d\n" - "Local server channels: %d\n" - "Local server operators: %d\n" - "Local router operators: %d\n" - "Local cell clients: %d\n" - "Local cell channels: %d\n" - "Local cell servers: %d\n" - "Total clients: %d\n" - "Total channels: %d\n" - "Total servers: %d\n" - "Total routers: %d\n" - "Total server operators: %d\n" - "Total router operators: %d\n"), - silc_get_time(starttime), - purple_str_seconds_to_string((int)uptime), - (int)my_clients, (int)my_channels, (int)my_server_ops, (int)my_router_ops, - (int)cell_clients, (int)cell_channels, (int)cell_servers, - (int)clients, (int)channels, (int)servers, (int)routers, - (int)server_ops, (int)router_ops); + "Local server uptime: %s\n" + "Local server clients: %d\n" + "Local server channels: %d\n" + "Local server operators: %d\n" + "Local router operators: %d\n" + "Local cell clients: %d\n" + "Local cell channels: %d\n" + "Local cell servers: %d\n" + "Total clients: %d\n" + "Total channels: %d\n" + "Total servers: %d\n" + "Total routers: %d\n" + "Total server operators: %d\n" + "Total router operators: %d\n"), + silc_time_string(stats->starttime), + purple_str_seconds_to_string((int)stats->uptime), + (int)stats->my_clients, + (int)stats->my_channels, + (int)stats->my_server_ops, + (int)stats->my_router_ops, + (int)stats->cell_clients, + (int)stats->cell_channels, + (int)stats->cell_servers, + (int)stats->clients, + (int)stats->channels, + (int)stats->servers, + (int)stats->routers, + (int)stats->server_ops, + (int)stats->router_ops); purple_notify_info(gc, NULL, - _("Network Statistics"), msg); + _("Network Statistics"), msg); g_free(msg); } break; case SILC_COMMAND_PING: { - if (!success) { + if (status != SILC_STATUS_OK) { purple_notify_error(gc, _("Ping"), _("Ping failed"), - silc_get_status_message(status)); + silc_get_status_message(error)); return; } purple_notify_info(gc, _("Ping"), _("Ping reply received from server"), - NULL); + NULL); } break; case SILC_COMMAND_KILL: - if (!success) { + if (status != SILC_STATUS_OK) { purple_notify_error(gc, _("Kill User"), - _("Could not kill user"), - silc_get_status_message(status)); + _("Could not kill user"), + silc_get_status_message(error)); return; } break; @@ -1631,188 +1615,108 @@ case SILC_COMMAND_CMODE: { SilcChannelEntry channel_entry; - SilcBuffer channel_pubkeys; + SilcDList channel_pubkeys, list; + SilcArgumentDecodedList e; - if (!success) + if (status != SILC_STATUS_OK) return; - channel_entry = va_arg(vp, SilcChannelEntry); - (void)va_arg(vp, SilcUInt32); - (void)va_arg(vp, SilcPublicKey); - channel_pubkeys = va_arg(vp, SilcBuffer); + channel_entry = va_arg(ap, SilcChannelEntry); + (void)va_arg(ap, SilcUInt32); + (void)va_arg(ap, SilcPublicKey); + channel_pubkeys = va_arg(ap, SilcDList); + + if (!sg->chpk) + break; + + list = silc_dlist_init(); - if (sg->chpk) - silcpurple_chat_chauth_show(sg, channel_entry, channel_pubkeys); + if (channel_pubkeys) { + silc_dlist_start(channel_pubkeys); + while ((e = silc_dlist_get(channel_pubkeys))) { + if (e->arg_type == 0x00 || + e->arg_type == 0x03) + silc_dlist_add(list, silc_pkcs_public_key_copy(e->argument)); + } + } + silcpurple_chat_chauth_show(sg, channel_entry, list); + } + break; + + case SILC_COMMAND_WATCH: + if (status != SILC_STATUS_OK) { + purple_notify_error(gc, _("WATCH"), _("Cannot watch user"), + silc_get_status_message(error)); + return; } break; default: - if (success) + if (status == SILC_STATUS_OK) purple_debug_info("silc", "Unhandled command: %d (succeeded)\n", command); else purple_debug_info("silc", "Unhandled command: %d (failed: %s)\n", command, - silc_get_status_message(status)); + silc_get_status_message(error)); break; } - - va_end(vp); } - -/* Called to indicate that connection was either successfully established - or connecting failed. This is also the first time application receives - the SilcClientConnection object which it should save somewhere. - If the `success' is FALSE the application must always call the function - silc_client_close_connection. */ - -static void -silc_connected(SilcClient client, SilcClientConnection conn, - SilcClientConnectionStatus status) -{ - PurpleConnection *gc = client->application; - SilcPurple sg; - gboolean reject_watch, block_invites, block_ims; - - if (gc == NULL) { - silc_client_close_connection(client, conn); - return; - } - sg = gc->proto_data; - - switch (status) { - case SILC_CLIENT_CONN_SUCCESS: - case SILC_CLIENT_CONN_SUCCESS_RESUME: - purple_connection_set_state(gc, PURPLE_CONNECTED); - - /* Send the server our buddy list */ - silcpurple_send_buddylist(gc); - - g_unlink(silcpurple_session_file(purple_account_get_username(sg->account))); - - /* Send any UMODEs configured for account */ - reject_watch = purple_account_get_bool(sg->account, "reject-watch", FALSE); - block_invites = purple_account_get_bool(sg->account, "block-invites", FALSE); - block_ims = purple_account_get_bool(sg->account, "block-ims", FALSE); - if (reject_watch || block_invites || block_ims) { - char m[5]; - g_snprintf(m, sizeof(m), "+%s%s%s", - reject_watch ? "w" : "", - block_invites ? "I" : "", - block_ims ? "P" : ""); - silc_client_command_call(sg->client, sg->conn, NULL, - "UMODE", m, NULL); - } +/* Generic command reply callback for silc_client_command_send. Simply + calls the default command_reply client operation callback */ - return; - break; - case SILC_CLIENT_CONN_ERROR: - purple_connection_error(gc, _("Error during connecting to SILC Server")); - g_unlink(silcpurple_session_file(purple_account_get_username(sg->account))); - break; - - case SILC_CLIENT_CONN_ERROR_KE: - purple_connection_error(gc, _("Key Exchange failed")); - break; - - case SILC_CLIENT_CONN_ERROR_AUTH: - purple_connection_error(gc, _("Authentication failed")); - break; - - case SILC_CLIENT_CONN_ERROR_RESUME: - purple_connection_error(gc, - _("Resuming detached session failed. " - "Press Reconnect to create new connection.")); - g_unlink(silcpurple_session_file(purple_account_get_username(sg->account))); - break; - - case SILC_CLIENT_CONN_ERROR_TIMEOUT: - purple_connection_error(gc, _("Connection Timeout")); - break; - } - - /* Error */ - sg->conn = NULL; - silc_client_close_connection(client, conn); -} - - -/* Called to indicate that connection was disconnected to the server. - The `status' may tell the reason of the disconnection, and if the - `message' is non-NULL it may include the disconnection message - received from server. */ - -static void -silc_disconnected(SilcClient client, SilcClientConnection conn, - SilcStatus status, const char *message) +SilcBool silcpurple_command_reply(SilcClient client, SilcClientConnection conn, + SilcCommand command, SilcStatus status, + SilcStatus error, void *context, va_list ap) { - PurpleConnection *gc = client->application; - SilcPurple sg = gc->proto_data; - - if (sg->resuming && !sg->detaching) - g_unlink(silcpurple_session_file(purple_account_get_username(sg->account))); - - sg->conn = NULL; - - /* Close the connection */ - if (!sg->detaching) - purple_connection_error(gc, _("Disconnected by server")); - else - /* TODO: Does this work correctly? Maybe we need to set wants_to_die? */ - purple_account_disconnect(purple_connection_get_account(gc)); + silc_command_reply(client, conn, command, status, error, ap); + return TRUE; } typedef struct { - SilcGetAuthMeth completion; + union { + SilcAskPassphrase ask_pass; + SilcGetAuthMeth get_auth; + } u; void *context; -} *SilcPurpleGetAuthMethod; - -/* Callback called when we've received the authentication method information - from the server after we've requested it. */ - -static void silc_get_auth_method_callback(SilcClient client, - SilcClientConnection conn, - SilcAuthMethod auth_meth, - void *context) -{ - SilcPurpleGetAuthMethod internal = context; +} *SilcPurpleAskPassphrase; - switch (auth_meth) { - case SILC_AUTH_NONE: - /* No authentication required. */ - (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context); - break; +static void +silc_ask_auth_password_cb(const unsigned char *passphrase, + SilcUInt32 passphrase_len, void *context) +{ + SilcPurpleAskPassphrase internal = context; - case SILC_AUTH_PASSWORD: - /* By returning NULL here the library will ask the passphrase from us - by calling the silc_ask_passphrase. */ - (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context); - break; - - case SILC_AUTH_PUBLIC_KEY: - /* Do not get the authentication data now, the library will generate - it using our default key, if we do not provide it here. */ - (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context); - break; - } - + if (!passphrase || !(*passphrase)) + internal->u.get_auth(SILC_AUTH_NONE, NULL, 0, internal->context); + else + internal->u.get_auth(SILC_AUTH_PASSWORD, + (unsigned char *)passphrase, + passphrase_len, internal->context); silc_free(internal); } /* Find authentication method and authentication data by hostname and - port. The hostname may be IP address as well. When the authentication - method has been resolved the `completion' callback with the found - authentication method and authentication data is called. The `conn' - may be NULL. */ + port. The hostname may be IP address as well. The `auth_method' is + the authentication method the remote connection requires. It is + however possible that remote accepts also some other authentication + method. Application should use the method that may have been + configured for this connection. If none has been configured it should + use the required `auth_method'. If the `auth_method' is + SILC_AUTH_NONE, server does not require any authentication or the + required authentication method is not known. The `completion' + callback must be called to deliver the chosen authentication method + and data. The `conn' may be NULL. */ static void silc_get_auth_method(SilcClient client, SilcClientConnection conn, char *hostname, SilcUInt16 port, + SilcAuthMethod auth_method, SilcGetAuthMeth completion, void *context) { PurpleConnection *gc = client->application; SilcPurple sg = gc->proto_data; - SilcPurpleGetAuthMethod internal; + SilcPurpleAskPassphrase internal; const char *password; /* Progress */ @@ -1821,72 +1725,71 @@ else purple_connection_update_progress(gc, _("Authenticating connection"), 4, 5); - /* Check configuration if we have this connection configured. If we - have then return that data immediately, as it's faster way. */ - if (purple_account_get_bool(sg->account, "pubkey-auth", FALSE)) { - completion(TRUE, SILC_AUTH_PUBLIC_KEY, NULL, 0, context); + /* Check configuration if we have this connection configured. */ + if (auth_method == SILC_AUTH_PUBLIC_KEY && + purple_account_get_bool(sg->account, "pubkey-auth", FALSE)) { + completion(SILC_AUTH_PUBLIC_KEY, NULL, 0, context); return; } - password = purple_connection_get_password(gc); - if (password && *password) { - completion(TRUE, SILC_AUTH_PASSWORD, (unsigned char *)password, strlen(password), context); + if (auth_method == SILC_AUTH_PASSWORD) { + password = purple_connection_get_password(gc); + if (password && *password) { + completion(SILC_AUTH_PASSWORD, (unsigned char *)password, strlen(password), context); + return; + } + + /* Ask password from user */ + internal = silc_calloc(1, sizeof(*internal)); + if (!internal) + return; + internal->u.get_auth = completion; + internal->context = context; + silc_ask_passphrase(client, conn, silc_ask_auth_password_cb, + internal); return; } - /* Resolve the authentication method from server, as we may not know it. */ - internal = silc_calloc(1, sizeof(*internal)); - if (!internal) - return; - internal->completion = completion; - internal->context = context; - silc_client_request_authentication_method(client, conn, - silc_get_auth_method_callback, - internal); + completion(SILC_AUTH_NONE, NULL, 0, context); } -/* Verifies received public key. The `conn_type' indicates which entity - (server, client etc.) has sent the public key. If user decides to trust - the application may save the key as trusted public key for later - use. The `completion' must be called after the public key has been - verified. */ +/* Called to verify received public key. The `conn_type' indicates which + entity (server or client) has sent the public key. If user decides to + trust the key the application may save the key as trusted public key for + later use. The `completion' must be called after the public key has + been verified. */ static void silc_verify_public_key(SilcClient client, SilcClientConnection conn, - SilcSocketType conn_type, unsigned char *pk, - SilcUInt32 pk_len, SilcSKEPKType pk_type, + SilcConnectionType conn_type, + SilcPublicKey public_key, SilcVerifyPublicKey completion, void *context) { PurpleConnection *gc = client->application; SilcPurple sg = gc->proto_data; - if (!sg->conn && (conn_type == SILC_SOCKET_TYPE_SERVER || - conn_type == SILC_SOCKET_TYPE_ROUTER)) { + if (!sg->conn && (conn_type == SILC_CONN_SERVER || + conn_type == SILC_CONN_ROUTER)) { /* Progress */ if (sg->resuming) purple_connection_update_progress(gc, _("Resuming session"), 3, 5); else purple_connection_update_progress(gc, _("Verifying server public key"), - 3, 5); + 3, 5); } /* Verify public key */ - silcpurple_verify_public_key(client, conn, NULL, conn_type, pk, - pk_len, pk_type, completion, context); + silcpurple_verify_public_key(client, conn, NULL, conn_type, + public_key, completion, context); } -typedef struct { - SilcAskPassphrase completion; - void *context; -} *SilcPurpleAskPassphrase; - static void silc_ask_passphrase_cb(SilcPurpleAskPassphrase internal, const char *passphrase) { if (!passphrase || !(*passphrase)) - internal->completion(NULL, 0, internal->context); + internal->u.ask_pass(NULL, 0, internal->context); else - internal->completion((unsigned char *)passphrase, + internal->u.ask_pass((unsigned char *)passphrase, strlen(passphrase), internal->context); silc_free(internal); } @@ -1905,97 +1808,32 @@ if (!internal) return; - internal->completion = completion; + internal->u.ask_pass = completion; internal->context = context; purple_request_input(gc, _("Passphrase"), NULL, - _("Passphrase required"), NULL, FALSE, TRUE, NULL, - _("OK"), G_CALLBACK(silc_ask_passphrase_cb), - _("Cancel"), G_CALLBACK(silc_ask_passphrase_cb), - purple_connection_get_account(gc), NULL, NULL, internal); + _("Passphrase required"), NULL, FALSE, TRUE, NULL, + _("OK"), G_CALLBACK(silc_ask_passphrase_cb), + _("Cancel"), G_CALLBACK(silc_ask_passphrase_cb), + purple_connection_get_account(gc), NULL, NULL, internal); } -/* Notifies application that failure packet was received. This is called - if there is some protocol active in the client. The `protocol' is the - protocol context. The `failure' is opaque pointer to the failure - indication. Note, that the `failure' is protocol dependant and - application must explicitly cast it to correct type. Usually `failure' - is 32 bit failure type (see protocol specs for all protocol failure - types). */ +/* Called to indicate that incoming key agreement request has been + received. If the application wants to perform key agreement it may + call silc_client_perform_key_agreement to initiate key agreement or + silc_client_send_key_agreement to provide connection point to the + remote client in case the `hostname' is NULL. If key agreement is + not desired this request can be ignored. The `protocol' is either + value 0 for TCP or value 1 for UDP. */ static void -silc_failure(SilcClient client, SilcClientConnection conn, - SilcProtocol protocol, void *failure) +silc_key_agreement(SilcClient client, SilcClientConnection conn, + SilcClientEntry client_entry, + const char *hostname, SilcUInt16 protocol, + SilcUInt16 port) { - PurpleConnection *gc = client->application; - char buf[128]; - - memset(buf, 0, sizeof(buf)); - - if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) { - SilcSKEStatus status = (SilcSKEStatus)SILC_PTR_TO_32(failure); - - if (status == SILC_SKE_STATUS_BAD_VERSION) - g_snprintf(buf, sizeof(buf), - _("Failure: Version mismatch, upgrade your client")); - if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY) - g_snprintf(buf, sizeof(buf), - _("Failure: Remote does not trust/support your public key")); - if (status == SILC_SKE_STATUS_UNKNOWN_GROUP) - g_snprintf(buf, sizeof(buf), - _("Failure: Remote does not support proposed KE group")); - if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER) - g_snprintf(buf, sizeof(buf), - _("Failure: Remote does not support proposed cipher")); - if (status == SILC_SKE_STATUS_UNKNOWN_PKCS) - g_snprintf(buf, sizeof(buf), - _("Failure: Remote does not support proposed PKCS")); - if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION) - g_snprintf(buf, sizeof(buf), - _("Failure: Remote does not support proposed hash function")); - if (status == SILC_SKE_STATUS_UNKNOWN_HMAC) - g_snprintf(buf, sizeof(buf), - _("Failure: Remote does not support proposed HMAC")); - if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE) - g_snprintf(buf, sizeof(buf), _("Failure: Incorrect signature")); - if (status == SILC_SKE_STATUS_INVALID_COOKIE) - g_snprintf(buf, sizeof(buf), _("Failure: Invalid cookie")); - - /* Show the error on the progress bar. A more generic error message - is going to be showed to user after this in the silc_connected. */ - purple_connection_update_progress(gc, buf, 2, 5); - } - - if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) { - SilcUInt32 err = SILC_PTR_TO_32(failure); - - if (err == SILC_AUTH_FAILED) - g_snprintf(buf, sizeof(buf), _("Failure: Authentication failed")); - - /* Show the error on the progress bar. A more generic error message - is going to be showed to user after this in the silc_connected. */ - purple_connection_update_progress(gc, buf, 4, 5); - } -} - -/* Asks whether the user would like to perform the key agreement protocol. - This is called after we have received an key agreement packet or an - reply to our key agreement packet. This returns TRUE if the user wants - the library to perform the key agreement protocol and FALSE if it is not - desired (application may start it later by calling the function - silc_client_perform_key_agreement). If TRUE is returned also the - `completion' and `context' arguments must be set by the application. */ - -static bool -silc_key_agreement(SilcClient client, SilcClientConnection conn, - SilcClientEntry client_entry, const char *hostname, - SilcUInt16 port, SilcKeyAgreementCallback *completion, - void **context) -{ - silcpurple_buddy_keyagr_request(client, conn, client_entry, hostname, port); - *completion = NULL; - *context = NULL; - return FALSE; + silcpurple_buddy_keyagr_request(client, conn, client_entry, + hostname, port, protocol); } @@ -2012,39 +1850,7 @@ const char *hostname, SilcUInt16 port) { silcpurple_ftp_request(client, conn, client_entry, session_id, - hostname, port); -} - - -/* Delivers SILC session detachment data indicated by `detach_data' to the - application. If application has issued SILC_COMMAND_DETACH command - the client session in the SILC network is not quit. The client remains - in the network but is detached. The detachment data may be used later - to resume the session in the SILC Network. The appliation is - responsible of saving the `detach_data', to for example in a file. - - The detachment data can be given as argument to the functions - silc_client_connect_to_server, or silc_client_add_connection when - creating connection to remote server, inside SilcClientConnectionParams - structure. If it is provided the client library will attempt to resume - the session in the network. After the connection is created - successfully, the application is responsible of setting the user - interface for user into the same state it was before detaching (showing - same channels, channel modes, etc). It can do this by fetching the - information (like joined channels) from the client library. */ - -static void -silc_detach(SilcClient client, SilcClientConnection conn, - const unsigned char *detach_data, SilcUInt32 detach_data_len) -{ - PurpleConnection *gc = client->application; - SilcPurple sg = gc->proto_data; - const char *file; - - /* Save the detachment data to file. */ - file = silcpurple_session_file(purple_account_get_username(sg->account)); - g_unlink(file); - silc_file_writefile(file, (char *)detach_data, detach_data_len); + hostname, port); } SilcClientOperations ops = { @@ -2054,13 +1860,9 @@ silc_notify, silc_command, silc_command_reply, - silc_connected, - silc_disconnected, silc_get_auth_method, silc_verify_public_key, silc_ask_passphrase, - silc_failure, silc_key_agreement, - silc_ftp, - silc_detach + silc_ftp };
--- a/libpurple/protocols/silc/pk.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/silc/pk.c Mon Jun 18 01:48:35 2007 +0000 @@ -4,7 +4,7 @@ Author: Pekka Riikonen <priikone@silcnet.org> - Copyright (C) 2004 Pekka Riikonen + Copyright (C) 2004 - 2007 Pekka Riikonen 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 @@ -17,7 +17,7 @@ */ -#include "silcincludes.h" +#include "silc.h" #include "silcclient.h" #include "silcpurple.h" @@ -31,18 +31,16 @@ char *entity_name; char *fingerprint; char *babbleprint; - unsigned char *pk; - SilcUInt32 pk_len; - SilcSKEPKType pk_type; + SilcPublicKey public_key; SilcVerifyPublicKey completion; void *context; gboolean changed; } *PublicKeyVerify; static void silcpurple_verify_ask(const char *entity, - const char *fingerprint, - const char *babbleprint, - PublicKeyVerify verify); + const char *fingerprint, + const char *babbleprint, + PublicKeyVerify verify); static void silcpurple_verify_cb(PublicKeyVerify verify, gint id) { @@ -54,8 +52,8 @@ verify->completion(TRUE, verify->context); /* Save the key for future checking */ - silc_pkcs_save_public_key_data(verify->filename, verify->pk, - verify->pk_len, SILC_PKCS_FILE_PEM); + silc_pkcs_save_public_key(verify->filename, verify->public_key, + SILC_PKCS_FILE_BASE64); } silc_free(verify->filename); @@ -63,7 +61,7 @@ silc_free(verify->entity_name); silc_free(verify->fingerprint); silc_free(verify->babbleprint); - silc_free(verify->pk); + silc_pkcs_public_key_free(verify->public_key); silc_free(verify); } @@ -74,27 +72,23 @@ should have option for the dialogs whether the buttons close them or not. */ silcpurple_verify_ask(verify->entity, verify->fingerprint, - verify->babbleprint, verify); + verify->babbleprint, verify); } static void silcpurple_verify_details(PublicKeyVerify verify, gint id) { - SilcPublicKey public_key; PurpleConnection *gc = verify->client->application; SilcPurple sg = gc->proto_data; - silc_pkcs_public_key_decode(verify->pk, verify->pk_len, - &public_key); - silcpurple_show_public_key(sg, verify->entity_name, public_key, - G_CALLBACK(silcpurple_verify_details_cb), - verify); - silc_pkcs_public_key_free(public_key); + silcpurple_show_public_key(sg, verify->entity_name, verify->public_key, + G_CALLBACK(silcpurple_verify_details_cb), + verify); } static void silcpurple_verify_ask(const char *entity, - const char *fingerprint, - const char *babbleprint, - PublicKeyVerify verify) + const char *fingerprint, + const char *babbleprint, + PublicKeyVerify verify) { PurpleConnection *gc = verify->client->application; char tmp[256], tmp2[256]; @@ -114,18 +108,17 @@ "%s\n%s\n"), entity, fingerprint, babbleprint); purple_request_action(gc, _("Verify Public Key"), tmp, tmp2, - PURPLE_DEFAULT_ACTION_NONE, - purple_connection_get_account(gc), entity, NULL, verify, 3, - _("Yes"), G_CALLBACK(silcpurple_verify_cb), - _("No"), G_CALLBACK(silcpurple_verify_cb), - _("_View..."), G_CALLBACK(silcpurple_verify_details)); + PURPLE_DEFAULT_ACTION_NONE, + purple_connection_get_account(gc), entity, NULL, verify, 3, + _("Yes"), G_CALLBACK(silcpurple_verify_cb), + _("No"), G_CALLBACK(silcpurple_verify_cb), + _("_View..."), G_CALLBACK(silcpurple_verify_details)); } void silcpurple_verify_public_key(SilcClient client, SilcClientConnection conn, - const char *name, SilcSocketType conn_type, - unsigned char *pk, SilcUInt32 pk_len, - SilcSKEPKType pk_type, - SilcVerifyPublicKey completion, void *context) + const char *name, SilcConnectionType conn_type, + SilcPublicKey public_key, + SilcVerifyPublicKey completion, void *context) { PurpleConnection *gc = client->application; int i; @@ -133,14 +126,18 @@ char *fingerprint, *babbleprint; struct passwd *pw; struct stat st; - char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER || - conn_type == SILC_SOCKET_TYPE_ROUTER) ? + char *entity = ((conn_type == SILC_CONN_SERVER || + conn_type == SILC_CONN_ROUTER) ? "server" : "client"); PublicKeyVerify verify; + const char *ip, *hostname; + SilcUInt16 port; + unsigned char *pk; + SilcUInt32 pk_len; - if (pk_type != SILC_SKE_PK_TYPE_SILC) { + if (silc_pkcs_get_type(public_key) != SILC_PKCS_SILC) { purple_notify_error(gc, _("Verify Public Key"), - _("Unsupported public key type"), NULL); + _("Unsupported public key type"), NULL); if (completion) completion(FALSE, context); return; @@ -157,17 +154,22 @@ memset(filename2, 0, sizeof(filename2)); memset(file, 0, sizeof(file)); - if (conn_type == SILC_SOCKET_TYPE_SERVER || - conn_type == SILC_SOCKET_TYPE_ROUTER) { + silc_socket_stream_get_info(silc_packet_stream_get_stream(conn->stream), + NULL, &hostname, &ip, &port); + + pk = silc_pkcs_public_key_encode(public_key, &pk_len); + + if (conn_type == SILC_CONN_SERVER || + conn_type == SILC_CONN_ROUTER) { if (!name) { g_snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity, - conn->sock->ip, conn->sock->port); + ip, port); g_snprintf(filename, sizeof(filename) - 1, "%s" G_DIR_SEPARATOR_S "%skeys" G_DIR_SEPARATOR_S "%s", silcpurple_silcdir(), entity, file); g_snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity, - conn->sock->hostname, conn->sock->port); + hostname, port); g_snprintf(filename2, sizeof(filename2) - 1, "%s" G_DIR_SEPARATOR_S "%skeys" G_DIR_SEPARATOR_S "%s", silcpurple_silcdir(), entity, file); @@ -176,7 +178,7 @@ hostf = filename2; } else { g_snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity, - name, conn->sock->port); + name, port); g_snprintf(filename, sizeof(filename) - 1, "%s" G_DIR_SEPARATOR_S "%skeys" G_DIR_SEPARATOR_S "%s", silcpurple_silcdir(), entity, file); @@ -206,12 +208,10 @@ verify->conn = conn; verify->filename = strdup(ipf); verify->entity = strdup(entity); - verify->entity_name = (conn_type != SILC_SOCKET_TYPE_CLIENT ? - (name ? strdup(name) : strdup(conn->sock->hostname)) + verify->entity_name = (conn_type != SILC_CONN_CLIENT ? + (name ? strdup(name) : strdup(hostname)) : NULL); - verify->pk = silc_memdup(pk, pk_len); - verify->pk_len = pk_len; - verify->pk_type = pk_type; + verify->public_key = silc_pkcs_public_key_copy(public_key); verify->completion = completion; verify->context = context; fingerprint = verify->fingerprint = silc_hash_fingerprint(NULL, pk, pk_len); @@ -221,7 +221,7 @@ if (g_stat(ipf, &st) < 0 && (!hostf || g_stat(hostf, &st) < 0)) { /* Key does not exist, ask user to verify the key and save it */ silcpurple_verify_ask(name ? name : entity, - fingerprint, babbleprint, verify); + fingerprint, babbleprint, verify); return; } else { /* The key already exists, verify it. */ @@ -230,14 +230,8 @@ SilcUInt32 encpk_len; /* Load the key file, try for both IP filename and hostname filename */ - if (!silc_pkcs_load_public_key(ipf, &public_key, - SILC_PKCS_FILE_PEM) && - !silc_pkcs_load_public_key(ipf, &public_key, - SILC_PKCS_FILE_BIN) && - (!hostf || (!silc_pkcs_load_public_key(hostf, &public_key, - SILC_PKCS_FILE_PEM) && - !silc_pkcs_load_public_key(hostf, &public_key, - SILC_PKCS_FILE_BIN)))) { + if (!silc_pkcs_load_public_key(ipf, &public_key) && + (!hostf || (!silc_pkcs_load_public_key(hostf, &public_key)))) { silcpurple_verify_ask(name ? name : entity, fingerprint, babbleprint, verify); return; @@ -266,9 +260,9 @@ silc_free(verify->filename); silc_free(verify->entity); silc_free(verify->entity_name); - silc_free(verify->pk); silc_free(verify->fingerprint); silc_free(verify->babbleprint); + silc_pkcs_public_key_free(verify->public_key); silc_free(verify); } }
--- a/libpurple/protocols/silc/silc.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/silc/silc.c Mon Jun 18 01:48:35 2007 +0000 @@ -4,7 +4,7 @@ Author: Pekka Riikonen <priikone@silcnet.org> - Copyright (C) 2004 - 2005 Pekka Riikonen + Copyright (C) 2004 - 2007 Pekka Riikonen 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 @@ -17,7 +17,7 @@ */ -#include "silcincludes.h" +#include "silc.h" #include "silcclient.h" #include "silcpurple.h" #include "version.h" @@ -26,6 +26,15 @@ extern SilcClientOperations ops; static PurplePlugin *silc_plugin = NULL; +/* Error log message callback */ + +static SilcBool silcpurple_log_error(SilcLogType type, char *message, + void *context) +{ + silc_say(NULL, NULL, SILC_CLIENT_MESSAGE_ERROR, message); + return TRUE; +} + static const char * silcpurple_list_icon(PurpleAccount *a, PurpleBuddy *b) { @@ -102,8 +111,8 @@ idp = silc_id_payload_encode(sg->conn->local_id, SILC_ID_CLIENT); SILC_PUT32_MSB(mode, mb); silc_client_command_send(sg->client, sg->conn, SILC_COMMAND_UMODE, - ++sg->conn->cmd_ident, 2, - 1, idp->data, idp->len, + silcpurple_command_reply, NULL, 2, + 1, idp->data, silc_buffer_len(idp), 2, mb, sizeof(mb)); silc_buffer_free(idp); } @@ -115,91 +124,54 @@ silcpurple_keepalive(PurpleConnection *gc) { SilcPurple sg = gc->proto_data; - silc_client_send_packet(sg->client, sg->conn, SILC_PACKET_HEARTBEAT, - NULL, 0); + silc_packet_send(sg->conn->stream, SILC_PACKET_HEARTBEAT, 0, + NULL, 0); } -static int +static gboolean silcpurple_scheduler(gpointer *context) { - SilcPurple sg = (SilcPurple)context; - silc_client_run_one(sg->client); - return 1; + SilcClient client = (SilcClient)context; + silc_client_run_one(client); + return TRUE; } static void -silcpurple_nickname_parse(const char *nickname, - char **ret_nickname) -{ - silc_parse_userfqdn(nickname, ret_nickname, NULL); -} - -static void -silcpurple_login_connected(gpointer data, gint source, const gchar *error_message) +silcpurple_connect_cb(SilcClient client, SilcClientConnection conn, + SilcClientConnectionStatus status, SilcStatus error, + const char *message, void *context) { - PurpleConnection *gc = data; + PurpleConnection *gc = context; SilcPurple sg; - SilcClient client; - SilcClientConnection conn; - PurpleAccount *account; - SilcClientConnectionParams params; - const char *dfile; - - g_return_if_fail(gc != NULL); + SilcUInt32 mask; + char tz[16]; + PurpleStoredImage *img; +#ifdef HAVE_SYS_UTSNAME_H + struct utsname u; +#endif sg = gc->proto_data; - if (source < 0) { - purple_connection_error(gc, _("Connection failed")); - return; - } + switch (status) { + case SILC_CLIENT_CONN_SUCCESS: + case SILC_CLIENT_CONN_SUCCESS_RESUME: + sg->conn = conn; - client = sg->client; - account = sg->account; - - /* Get session detachment data, if available */ - memset(¶ms, 0, sizeof(params)); - dfile = silcpurple_session_file(purple_account_get_username(sg->account)); - params.detach_data = (unsigned char *)silc_file_readfile(dfile, ¶ms.detach_data_len); - if (params.detach_data) - params.detach_data[params.detach_data_len] = 0; + /* Connection created successfully */ + purple_connection_set_state(gc, PURPLE_CONNECTED); - /* Add connection to SILC client library */ - conn = silc_client_add_connection( - sg->client, ¶ms, - (char *)purple_account_get_string(account, "server", - "silc.silcnet.org"), - purple_account_get_int(account, "port", 706), sg); - if (!conn) { - purple_connection_error(gc, _("Cannot initialize SILC Client connection")); - gc->proto_data = NULL; - return; - } - sg->conn = conn; + /* Send the server our buddy list */ + silcpurple_send_buddylist(gc); + + g_unlink(silcpurple_session_file(purple_account_get_username(sg->account))); - /* Progress */ - if (params.detach_data) { - purple_connection_update_progress(gc, _("Resuming session"), 2, 5); - sg->resuming = TRUE; - } else { - purple_connection_update_progress(gc, _("Performing key exchange"), 2, 5); - } - - /* Perform SILC Key Exchange. The "silc_connected" will be called - eventually. */ - silc_client_start_key_exchange(sg->client, sg->conn, source); + /* Send any UMODEs configured for account */ + if (purple_account_get_bool(sg->account, "block-ims", FALSE)) { + silc_client_command_call(sg->client, sg->conn, NULL, + "UMODE", "+P", NULL); + } - /* Set default attributes */ - if (!purple_account_get_bool(account, "reject-attrs", FALSE)) { - SilcUInt32 mask; - const char *tmp; -#ifdef SILC_ATTRIBUTE_USER_ICON - PurpleStoredImage *img; -#endif -#ifdef HAVE_SYS_UTSNAME_H - struct utsname u; -#endif - + /* Set default attributes */ mask = SILC_ATTRIBUTE_MOOD_NORMAL; silc_client_attribute_add(client, conn, SILC_ATTRIBUTE_STATUS_MOOD, @@ -222,36 +194,191 @@ (void *)&dev, sizeof(dev)); } #endif -#ifdef _WIN32 - tmp = _tzname[0]; -#else - tmp = tzname[0]; -#endif + silc_timezone(tz, sizeof(tz)); silc_client_attribute_add(client, conn, SILC_ATTRIBUTE_TIMEZONE, - (void *)tmp, strlen(tmp)); + (void *)tz, strlen(tz)); -#ifdef SILC_ATTRIBUTE_USER_ICON /* Set our buddy icon */ - img = purple_buddy_icons_find_account_icon(account); + img = purple_buddy_icons_find_account_icon(sg->account); silcpurple_buddy_set_icon(gc, img); purple_imgstore_unref(img); -#endif + + return; + break; + + case SILC_CLIENT_CONN_DISCONNECTED: + /* Disconnected */ + if (sg->resuming && !sg->detaching) + g_unlink(silcpurple_session_file(purple_account_get_username(sg->account))); + + /* Close the connection */ + if (!sg->detaching) + purple_connection_error(gc, _("Disconnected by server")); + else + /* TODO: Does this work correctly? Maybe we need to set wants_to_die? */ + purple_account_disconnect(purple_connection_get_account(gc)); + break; + + case SILC_CLIENT_CONN_ERROR: + purple_connection_error(gc, _("Error during connecting to SILC Server")); + g_unlink(silcpurple_session_file(purple_account_get_username(sg->account))); + break; + + case SILC_CLIENT_CONN_ERROR_KE: + purple_connection_error(gc, _("Key Exchange failed")); + break; + + case SILC_CLIENT_CONN_ERROR_AUTH: + purple_connection_error(gc, _("Authentication failed")); + break; + + case SILC_CLIENT_CONN_ERROR_RESUME: + purple_connection_error(gc, + _("Resuming detached session failed. " + "Press Reconnect to create new connection.")); + g_unlink(silcpurple_session_file(purple_account_get_username(sg->account))); + break; + + case SILC_CLIENT_CONN_ERROR_TIMEOUT: + purple_connection_error(gc, _("Connection Timeout")); + break; } + /* Error */ + sg->conn = NULL; +} + +static void +silcpurple_stream_created(SilcSocketStreamStatus status, SilcStream stream, + void *context) +{ + PurpleConnection *gc = context; + SilcPurple sg; + SilcClient client; + SilcClientConnectionParams params; + const char *dfile; + + sg = gc->proto_data; + + if (status != SILC_SOCKET_OK) { + purple_connection_error(gc, _("Connection failed")); + silc_pkcs_public_key_free(sg->public_key); + silc_pkcs_private_key_free(sg->private_key); + silc_free(sg); + gc->proto_data = NULL; + return; + } + + client = sg->client; + + /* Progress */ + if (params.detach_data) { + purple_connection_update_progress(gc, _("Resuming session"), 2, 5); + sg->resuming = TRUE; + } else { + purple_connection_update_progress(gc, _("Performing key exchange"), 2, 5); + } + + /* Get session detachment data, if available */ + memset(¶ms, 0, sizeof(params)); + dfile = silcpurple_session_file(purple_account_get_username(sg->account)); + params.detach_data = (unsigned char *)silc_file_readfile(dfile, ¶ms.detach_data_len); + if (params.detach_data) + params.detach_data[params.detach_data_len] = 0; + params.ignore_requested_attributes = FALSE; + params.pfs = purple_account_get_bool(sg->account, "pfs", FALSE); + + /* Perform SILC Key Exchange. */ + silc_client_key_exchange(sg->client, ¶ms, sg->public_key, + sg->private_key, stream, SILC_CONN_SERVER, + silcpurple_connect_cb, gc); + silc_free(params.detach_data); } static void +silcpurple_login_connected(gpointer data, gint source, const gchar *error_message) +{ + PurpleConnection *gc = data; + SilcPurple sg; + + g_return_if_fail(gc != NULL); + + sg = gc->proto_data; + + if (source < 0) { + purple_connection_error(gc, _("Connection failed")); + silc_pkcs_public_key_free(sg->public_key); + silc_pkcs_private_key_free(sg->private_key); + silc_free(sg); + gc->proto_data = NULL; + return; + } + + /* Wrap socket to TCP stream */ + silc_socket_tcp_stream_create(source, TRUE, FALSE, + sg->client->schedule, + silcpurple_stream_created, gc); +} + +static void silcpurple_running(SilcClient client, void *context) +{ + PurpleAccount *account = context; + PurpleConnection *gc = account->gc; + SilcPurple sg; + char pkd[256], prd[256]; + + sg = silc_calloc(1, sizeof(*sg)); + if (!sg) + return; + memset(sg, 0, sizeof(*sg)); + sg->client = client; + sg->gc = gc; + sg->account = account; + sg->scheduler = SILC_PTR_TO_32(gc->proto_data); + gc->proto_data = sg; + + /* Progress */ + purple_connection_update_progress(gc, _("Connecting to SILC Server"), 1, 5); + + /* Load SILC key pair */ + g_snprintf(pkd, sizeof(pkd), "%s" G_DIR_SEPARATOR_S "public_key.pub", silcpurple_silcdir()); + g_snprintf(prd, sizeof(prd), "%s" G_DIR_SEPARATOR_S "private_key.prv", silcpurple_silcdir()); + if (!silc_load_key_pair((char *)purple_account_get_string(account, "public-key", pkd), + (char *)purple_account_get_string(account, "private-key", prd), + (gc->password == NULL) ? "" : gc->password, + &sg->public_key, &sg->private_key)) { + g_snprintf(pkd, sizeof(pkd), _("Could not load SILC key pair")); + purple_connection_error(gc, pkd); + gc->proto_data = NULL; + silc_free(sg); + return; + } + + /* Connect to the SILC server */ + if (purple_proxy_connect(gc, account, + purple_account_get_string(account, "server", + "silc.silcnet.org"), + purple_account_get_int(account, "port", 706), + silcpurple_login_connected, gc) == NULL) + { + purple_connection_error(gc, _("Unable to create connection")); + gc->proto_data = NULL; + silc_free(sg); + return; + } +} + +static void silcpurple_login(PurpleAccount *account) { - SilcPurple sg; SilcClient client; - SilcClientParams params; PurpleConnection *gc; - char pkd[256], prd[256]; + SilcClientParams params; const char *cipher, *hmac; - char *realname; + char *username, *hostname, *realname, **up; + guint scheduler; int i; gc = account->gc; @@ -260,10 +387,7 @@ gc->proto_data = NULL; memset(¶ms, 0, sizeof(params)); - strcat(params.nickname_format, "%n@%h%a"); - params.nickname_parse = silcpurple_nickname_parse; - params.ignore_requested_attributes = - purple_account_get_bool(account, "reject-attrs", FALSE); + strcat(params.nickname_format, "%n#a"); /* Allocate SILC client */ client = silc_client_alloc(&ops, ¶ms, gc, NULL); @@ -273,32 +397,28 @@ } /* Get username, real name and local hostname for SILC library */ - if (purple_account_get_username(account)) { - const char *u = purple_account_get_username(account); - char **up = g_strsplit(u, "@", 2); - client->username = strdup(up[0]); - g_strfreev(up); - } else { - client->username = silc_get_username(); - purple_account_set_username(account, client->username); + if (!purple_account_get_username(account)) + purple_account_set_username(account, silc_get_username()); + + username = (char *)purple_account_get_username(account); + up = g_strsplit(username, "@", 2); + username = strdup(up[0]); + g_strfreev(up); + + if (!purple_account_get_user_info(account)) { + purple_account_set_user_info(account, silc_get_real_name()); + if (!purple_account_get_user_info(account)) + purple_account_set_user_info(account, + "John T. Noname"); } - realname = silc_get_real_name(); - if (purple_account_get_user_info(account)) { - client->realname = strdup(purple_account_get_user_info(account)); - free(realname); - } else if ((silc_get_real_name() != NULL) && (*realname != '\0')) { - client->realname = realname; - purple_account_set_user_info(account, client->realname); - } else { - free(realname); - client->realname = strdup(_("John Noname")); - } - client->hostname = silc_net_localhost(); + realname = (char *)purple_account_get_user_info(account); + hostname = silc_net_localhost(); - purple_connection_set_display_name(gc, client->username); + purple_connection_set_display_name(gc, username); /* Register requested cipher and HMAC */ - cipher = purple_account_get_string(account, "cipher", SILC_DEFAULT_CIPHER); + cipher = purple_account_get_string(account, "cipher", + SILC_DEFAULT_CIPHER); for (i = 0; silc_default_ciphers[i].name; i++) if (!strcmp(silc_default_ciphers[i].name, cipher)) { silc_cipher_register(&(silc_default_ciphers[i])); @@ -312,7 +432,8 @@ } /* Init SILC client */ - if (!silc_client_init(client)) { + if (!silc_client_init(client, username, hostname, realname, + silcpurple_running, account)) { gc->wants_to_die = TRUE; purple_connection_error(gc, _("Cannot initialize SILC protocol")); return; @@ -321,63 +442,23 @@ /* Check the ~/.silc dir and create it, and new key pair if necessary. */ if (!silcpurple_check_silc_dir(gc)) { gc->wants_to_die = TRUE; - purple_connection_error(gc, _("Cannot find/access ~/.silc directory")); - return; - } - - /* Progress */ - purple_connection_update_progress(gc, _("Connecting to SILC Server"), 1, 5); - - /* Load SILC key pair */ - g_snprintf(pkd, sizeof(pkd), "%s" G_DIR_SEPARATOR_S "public_key.pub", silcpurple_silcdir()); - g_snprintf(prd, sizeof(prd), "%s" G_DIR_SEPARATOR_S "private_key.prv", silcpurple_silcdir()); - if (!silc_load_key_pair((char *)purple_account_get_string(account, "public-key", pkd), - (char *)purple_account_get_string(account, "private-key", prd), - (gc->password == NULL) ? "" : gc->password, &client->pkcs, - &client->public_key, &client->private_key)) { - g_snprintf(pkd, sizeof(pkd), _("Could not load SILC key pair: %s"), strerror(errno)); - purple_connection_error(gc, pkd); - return; - } - - sg = silc_calloc(1, sizeof(*sg)); - if (!sg) - return; - memset(sg, 0, sizeof(*sg)); - sg->client = client; - sg->gc = gc; - sg->account = account; - gc->proto_data = sg; - - /* Connect to the SILC server */ - if (purple_proxy_connect(gc, account, - purple_account_get_string(account, "server", - "silc.silcnet.org"), - purple_account_get_int(account, "port", 706), - silcpurple_login_connected, gc) == NULL) - { - purple_connection_error(gc, _("Unable to create connection")); + purple_connection_error(gc, _("Error loading SILC key pair")); return; } /* Schedule SILC using Glib's event loop */ -#ifndef _WIN32 - sg->scheduler = g_timeout_add(5, (GSourceFunc)silcpurple_scheduler, sg); -#else - sg->scheduler = g_timeout_add(300, (GSourceFunc)silcpurple_scheduler, sg); -#endif + scheduler = purple_timeout_add(300, (GSourceFunc)silcpurple_scheduler, client); + gc->proto_data = SILC_32_TO_PTR(scheduler); } static int silcpurple_close_final(gpointer *context) { SilcPurple sg = (SilcPurple)context; - silc_client_stop(sg->client); + silc_client_stop(sg->client, NULL, NULL); silc_client_free(sg->client); -#ifdef HAVE_SILCMIME_H if (sg->mimeass) silc_mime_assembler_free(sg->mimeass); -#endif silc_free(sg); return 0; } @@ -391,13 +472,13 @@ /* Send QUIT */ silc_client_command_call(sg->client, sg->conn, NULL, - "QUIT", "Download Purple: " PURPLE_WEBSITE, NULL); + "QUIT", "Download Pidgin: " PURPLE_WEBSITE, NULL); if (sg->conn) silc_client_close_connection(sg->client, sg->conn); - g_source_remove(sg->scheduler); - g_timeout_add(1, (GSourceFunc)silcpurple_close_final, sg); + purple_timeout_remove(sg->scheduler); + purple_timeout_add(1, (GSourceFunc)silcpurple_close_final, sg); } @@ -599,7 +680,7 @@ gboolean cemail = FALSE, ccall = FALSE, csms = FALSE, cmms = FALSE, cchat = TRUE, cvideo = FALSE; gboolean device = TRUE; - char status[1024]; + char status[1024], tz[16]; sg = gc->proto_data; if (!sg) @@ -726,11 +807,9 @@ purple_account_get_string(sg->account, "vcard", ""), FALSE); purple_request_field_group_add_field(g, f); -#ifdef _WIN32 - f = purple_request_field_string_new("timezone", _("Timezone"), _tzname[0], FALSE); -#else - f = purple_request_field_string_new("timezone", _("Timezone"), tzname[0], FALSE); -#endif + + silc_timezone(tz, sizeof(tz)); + f = purple_request_field_string_new("timezone", _("Timezone (UTC)"), tz, FALSE); purple_request_field_group_add_field(g, f); purple_request_fields_add_group(fields, g); @@ -865,12 +944,14 @@ if (f) c = purple_request_field_string_get_value(f); - identifier = silc_pkcs_encode_identifier((char *)un, (char *)hn, - (char *)rn, (char *)e, (char *)o, (char *)c); + identifier = silc_pkcs_silc_encode_identifier((char *)un, (char *)hn, + (char *)rn, (char *)e, + (char *)o, (char *)c, + NULL); /* Create the key pair */ if (!silc_create_key_pair(SILCPURPLE_DEF_PKCS, keylen, pkfile, prfile, - identifier, pass1, NULL, &public_key, NULL, + identifier, pass1, &public_key, NULL, FALSE)) { purple_notify_error( gc, _("Create New SILC Key Pair"), _("Key Pair Generation failed"), NULL); @@ -945,10 +1026,10 @@ purple_request_fields_add_group(fields, g); purple_request_fields(gc, _("Create New SILC Key Pair"), - _("Create New SILC Key Pair"), NULL, fields, - _("Generate Key Pair"), G_CALLBACK(silcpurple_create_keypair_cb), - _("Cancel"), G_CALLBACK(silcpurple_create_keypair_cancel), - gc->account, NULL, NULL, gc); + _("Create New SILC Key Pair"), NULL, fields, + _("Generate Key Pair"), G_CALLBACK(silcpurple_create_keypair_cb), + _("Cancel"), G_CALLBACK(silcpurple_create_keypair_cancel), + gc->account, NULL, NULL, gc); g_strfreev(u); silc_free(hostname); @@ -967,8 +1048,8 @@ char prd[256]; g_snprintf(prd, sizeof(prd), "%s" G_DIR_SEPARATOR_S "private_key.pub", silcpurple_silcdir()); silc_change_private_key_passphrase(purple_account_get_string(gc->account, - "private-key", - prd), old, new); + "private-key", + prd), old, new); } static void @@ -986,15 +1067,12 @@ static GList * silcpurple_actions(PurplePlugin *plugin, gpointer context) { - PurpleConnection *gc = context; GList *list = NULL; PurplePluginAction *act; - if (!purple_account_get_bool(gc->account, "reject-attrs", FALSE)) { - act = purple_plugin_action_new(_("Online Status"), - silcpurple_attrs); - list = g_list_append(list, act); - } + act = purple_plugin_action_new(_("Online Status"), + silcpurple_attrs); + list = g_list_append(list, act); act = purple_plugin_action_new(_("Detach From Server"), silcpurple_detach); @@ -1032,49 +1110,43 @@ static void silcpurple_send_im_resolved(SilcClient client, - SilcClientConnection conn, - SilcClientEntry *clients, - SilcUInt32 clients_count, - void *context) + SilcClientConnection conn, + SilcStatus status, + SilcDList clients, + void *context) { PurpleConnection *gc = client->application; SilcPurple sg = gc->proto_data; SilcPurpleIM im = context; PurpleConversation *convo; - char tmp[256], *nickname = NULL; + char tmp[256]; SilcClientEntry client_entry; -#ifdef HAVE_SILCMIME_H SilcDList list; -#endif convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, im->nick, - sg->account); + sg->account); if (!convo) return; if (!clients) goto err; - if (clients_count > 1) { - silc_parse_userfqdn(im->nick, &nickname, NULL); - + if (silc_dlist_count(clients) > 1) { /* Find the correct one. The im->nick might be a formatted nick so this will find the correct one. */ clients = silc_client_get_clients_local(client, conn, - nickname, im->nick, - &clients_count); + im->nick, FALSE); if (!clients) goto err; - client_entry = clients[0]; - silc_free(clients); - } else { - client_entry = clients[0]; } -#ifdef HAVE_SILCMIME_H + silc_dlist_start(clients); + client_entry = silc_dlist_get(clients); + /* Check for images */ if (im->gflags & PURPLE_MESSAGE_IMAGES) { - list = silcpurple_image_message(im->message, (SilcUInt32 *)&im->flags); + list = silcpurple_image_message(im->message, + (SilcUInt32 *)(void *)&im->flags); if (list) { /* Send one or more MIME message. If more than one, they are MIME fragments due to over large message */ @@ -1083,22 +1155,21 @@ silc_dlist_start(list); while ((buf = silc_dlist_get(list)) != SILC_LIST_END) silc_client_send_private_message(client, conn, - client_entry, im->flags, - buf->data, buf->len, - TRUE); + client_entry, im->flags, NULL, + buf->data, + silc_buffer_len(buf)); silc_mime_partial_free(list); purple_conv_im_write(PURPLE_CONV_IM(convo), conn->local_entry->nickname, - im->message, 0, time(NULL)); + im->message, 0, time(NULL)); goto out; } } -#endif /* Send the message */ silc_client_send_private_message(client, conn, client_entry, im->flags, - (unsigned char *)im->message, im->message_len, TRUE); + NULL, (unsigned char *)im->message, im->message_len); purple_conv_im_write(PURPLE_CONV_IM(convo), conn->local_entry->nickname, - im->message, 0, time(NULL)); + im->message, 0, time(NULL)); goto out; err: @@ -1110,24 +1181,22 @@ g_free(im->nick); g_free(im->message); silc_free(im); - silc_free(nickname); } static int silcpurple_send_im(PurpleConnection *gc, const char *who, const char *message, - PurpleMessageFlags flags) + PurpleMessageFlags flags) { SilcPurple sg = gc->proto_data; SilcClient client = sg->client; SilcClientConnection conn = sg->conn; - SilcClientEntry *clients; - SilcUInt32 clients_count, mflags; - char *nickname, *msg, *tmp; + SilcDList clients; + SilcClientEntry client_entry; + SilcUInt32 mflags; + char *msg, *tmp; int ret = 0; gboolean sign = purple_account_get_bool(sg->account, "sign-verify", FALSE); -#ifdef HAVE_SILCMIME_H SilcDList list; -#endif if (!who || !message) return 0; @@ -1145,14 +1214,9 @@ mflags |= SILC_MESSAGE_FLAG_ACTION; } else if (strlen(msg) > 1 && msg[0] == '/') { if (!silc_client_command_call(client, conn, msg + 1)) - purple_notify_error(gc, _("Call Command"), _("Cannot call command"), - _("Unknown command")); - g_free(tmp); - return 0; - } - - - if (!silc_parse_userfqdn(who, &nickname, NULL)) { + purple_notify_error(gc, _("Call Command"), + _("Cannot call command"), + _("Unknown command")); g_free(tmp); return 0; } @@ -1161,8 +1225,7 @@ mflags |= SILC_MESSAGE_FLAG_SIGNED; /* Find client entry */ - clients = silc_client_get_clients_local(client, conn, nickname, who, - &clients_count); + clients = silc_client_get_clients_local(client, conn, who, FALSE); if (!clients) { /* Resolve unknown user */ SilcPurpleIM im = silc_calloc(1, sizeof(*im)); @@ -1175,14 +1238,15 @@ im->message_len = strlen(im->message); im->flags = mflags; im->gflags = flags; - silc_client_get_clients(client, conn, nickname, NULL, + silc_client_get_clients(client, conn, who, NULL, silcpurple_send_im_resolved, im); - silc_free(nickname); g_free(tmp); return 0; } -#ifdef HAVE_SILCMIME_H + silc_dlist_start(clients); + client_entry = silc_dlist_get(clients); + /* Check for images */ if (flags & PURPLE_MESSAGE_IMAGES) { list = silcpurple_image_message(message, &mflags); @@ -1195,27 +1259,24 @@ while ((buf = silc_dlist_get(list)) != SILC_LIST_END) ret = silc_client_send_private_message(client, conn, - clients[0], mflags, - buf->data, buf->len, - TRUE); + client_entry, mflags, NULL, + buf->data, + silc_buffer_len(buf)); silc_mime_partial_free(list); g_free(tmp); - silc_free(nickname); - silc_free(clients); + silc_client_list_free(client, conn, clients); return ret; } } -#endif /* Send private message directly */ - ret = silc_client_send_private_message(client, conn, clients[0], - mflags, + ret = silc_client_send_private_message(client, conn, client_entry, + mflags, NULL, (unsigned char *)msg, - strlen(msg), TRUE); + strlen(msg)); g_free(tmp); - silc_free(nickname); - silc_free(clients); + silc_client_list_free(client, conn, clients); return ret; } @@ -1223,7 +1284,6 @@ static GList *silcpurple_blist_node_menu(PurpleBlistNode *node) { /* split this single menu building function back into the two original: one for buddies and one for chats */ - if(PURPLE_BLIST_NODE_IS_CHAT(node)) { return silcpurple_chat_menu((PurpleChat *) node); } else if(PURPLE_BLIST_NODE_IS_BUDDY(node)) { @@ -1552,7 +1612,7 @@ return PURPLE_CMD_RET_FAILED; silc_client_command_call(sg->client, sg->conn, NULL, - "QUIT", (args && args[0]) ? args[0] : "Download Purple: " PURPLE_WEBSITE, NULL); + "QUIT", (args && args[0]) ? args[0] : "Download Pidgin: " PURPLE_WEBSITE, NULL); return PURPLE_CMD_RET_OK; } @@ -1726,82 +1786,69 @@ static PurplePluginProtocolInfo prpl_info = { -#ifdef HAVE_SILCMIME_H OPT_PROTO_CHAT_TOPIC | OPT_PROTO_UNIQUE_CHATNAME | OPT_PROTO_PASSWORD_OPTIONAL | OPT_PROTO_IM_IMAGE, -#else - OPT_PROTO_CHAT_TOPIC | OPT_PROTO_UNIQUE_CHATNAME | - OPT_PROTO_PASSWORD_OPTIONAL, -#endif - NULL, /* user_splits */ - NULL, /* protocol_options */ -#ifdef SILC_ATTRIBUTE_USER_ICON + NULL, /* user_splits */ + NULL, /* protocol_options */ {"jpeg,gif,png,bmp", 0, 0, 96, 96, 0, PURPLE_ICON_SCALE_DISPLAY}, /* icon_spec */ -#else - NO_BUDDY_ICONS, -#endif - silcpurple_list_icon, /* list_icon */ - NULL, /* list_emblems */ - silcpurple_status_text, /* status_text */ + silcpurple_list_icon, /* list_icon */ + NULL, /* list_emblems */ + silcpurple_status_text, /* status_text */ silcpurple_tooltip_text, /* tooltip_text */ - silcpurple_away_states, /* away_states */ - silcpurple_blist_node_menu, /* blist_node_menu */ + silcpurple_away_states, /* away_states */ + silcpurple_blist_node_menu, /* blist_node_menu */ silcpurple_chat_info, /* chat_info */ - silcpurple_chat_info_defaults,/* chat_info_defaults */ - silcpurple_login, /* login */ - silcpurple_close, /* close */ + silcpurple_chat_info_defaults, /* chat_info_defaults */ + silcpurple_login, /* login */ + silcpurple_close, /* close */ silcpurple_send_im, /* send_im */ silcpurple_set_info, /* set_info */ - NULL, /* send_typing */ + NULL, /* send_typing */ silcpurple_get_info, /* get_info */ - silcpurple_set_status, /* set_status */ + silcpurple_set_status, /* set_status */ silcpurple_idle_set, /* set_idle */ silcpurple_change_passwd, /* change_passwd */ silcpurple_add_buddy, /* add_buddy */ - NULL, /* add_buddies */ + NULL, /* add_buddies */ silcpurple_remove_buddy, /* remove_buddy */ - NULL, /* remove_buddies */ - NULL, /* add_permit */ - NULL, /* add_deny */ - NULL, /* rem_permit */ - NULL, /* rem_deny */ - NULL, /* set_permit_deny */ + NULL, /* remove_buddies */ + NULL, /* add_permit */ + NULL, /* add_deny */ + NULL, /* rem_permit */ + NULL, /* rem_deny */ + NULL, /* set_permit_deny */ silcpurple_chat_join, /* join_chat */ - NULL, /* reject_chat */ + NULL, /* reject_chat */ silcpurple_get_chat_name, /* get_chat_name */ - silcpurple_chat_invite, /* chat_invite */ - silcpurple_chat_leave, /* chat_leave */ - NULL, /* chat_whisper */ + silcpurple_chat_invite, /* chat_invite */ + silcpurple_chat_leave, /* chat_leave */ + NULL, /* chat_whisper */ silcpurple_chat_send, /* chat_send */ silcpurple_keepalive, /* keepalive */ - NULL, /* register_user */ - NULL, /* get_cb_info */ - NULL, /* get_cb_away */ - NULL, /* alias_buddy */ - NULL, /* group_buddy */ - NULL, /* rename_group */ - NULL, /* buddy_free */ - NULL, /* convo_closed */ - NULL, /* normalize */ -#ifdef SILC_ATTRIBUTE_USER_ICON - silcpurple_buddy_set_icon, /* set_buddy_icon */ -#else - NULL, -#endif - NULL, /* remove_group */ - NULL, /* get_cb_real_name */ - silcpurple_chat_set_topic, /* set_chat_topic */ - NULL, /* find_blist_chat */ - silcpurple_roomlist_get_list, /* roomlist_get_list */ - silcpurple_roomlist_cancel, /* roomlist_cancel */ - NULL, /* roomlist_expand_category */ - NULL, /* can_receive_file */ + NULL, /* register_user */ + NULL, /* get_cb_info */ + NULL, /* get_cb_away */ + NULL, /* alias_buddy */ + NULL, /* group_buddy */ + NULL, /* rename_group */ + NULL, /* buddy_free */ + NULL, /* convo_closed */ + NULL, /* normalize */ + silcpurple_buddy_set_icon, /* set_buddy_icon */ + NULL, /* remove_group */ + NULL, /* get_cb_real_name */ + silcpurple_chat_set_topic, /* set_chat_topic */ + NULL, /* find_blist_chat */ + silcpurple_roomlist_get_list, /* roomlist_get_list */ + silcpurple_roomlist_cancel, /* roomlist_cancel */ + NULL, /* roomlist_expand_category */ + NULL, /* can_receive_file */ silcpurple_ftp_send_file, /* send_file */ silcpurple_ftp_new_xfer, /* new_xfer */ - NULL, /* offline_message */ + NULL, /* offline_message */ &silcpurple_wb_ops, /* whiteboard_prpl_ops */ - NULL, /* send_raw */ - NULL, /* roomlist_room_serialize */ + NULL, /* send_raw */ + NULL, /* roomlist_room_serialize */ /* padding */ NULL, @@ -1815,29 +1862,29 @@ PURPLE_PLUGIN_MAGIC, PURPLE_MAJOR_VERSION, PURPLE_MINOR_VERSION, - PURPLE_PLUGIN_PROTOCOL, /**< type */ - NULL, /**< ui_requirement */ - 0, /**< flags */ - NULL, /**< dependencies */ - PURPLE_PRIORITY_DEFAULT, /**< priority */ + PURPLE_PLUGIN_PROTOCOL, /**< type */ + NULL, /**< ui_requirement */ + 0, /**< flags */ + NULL, /**< dependencies */ + PURPLE_PRIORITY_DEFAULT, /**< priority */ - "prpl-silc", /**< id */ - "SILC", /**< name */ - "1.0", /**< version */ + "prpl-silc", /**< id */ + "SILC", /**< name */ + "1.1", /**< version */ /** summary */ N_("SILC Protocol Plugin"), /** description */ N_("Secure Internet Live Conferencing (SILC) Protocol"), - "Pekka Riikonen", /**< author */ - "http://silcnet.org/", /**< homepage */ + "Pekka Riikonen", /**< author */ + "http://silcnet.org/", /**< homepage */ - NULL, /**< load */ - NULL, /**< unload */ - NULL, /**< destroy */ + NULL, /**< load */ + NULL, /**< unload */ + NULL, /**< destroy */ - NULL, /**< ui_info */ - &prpl_info, /**< extra_info */ - NULL, /**< prefs_info */ + NULL, /**< ui_info */ + &prpl_info, /**< extra_info */ + NULL, /**< prefs_info */ silcpurple_actions, /* padding */ @@ -1864,18 +1911,18 @@ /* Account options */ option = purple_account_option_string_new(_("Connect server"), - "server", - "silc.silcnet.org"); + "server", + "silc.silcnet.org"); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); option = purple_account_option_int_new(_("Port"), "port", 706); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); g_snprintf(tmp, sizeof(tmp), "%s" G_DIR_SEPARATOR_S "public_key.pub", silcpurple_silcdir()); option = purple_account_option_string_new(_("Public Key file"), - "public-key", tmp); + "public-key", tmp); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); g_snprintf(tmp, sizeof(tmp), "%s" G_DIR_SEPARATOR_S "private_key.prv", silcpurple_silcdir()); option = purple_account_option_string_new(_("Private Key file"), - "private-key", tmp); + "private-key", tmp); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); for (i = 0; silc_default_ciphers[i].name; i++) { @@ -1897,35 +1944,36 @@ option = purple_account_option_list_new(_("HMAC"), "hmac", list); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); - option = purple_account_option_bool_new(_("Public key authentication"), - "pubkey-auth", FALSE); + option = purple_account_option_bool_new(_("Use Perfect Forward Secrecy"), + "pfs", FALSE); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); - option = purple_account_option_bool_new(_("Reject watching by other users"), - "reject-watch", FALSE); - prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); - option = purple_account_option_bool_new(_("Block invites"), - "block-invites", FALSE); + + option = purple_account_option_bool_new(_("Public key authentication"), + "pubkey-auth", FALSE); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); option = purple_account_option_bool_new(_("Block IMs without Key Exchange"), - "block-ims", FALSE); - prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); - option = purple_account_option_bool_new(_("Reject online status attribute requests"), - "reject-attrs", FALSE); + "block-ims", FALSE); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); option = purple_account_option_bool_new(_("Block messages to whiteboard"), - "block-wb", FALSE); + "block-wb", FALSE); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); option = purple_account_option_bool_new(_("Automatically open whiteboard"), - "open-wb", FALSE); + "open-wb", FALSE); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); option = purple_account_option_bool_new(_("Digitally sign and verify all messages"), - "sign-verify", FALSE); + "sign-verify", FALSE); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); purple_prefs_remove("/plugins/prpl/silc"); + silc_log_set_callback(SILC_LOG_ERROR, silcpurple_log_error, NULL); silcpurple_register_commands(); +#if 0 +silc_log_debug(TRUE); +silc_log_set_debug_string("*client*"); +#endif + #ifdef _WIN32 silc_net_win32_init(); #endif
--- a/libpurple/protocols/silc/silcpurple.h Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/silc/silcpurple.h Mon Jun 18 01:48:35 2007 +0000 @@ -4,7 +4,7 @@ Author: Pekka Riikonen <priikone@silcnet.org> - Copyright (C) 2004 Pekka Riikonen + Copyright (C) 2004 - 2007 Pekka Riikonen 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 @@ -66,6 +66,8 @@ typedef struct SilcPurpleStruct { SilcClient client; SilcClientConnection conn; + SilcPublicKey public_key; + SilcPrivateKey private_key; guint scheduler; PurpleConnection *gc; @@ -75,9 +77,7 @@ char *motd; PurpleRoomlist *roomlist; -#ifdef HAVE_SILCMIME_H SilcMimeAssembler mimeass; -#endif unsigned int detaching : 1; unsigned int resuming : 1; unsigned int roomlist_canceled : 1; @@ -85,27 +85,29 @@ } *SilcPurple; +void silc_say(SilcClient client, SilcClientConnection conn, + SilcClientMessageType type, char *msg, ...); +SilcBool silcpurple_command_reply(SilcClient client, SilcClientConnection conn, + SilcCommand command, SilcStatus status, + SilcStatus error, void *context, va_list ap); gboolean silcpurple_check_silc_dir(PurpleConnection *gc); -void silcpurple_chat_join_done(SilcClient client, - SilcClientConnection conn, - SilcClientEntry *clients, - SilcUInt32 clients_count, - void *context); const char *silcpurple_silcdir(void); const char *silcpurple_session_file(const char *account); void silcpurple_verify_public_key(SilcClient client, SilcClientConnection conn, - const char *name, SilcSocketType conn_type, - unsigned char *pk, SilcUInt32 pk_len, - SilcSKEPKType pk_type, - SilcVerifyPublicKey completion, void *context); + const char *name, + SilcConnectionType conn_type, + SilcPublicKey public_key, + SilcVerifyPublicKey completion, + void *context); GList *silcpurple_buddy_menu(PurpleBuddy *buddy); void silcpurple_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group); void silcpurple_send_buddylist(PurpleConnection *gc); void silcpurple_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group); void silcpurple_buddy_keyagr_request(SilcClient client, - SilcClientConnection conn, - SilcClientEntry client_entry, - const char *hostname, SilcUInt16 port); + SilcClientConnection conn, + SilcClientEntry client_entry, + const char *hostname, SilcUInt16 port, + SilcUInt16 protocol); void silcpurple_idle_set(PurpleConnection *gc, int idle); void silcpurple_tooltip_text(PurpleBuddy *b, PurpleNotifyUserInfo *user_info, gboolean full); char *silcpurple_status_text(PurpleBuddy *b); @@ -140,17 +142,13 @@ PurpleRoomlist *silcpurple_roomlist_get_list(PurpleConnection *gc); void silcpurple_roomlist_cancel(PurpleRoomlist *list); void silcpurple_chat_chauth_show(SilcPurple sg, SilcChannelEntry channel, - SilcBuffer channel_pubkeys); + SilcDList channel_pubkeys); void silcpurple_parse_attrs(SilcDList attrs, char **moodstr, char **statusstr, char **contactstr, char **langstr, char **devicestr, char **tzstr, char **geostr); -#ifdef SILC_ATTRIBUTE_USER_ICON void silcpurple_buddy_set_icon(PurpleConnection *gc, PurpleStoredImage *img); -#endif -#ifdef HAVE_SILCMIME_H char *silcpurple_file2mime(const char *filename); SilcDList silcpurple_image_message(const char *msg, SilcUInt32 *mflags); -#endif #ifdef _WIN32 typedef int uid_t;
--- a/libpurple/protocols/silc/util.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/silc/util.c Mon Jun 18 01:48:35 2007 +0000 @@ -4,7 +4,7 @@ Author: Pekka Riikonen <priikone@silcnet.org> - Copyright (C) 2004 - 2005 Pekka Riikonen + Copyright (C) 2004 - 2007 Pekka Riikonen 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 @@ -17,7 +17,7 @@ */ -#include "silcincludes.h" +#include "silc.h" #include "silcclient.h" #include "silcpurple.h" #include "imgstore.h" @@ -206,22 +206,24 @@ if (errno == ENOENT) { purple_connection_update_progress(gc, _("Creating SILC key pair..."), 1, 5); if (!silc_create_key_pair(SILCPURPLE_DEF_PKCS, - SILCPURPLE_DEF_PKCS_LEN, - file_public_key, file_private_key, NULL, - (gc->password == NULL) ? "" : gc->password, - NULL, NULL, NULL, FALSE)) { - purple_debug_error("silc", "Couldn't create key pair\n"); + SILCPURPLE_DEF_PKCS_LEN, + file_public_key, + file_private_key, NULL, + (gc->password == NULL) + ? "" : gc->password, + NULL, NULL, FALSE)) { + purple_connection_error(gc, _("Cannot create SILC key pair\n")); return FALSE; } if ((g_stat(file_public_key, &st)) == -1) { purple_debug_error("silc", "Couldn't stat '%s' public key, error: %s\n", - file_public_key, strerror(errno)); + file_public_key, strerror(errno)); return FALSE; } } else { purple_debug_error("silc", "Couldn't stat '%s' public key, error: %s\n", - file_public_key, strerror(errno)); + file_public_key, strerror(errno)); return FALSE; } } @@ -237,7 +239,7 @@ if ((fd = g_open(file_private_key, O_RDONLY, 0)) != -1) { if ((fstat(fd, &st)) == -1) { purple_debug_error("silc", "Couldn't stat '%s' private key, error: %s\n", - file_private_key, strerror(errno)); + file_private_key, strerror(errno)); close(fd); return FALSE; } @@ -246,18 +248,20 @@ if (errno == ENOENT) { purple_connection_update_progress(gc, _("Creating SILC key pair..."), 1, 5); if (!silc_create_key_pair(SILCPURPLE_DEF_PKCS, - SILCPURPLE_DEF_PKCS_LEN, - file_public_key, file_private_key, NULL, - (gc->password == NULL) ? "" : gc->password, - NULL, NULL, NULL, FALSE)) { - purple_debug_error("silc", "Couldn't create key pair\n"); + SILCPURPLE_DEF_PKCS_LEN, + file_public_key, + file_private_key, NULL, + (gc->password == NULL) + ? "" : gc->password, + NULL, NULL, FALSE)) { + purple_connection_error(gc, _("Cannot create SILC key pair\n")); return FALSE; } if ((fd = g_open(file_private_key, O_RDONLY, 0)) != -1) { if ((fstat(fd, &st)) == -1) { purple_debug_error("silc", "Couldn't stat '%s' private key, error: %s\n", - file_private_key, strerror(errno)); + file_private_key, strerror(errno)); close(fd); return FALSE; } @@ -266,12 +270,12 @@ * will set the permissions */ else if ((g_stat(file_private_key, &st)) == -1) { purple_debug_error("silc", "Couldn't stat '%s' private key, error: %s\n", - file_private_key, strerror(errno)); + file_private_key, strerror(errno)); return FALSE; } } else { purple_debug_error("silc", "Couldn't stat '%s' private key, error: %s\n", - file_private_key, strerror(errno)); + file_private_key, strerror(errno)); return FALSE; } } @@ -323,30 +327,29 @@ #endif void silcpurple_show_public_key(SilcPurple sg, - const char *name, SilcPublicKey public_key, - GCallback callback, void *context) + const char *name, SilcPublicKey public_key, + GCallback callback, void *context) { SilcPublicKeyIdentifier ident; - SilcPKCS pkcs; + SilcSILCPublicKey silc_pubkey; char *fingerprint, *babbleprint; unsigned char *pk; SilcUInt32 pk_len, key_len = 0; GString *s; char *buf; - ident = silc_pkcs_decode_identifier(public_key->identifier); - if (!ident) - return; + /* We support showing only SILC public keys for now */ + if (silc_pkcs_get_type(public_key) != SILC_PKCS_SILC) + return; + + silc_pubkey = silc_pkcs_get_context(SILC_PKCS_SILC, public_key); + ident = &silc_pubkey->identifier; + key_len = silc_pkcs_public_key_get_len(public_key); pk = silc_pkcs_public_key_encode(public_key, &pk_len); fingerprint = silc_hash_fingerprint(NULL, pk, pk_len); babbleprint = silc_hash_babbleprint(NULL, pk, pk_len); - if (silc_pkcs_alloc((unsigned char *)public_key->name, &pkcs)) { - key_len = silc_pkcs_public_key_set(pkcs, public_key); - silc_pkcs_free(pkcs); - } - s = g_string_new(""); if (ident->realname) /* Hint for translators: Please check the tabulator width here and in @@ -363,8 +366,10 @@ g_string_append_printf(s, _("Organization: \t%s\n"), ident->org); if (ident->country) g_string_append_printf(s, _("Country: \t%s\n"), ident->country); - g_string_append_printf(s, _("Algorithm: \t%s\n"), public_key->name); + g_string_append_printf(s, _("Algorithm: \t%s\n"), silc_pubkey->pkcs->name); g_string_append_printf(s, _("Key Length: \t%d bits\n"), (int)key_len); + if (ident->version) + g_string_append_printf(s, _("Version: \t%s\n"), ident->version); g_string_append_printf(s, "\n"); g_string_append_printf(s, _("Public Key Fingerprint:\n%s\n\n"), fingerprint); g_string_append_printf(s, _("Public Key Babbleprint:\n%s"), babbleprint); @@ -372,15 +377,14 @@ buf = g_string_free(s, FALSE); purple_request_action(sg->gc, _("Public Key Information"), - _("Public Key Information"), - buf, 0, purple_connection_get_account(sg->gc), - NULL, NULL, context, 1, _("Close"), callback); + _("Public Key Information"), + buf, 0, purple_connection_get_account(sg->gc), + NULL, NULL, context, 1, _("Close"), callback); g_free(buf); silc_free(fingerprint); silc_free(babbleprint); silc_free(pk); - silc_pkcs_free_identifier(ident); } SilcAttributePayload @@ -400,7 +404,7 @@ } void silcpurple_get_umode_string(SilcUInt32 mode, char *buf, - SilcUInt32 buf_size) + SilcUInt32 buf_size) { memset(buf, 0, buf_size); if ((mode & SILC_UMODE_SERVER_OPERATOR) || @@ -435,7 +439,7 @@ } void silcpurple_get_chmode_string(SilcUInt32 mode, char *buf, - SilcUInt32 buf_size) + SilcUInt32 buf_size) { memset(buf, 0, buf_size); if (mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) @@ -482,8 +486,8 @@ void silcpurple_parse_attrs(SilcDList attrs, char **moodstr, char **statusstr, - char **contactstr, char **langstr, char **devicestr, - char **tzstr, char **geostr) + char **contactstr, char **langstr, char **devicestr, + char **tzstr, char **geostr) { SilcAttributePayload attr; SilcAttributeMood mood = 0; @@ -610,7 +614,6 @@ geo.accuracy ? geo.accuracy : ""); } -#ifdef HAVE_SILCMIME_H /* Returns MIME type of filetype */ char *silcpurple_file2mime(const char *filename) @@ -620,23 +623,23 @@ ct = strrchr(filename, '.'); if (!ct) return NULL; - else if (!g_ascii_strcasecmp(".png", ct)) + else if (!strcasecmp(".png", ct)) return strdup("image/png"); - else if (!g_ascii_strcasecmp(".jpg", ct)) + else if (!strcasecmp(".jpg", ct)) return strdup("image/jpeg"); - else if (!g_ascii_strcasecmp(".jpeg", ct)) + else if (!strcasecmp(".jpeg", ct)) return strdup("image/jpeg"); - else if (!g_ascii_strcasecmp(".gif", ct)) + else if (!strcasecmp(".gif", ct)) return strdup("image/gif"); - else if (!g_ascii_strcasecmp(".tiff", ct)) + else if (!strcasecmp(".tiff", ct)) return strdup("image/tiff"); - + return NULL; } -/* Checks if message has images, and assembles MIME message if it has. - If only one image is present, creates simple MIME image message. If - there are multiple images and/or text with images multipart MIME +/* Checks if message has images, and assembles MIME message if it has. + If only one image is present, creates simple MIME image message. If + there are multiple images and/or text with images multipart MIME message is created. */ SilcDList silcpurple_image_message(const char *msg, SilcUInt32 *mflags) @@ -666,8 +669,9 @@ tmp = g_strndup(last, start - last); text = purple_unescape_html(tmp); g_free(tmp); + /* Add text */ - silc_mime_add_data(p, text, strlen(text)); + silc_mime_add_data(p, (const unsigned char *)text, strlen(text)); g_free(text); if (!parts) @@ -720,7 +724,7 @@ "text/plain; charset=utf-8"); /* Add text */ - silc_mime_add_data(p, tmp, strlen(tmp)); + silc_mime_add_data(p, (const unsigned char *)tmp, strlen(tmp)); g_free(tmp); if (!parts) @@ -742,7 +746,7 @@ silc_mime_add_field(mime, "MIME-Version", "1.0"); g_snprintf(b, sizeof(b), "b%4X%4X", (unsigned int)time(NULL), - silc_dlist_count(parts)); + silc_dlist_count(parts)); silc_mime_set_multipart(mime, "mixed", b); silc_dlist_start(parts); while ((p = silc_dlist_get(parts)) != SILC_LIST_END) @@ -767,5 +771,3 @@ return list; } - -#endif /* HAVE_SILCMIME_H */
--- a/libpurple/protocols/silc/wb.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/silc/wb.c Mon Jun 18 01:48:35 2007 +0000 @@ -4,7 +4,7 @@ Author: Pekka Riikonen <priikone@silcnet.org> - Copyright (C) 2005 Pekka Riikonen + Copyright (C) 2005 - 2007 Pekka Riikonen 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 @@ -17,7 +17,7 @@ */ -#include "silcincludes.h" +#include "silc.h" #include "silcclient.h" #include "silcpurple.h" #include "wb.h" @@ -30,7 +30,7 @@ 2 bytes height 4 bytes brush color 2 bytes brush size - n bytes data + n bytes data Data: @@ -204,7 +204,7 @@ silc_buffer_pull(&buf, 8); x = dx; y = dy; - while (buf.len > 0) { + while (silc_buffer_len(&buf) > 0) { ret = silc_buffer_unformat(&buf, SILC_STR_UI_INT(&dx), SILC_STR_UI_INT(&dy), @@ -214,7 +214,7 @@ silc_buffer_pull(&buf, 8); purple_whiteboard_draw_line(wb, x, y, x + dx, y + dy, - brush_color, brush_size); + brush_color, brush_size); x += dx; y += dy; } @@ -253,8 +253,8 @@ } static void -silcpurple_wb_request(SilcClient client, const unsigned char *message, - SilcUInt32 message_len, SilcClientEntry sender, +silcpurple_wb_request(SilcClient client, const unsigned char *message, + SilcUInt32 message_len, SilcClientEntry sender, SilcChannelEntry channel) { char tmp[128]; @@ -406,16 +406,16 @@ /* Send the message */ if (wbs->type == 0) { /* Private message */ - silc_client_send_private_message(sg->client, sg->conn, - wbs->u.client, - SILC_MESSAGE_FLAG_DATA, - packet->head, len, TRUE); + silc_client_send_private_message(sg->client, sg->conn, + wbs->u.client, + SILC_MESSAGE_FLAG_DATA, NULL, + packet->head, len); } else if (wbs->type == 1) { /* Channel message. Channel private keys are not supported. */ silc_client_send_channel_message(sg->client, sg->conn, wbs->u.channel, NULL, - SILC_MESSAGE_FLAG_DATA, - packet->head, len, TRUE); + SILC_MESSAGE_FLAG_DATA, NULL, + packet->head, len); } silc_buffer_free(packet); @@ -501,16 +501,16 @@ /* Send the message */ if (wbs->type == 0) { /* Private message */ - silc_client_send_private_message(sg->client, sg->conn, - wbs->u.client, - SILC_MESSAGE_FLAG_DATA, - packet->head, len, TRUE); + silc_client_send_private_message(sg->client, sg->conn, + wbs->u.client, + SILC_MESSAGE_FLAG_DATA, NULL, + packet->head, len); } else if (wbs->type == 1) { /* Channel message */ silc_client_send_channel_message(sg->client, sg->conn, wbs->u.channel, NULL, - SILC_MESSAGE_FLAG_DATA, - packet->head, len, TRUE); + SILC_MESSAGE_FLAG_DATA, NULL, + packet->head, len); } silc_buffer_free(packet);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/silc10/Makefile.am Mon Jun 18 01:48:35 2007 +0000 @@ -0,0 +1,36 @@ +EXTRA_DIST = README TODO Makefile.mingw + +pkgdir = $(libdir)/purple-$(PURPLE_MAJOR_VERSION) + +SILCSOURCES = silc.c silcpurple.h buddy.c chat.c ft.c ops.c pk.c util.c wb.c wb.h + +AM_CFLAGS = $(st) + +libsilcpurple_la_LDFLAGS = -module -avoid-version + +if STATIC_SILC + +st = -DPURPLE_STATIC_PRPL $(SILC_CFLAGS) +noinst_LIBRARIES = libsilcpurple.a +pkg_LTLIBRARIES = + +libsilcpurple_a_SOURCES = $(SILCSOURCES) +libsilcpurple_a_CFLAGS = $(AM_CFLAGS) +libsilcpurple_a_LIBADD = $(SILC_LIBS) + +else + +st = $(SILC_CFLAGS) +pkg_LTLIBRARIES = libsilcpurple.la +noinst_LIBRARIES = + +libsilcpurple_la_SOURCES = $(SILCSOURCES) +libsilcpurple_la_LIBADD = $(GLIB_LIBS) $(SILC_LIBS) + +endif + +AM_CPPFLAGS = \ + -I$(top_srcdir)/libpurple \ + -I$(top_builddir)/libpurple \ + $(GLIB_CFLAGS) \ + $(DEBUG_CFLAGS)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/silc10/Makefile.mingw Mon Jun 18 01:48:35 2007 +0000 @@ -0,0 +1,91 @@ +# +# Makefile.mingw +# +# Description: Makefile for win32 (mingw) version of libsilc protocol plugin +# + +PIDGIN_TREE_TOP := ../../.. +include $(PIDGIN_TREE_TOP)/libpurple/win32/global.mak + +TARGET = libsilc +NEEDED_DLLS = $(SILC_TOOLKIT)/lib/silc.dll \ + $(SILC_TOOLKIT)/lib/silcclient.dll +TYPE = PLUGIN + +# Static or Plugin... +ifeq ($(TYPE),STATIC) + DEFINES += -DSTATIC + DLL_INSTALL_DIR = $(PURPLE_INSTALL_DIR) +else +ifeq ($(TYPE),PLUGIN) + DLL_INSTALL_DIR = $(PURPLE_INSTALL_PLUGINS_DIR) +endif +endif + +## +## INCLUDE PATHS +## +INCLUDE_PATHS += -I. \ + -I$(GTK_TOP)/include \ + -I$(GTK_TOP)/include/glib-2.0 \ + -I$(GTK_TOP)/lib/glib-2.0/include \ + -I$(PURPLE_TOP) \ + -I$(PURPLE_TOP)/win32 \ + -I$(PIDGIN_TREE_TOP) \ + -I$(SILC_TOOLKIT)/include + +LIB_PATHS += -L$(GTK_TOP)/lib \ + -L$(PURPLE_TOP) \ + -L$(SILC_TOOLKIT)/lib + +## +## SOURCES, OBJECTS +## +C_SRC = silc.c \ + buddy.c \ + chat.c \ + ft.c \ + ops.c \ + pk.c \ + util.c \ + wb.c + +OBJECTS = $(C_SRC:%.c=%.o) + +## +## LIBRARIES +## +LIBS = \ + -lglib-2.0 \ + -lws2_32 \ + -lintl \ + -lpurple \ + -lsilc \ + -lsilcclient + +include $(PIDGIN_COMMON_RULES) + +## +## TARGET DEFINITIONS +## +.PHONY: all install clean + +all: $(TARGET).dll + +install: all $(DLL_INSTALL_DIR) $(PURPLE_INSTALL_DIR) + cp $(TARGET).dll $(DLL_INSTALL_DIR) + cp $(NEEDED_DLLS) $(PURPLE_INSTALL_DIR) + +$(OBJECTS): $(PURPLE_CONFIG_H) + +$(TARGET).dll: $(PURPLE_DLL).a $(OBJECTS) + $(CC) -shared $(OBJECTS) $(LIB_PATHS) $(LIBS) $(DLL_LD_FLAGS) -Wl,--image-base,0x64000000 -o $(TARGET).dll + +## +## CLEAN RULES +## +clean: + rm -f $(OBJECTS) + rm -f $(TARGET).dll + +include $(PIDGIN_COMMON_TARGETS)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/silc10/README Mon Jun 18 01:48:35 2007 +0000 @@ -0,0 +1,31 @@ +SILC Purple Plugin +================== + +This is the Purple protocol plugin of the protocol called Secure Internet +Live Conferencing (SILC). The implementation will use the SILC Toolkit, +freely available from the http://silcnet.org/ site, for the actual SILC +protocol implementation. + +To include SILC into Purple, one needs to first compile and install +the SILC Toolkit. It is done as follows: + + ./configure --enable-shared + make + make install + +This will compile shared libraries of the SILC Toolkit. If the --prefix +is not given to ./configure, the binaries are installed into the +/usr/local/silc directory. + +Once the Toolkit is installed one needs to tell Purple's ./configure +script where the SILC Toolkit is located. It is done as simply as: + + ./configure + +if pkg-config is installed in your system. If it is isn't it's done as: + + ./configure --with-silc-libs=/path/to/silc/lib + --with-silc-includes=/path/to/silc/include + +If the SILC Toolkit cannot be found then the SILC protocol plugin will +not be compiled.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/silc10/TODO Mon Jun 18 01:48:35 2007 +0000 @@ -0,0 +1,8 @@ +Features TODO (maybe) +===================== + +Preferences + - Add joined channels to buddy list automatically (during + session) + - Add joined channels to buddy list automatically permanently +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/silc10/buddy.c Mon Jun 18 01:48:35 2007 +0000 @@ -0,0 +1,1728 @@ +/* + + silcpurple_buddy.c + + Author: Pekka Riikonen <priikone@silcnet.org> + + Copyright (C) 2004 Pekka Riikonen + + 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; version 2 of the License. + + 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. + +*/ + +#include "silcincludes.h" +#include "silcclient.h" +#include "silcpurple.h" +#include "wb.h" + +/***************************** Key Agreement *********************************/ + +static void +silcpurple_buddy_keyagr(PurpleBlistNode *node, gpointer data); + +static void +silcpurple_buddy_keyagr_do(PurpleConnection *gc, const char *name, + gboolean force_local); + +typedef struct { + char *nick; + PurpleConnection *gc; +} *SilcPurpleResolve; + +static void +silcpurple_buddy_keyagr_resolved(SilcClient client, + SilcClientConnection conn, + SilcClientEntry *clients, + SilcUInt32 clients_count, + void *context) +{ + PurpleConnection *gc = client->application; + SilcPurpleResolve r = context; + char tmp[256]; + + if (!clients) { + g_snprintf(tmp, sizeof(tmp), + _("User %s is not present in the network"), r->nick); + purple_notify_error(gc, _("Key Agreement"), + _("Cannot perform the key agreement"), tmp); + silc_free(r->nick); + silc_free(r); + return; + } + + silcpurple_buddy_keyagr_do(gc, r->nick, FALSE); + silc_free(r->nick); + silc_free(r); +} + +typedef struct { + gboolean responder; +} *SilcPurpleKeyAgr; + +static void +silcpurple_buddy_keyagr_cb(SilcClient client, + SilcClientConnection conn, + SilcClientEntry client_entry, + SilcKeyAgreementStatus status, + SilcSKEKeyMaterial *key, + void *context) +{ + PurpleConnection *gc = client->application; + SilcPurple sg = gc->proto_data; + SilcPurpleKeyAgr a = context; + + if (!sg->conn) + return; + + switch (status) { + case SILC_KEY_AGREEMENT_OK: + { + PurpleConversation *convo; + char tmp[128]; + + /* Set the private key for this client */ + silc_client_del_private_message_key(client, conn, client_entry); + silc_client_add_private_message_key_ske(client, conn, client_entry, + NULL, NULL, key, a->responder); + silc_ske_free_key_material(key); + + + /* Open IM window */ + convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, + client_entry->nickname, sg->account); + if (convo) { + /* we don't have windows in the core anymore...but we may want to + * provide some method for asking the UI to show the window + purple_conv_window_show(purple_conversation_get_window(convo)); + */ + } else { + convo = purple_conversation_new(PURPLE_CONV_TYPE_IM, sg->account, + client_entry->nickname); + } + g_snprintf(tmp, sizeof(tmp), "%s [private key]", client_entry->nickname); + purple_conversation_set_title(convo, tmp); + } + break; + + case SILC_KEY_AGREEMENT_ERROR: + purple_notify_error(gc, _("Key Agreement"), + _("Error occurred during key agreement"), NULL); + break; + + case SILC_KEY_AGREEMENT_FAILURE: + purple_notify_error(gc, _("Key Agreement"), _("Key Agreement failed"), NULL); + break; + + case SILC_KEY_AGREEMENT_TIMEOUT: + purple_notify_error(gc, _("Key Agreement"), + _("Timeout during key agreement"), NULL); + break; + + case SILC_KEY_AGREEMENT_ABORTED: + purple_notify_error(gc, _("Key Agreement"), + _("Key agreement was aborted"), NULL); + break; + + case SILC_KEY_AGREEMENT_ALREADY_STARTED: + purple_notify_error(gc, _("Key Agreement"), + _("Key agreement is already started"), NULL); + break; + + case SILC_KEY_AGREEMENT_SELF_DENIED: + purple_notify_error(gc, _("Key Agreement"), + _("Key agreement cannot be started with yourself"), + NULL); + break; + + default: + break; + } + + silc_free(a); +} + +static void +silcpurple_buddy_keyagr_do(PurpleConnection *gc, const char *name, + gboolean force_local) +{ + SilcPurple sg = gc->proto_data; + SilcClientEntry *clients; + SilcUInt32 clients_count; + char *local_ip = NULL, *remote_ip = NULL; + gboolean local = TRUE; + char *nickname; + SilcPurpleKeyAgr a; + + if (!sg->conn || !name) + return; + + if (!silc_parse_userfqdn(name, &nickname, NULL)) + return; + + /* Find client entry */ + clients = silc_client_get_clients_local(sg->client, sg->conn, nickname, name, + &clients_count); + if (!clients) { + /* Resolve unknown user */ + SilcPurpleResolve r = silc_calloc(1, sizeof(*r)); + if (!r) + return; + r->nick = g_strdup(name); + r->gc = gc; + silc_client_get_clients(sg->client, sg->conn, nickname, NULL, + silcpurple_buddy_keyagr_resolved, r); + silc_free(nickname); + return; + } + + /* Resolve the local IP from the outgoing socket connection. We resolve + it to check whether we have a private range IP address or public IP + address. If we have public then we will assume that we are not behind + NAT and will provide automatically the point of connection to the + agreement. If we have private range address we assume that we are + behind NAT and we let the responder provide the point of connection. + + The algorithm also checks the remote IP address of server connection. + If it is private range address and we have private range address we + assume that we are chatting in LAN and will provide the point of + connection. + + Naturally this algorithm does not always get things right. */ + + if (silc_net_check_local_by_sock(sg->conn->sock->sock, NULL, &local_ip)) { + /* Check if the IP is private */ + if (!force_local && silcpurple_ip_is_private(local_ip)) { + local = FALSE; + + /* Local IP is private, resolve the remote server IP to see whether + we are talking to Internet or just on LAN. */ + if (silc_net_check_host_by_sock(sg->conn->sock->sock, NULL, + &remote_ip)) + if (silcpurple_ip_is_private(remote_ip)) + /* We assume we are in LAN. Let's provide + the connection point. */ + local = TRUE; + } + } + + if (force_local) + local = TRUE; + + if (local && !local_ip) + local_ip = silc_net_localip(); + + a = silc_calloc(1, sizeof(*a)); + if (!a) + return; + a->responder = local; + + /* Send the key agreement request */ + silc_client_send_key_agreement(sg->client, sg->conn, clients[0], + local ? local_ip : NULL, NULL, 0, 60, + silcpurple_buddy_keyagr_cb, a); + + silc_free(local_ip); + silc_free(remote_ip); + silc_free(clients); +} + +typedef struct { + SilcClient client; + SilcClientConnection conn; + SilcClientID client_id; + char *hostname; + SilcUInt16 port; +} *SilcPurpleKeyAgrAsk; + +static void +silcpurple_buddy_keyagr_request_cb(SilcPurpleKeyAgrAsk a, gint id) +{ + SilcPurpleKeyAgr ai; + SilcClientEntry client_entry; + + if (id != 1) + goto out; + + /* Get the client entry. */ + client_entry = silc_client_get_client_by_id(a->client, a->conn, + &a->client_id); + if (!client_entry) { + purple_notify_error(a->client->application, _("Key Agreement"), + _("The remote user is not present in the network any more"), + NULL); + goto out; + } + + /* If the hostname was provided by the requestor perform the key agreement + now. Otherwise, we will send him a request to connect to us. */ + if (a->hostname) { + ai = silc_calloc(1, sizeof(*ai)); + if (!ai) + goto out; + ai->responder = FALSE; + silc_client_perform_key_agreement(a->client, a->conn, client_entry, + a->hostname, a->port, + silcpurple_buddy_keyagr_cb, ai); + } else { + /* Send request. Force us as the point of connection since requestor + did not provide the point of connection. */ + silcpurple_buddy_keyagr_do(a->client->application, + client_entry->nickname, TRUE); + } + + out: + silc_free(a->hostname); + silc_free(a); +} + +void silcpurple_buddy_keyagr_request(SilcClient client, + SilcClientConnection conn, + SilcClientEntry client_entry, + const char *hostname, SilcUInt16 port) +{ + char tmp[128], tmp2[128]; + SilcPurpleKeyAgrAsk a; + PurpleConnection *gc = client->application; + + g_snprintf(tmp, sizeof(tmp), + _("Key agreement request received from %s. Would you like to " + "perform the key agreement?"), client_entry->nickname); + if (hostname) + g_snprintf(tmp2, sizeof(tmp2), + _("The remote user is waiting key agreement on:\n" + "Remote host: %s\nRemote port: %d"), hostname, port); + + a = silc_calloc(1, sizeof(*a)); + if (!a) + return; + a->client = client; + a->conn = conn; + a->client_id = *client_entry->id; + if (hostname) + a->hostname = strdup(hostname); + a->port = port; + + purple_request_action(client->application, _("Key Agreement Request"), tmp, + hostname ? tmp2 : NULL, 1, gc->account, client_entry->nickname, + NULL, a, 2, _("Yes"), G_CALLBACK(silcpurple_buddy_keyagr_request_cb), + _("No"), G_CALLBACK(silcpurple_buddy_keyagr_request_cb)); +} + +static void +silcpurple_buddy_keyagr(PurpleBlistNode *node, gpointer data) +{ + PurpleBuddy *buddy; + + buddy = (PurpleBuddy *)node; + silcpurple_buddy_keyagr_do(buddy->account->gc, buddy->name, FALSE); +} + + +/**************************** Static IM Key **********************************/ + +static void +silcpurple_buddy_resetkey(PurpleBlistNode *node, gpointer data) +{ + PurpleBuddy *b; + PurpleConnection *gc; + SilcPurple sg; + char *nickname; + SilcClientEntry *clients; + SilcUInt32 clients_count; + + g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node)); + + b = (PurpleBuddy *) node; + gc = purple_account_get_connection(b->account); + sg = gc->proto_data; + + if (!silc_parse_userfqdn(b->name, &nickname, NULL)) + return; + + /* Find client entry */ + clients = silc_client_get_clients_local(sg->client, sg->conn, + nickname, b->name, + &clients_count); + if (!clients) { + silc_free(nickname); + return; + } + + clients[0]->prv_resp = FALSE; + silc_client_del_private_message_key(sg->client, sg->conn, + clients[0]); + silc_free(clients); + silc_free(nickname); +} + +typedef struct { + SilcClient client; + SilcClientConnection conn; + SilcClientID client_id; +} *SilcPurplePrivkey; + +static void +silcpurple_buddy_privkey(PurpleConnection *gc, const char *name); + +static void +silcpurple_buddy_privkey_cb(SilcPurplePrivkey p, const char *passphrase) +{ + SilcClientEntry client_entry; + + if (!passphrase || !(*passphrase)) { + silc_free(p); + return; + } + + /* Get the client entry. */ + client_entry = silc_client_get_client_by_id(p->client, p->conn, + &p->client_id); + if (!client_entry) { + purple_notify_error(p->client->application, _("IM With Password"), + _("The remote user is not present in the network any more"), + NULL); + silc_free(p); + return; + } + + /* Set the private message key */ + silc_client_del_private_message_key(p->client, p->conn, + client_entry); + silc_client_add_private_message_key(p->client, p->conn, + client_entry, NULL, NULL, + (unsigned char *)passphrase, + strlen(passphrase), FALSE, + client_entry->prv_resp); + if (!client_entry->prv_resp) + silc_client_send_private_message_key_request(p->client, + p->conn, + client_entry); + silc_free(p); +} + +static void +silcpurple_buddy_privkey_resolved(SilcClient client, + SilcClientConnection conn, + SilcClientEntry *clients, + SilcUInt32 clients_count, + void *context) +{ + char tmp[256]; + + if (!clients) { + g_snprintf(tmp, sizeof(tmp), + _("User %s is not present in the network"), + (const char *)context); + purple_notify_error(client->application, _("IM With Password"), + _("Cannot set IM key"), tmp); + g_free(context); + return; + } + + silcpurple_buddy_privkey(client->application, context); + silc_free(context); +} + +static void +silcpurple_buddy_privkey(PurpleConnection *gc, const char *name) +{ + SilcPurple sg = gc->proto_data; + char *nickname; + SilcPurplePrivkey p; + SilcClientEntry *clients; + SilcUInt32 clients_count; + + if (!name) + return; + if (!silc_parse_userfqdn(name, &nickname, NULL)) + return; + + /* Find client entry */ + clients = silc_client_get_clients_local(sg->client, sg->conn, + nickname, name, + &clients_count); + if (!clients) { + silc_client_get_clients(sg->client, sg->conn, nickname, NULL, + silcpurple_buddy_privkey_resolved, + g_strdup(name)); + silc_free(nickname); + return; + } + + p = silc_calloc(1, sizeof(*p)); + if (!p) + return; + p->client = sg->client; + p->conn = sg->conn; + p->client_id = *clients[0]->id; + purple_request_input(gc, _("IM With Password"), NULL, + _("Set IM Password"), NULL, FALSE, TRUE, NULL, + _("OK"), G_CALLBACK(silcpurple_buddy_privkey_cb), + _("Cancel"), G_CALLBACK(silcpurple_buddy_privkey_cb), + gc->account, NULL, NULL, p); + + silc_free(clients); + silc_free(nickname); +} + +static void +silcpurple_buddy_privkey_menu(PurpleBlistNode *node, gpointer data) +{ + PurpleBuddy *buddy; + PurpleConnection *gc; + + g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node)); + + buddy = (PurpleBuddy *) node; + gc = purple_account_get_connection(buddy->account); + + silcpurple_buddy_privkey(gc, buddy->name); +} + + +/**************************** Get Public Key *********************************/ + +typedef struct { + SilcClient client; + SilcClientConnection conn; + SilcClientID client_id; +} *SilcPurpleBuddyGetkey; + +static void +silcpurple_buddy_getkey(PurpleConnection *gc, const char *name); + +static void +silcpurple_buddy_getkey_cb(SilcPurpleBuddyGetkey g, + SilcClientCommandReplyContext cmd) +{ + SilcClientEntry client_entry; + unsigned char *pk; + SilcUInt32 pk_len; + + /* Get the client entry. */ + client_entry = silc_client_get_client_by_id(g->client, g->conn, + &g->client_id); + if (!client_entry) { + purple_notify_error(g->client->application, _("Get Public Key"), + _("The remote user is not present in the network any more"), + NULL); + silc_free(g); + return; + } + + if (!client_entry->public_key) { + silc_free(g); + return; + } + + /* Now verify the public key */ + pk = silc_pkcs_public_key_encode(client_entry->public_key, &pk_len); + silcpurple_verify_public_key(g->client, g->conn, client_entry->nickname, + SILC_SOCKET_TYPE_CLIENT, + pk, pk_len, SILC_SKE_PK_TYPE_SILC, + NULL, NULL); + silc_free(pk); + silc_free(g); +} + +static void +silcpurple_buddy_getkey_resolved(SilcClient client, + SilcClientConnection conn, + SilcClientEntry *clients, + SilcUInt32 clients_count, + void *context) +{ + char tmp[256]; + + if (!clients) { + g_snprintf(tmp, sizeof(tmp), + _("User %s is not present in the network"), + (const char *)context); + purple_notify_error(client->application, _("Get Public Key"), + _("Cannot fetch the public key"), tmp); + g_free(context); + return; + } + + silcpurple_buddy_getkey(client->application, context); + silc_free(context); +} + +static void +silcpurple_buddy_getkey(PurpleConnection *gc, const char *name) +{ + SilcPurple sg = gc->proto_data; + SilcClient client = sg->client; + SilcClientConnection conn = sg->conn; + SilcClientEntry *clients; + SilcUInt32 clients_count; + SilcPurpleBuddyGetkey g; + char *nickname; + + if (!name) + return; + + if (!silc_parse_userfqdn(name, &nickname, NULL)) + return; + + /* Find client entry */ + clients = silc_client_get_clients_local(client, conn, nickname, name, + &clients_count); + if (!clients) { + silc_client_get_clients(client, conn, nickname, NULL, + silcpurple_buddy_getkey_resolved, + g_strdup(name)); + silc_free(nickname); + return; + } + + /* Call GETKEY */ + g = silc_calloc(1, sizeof(*g)); + if (!g) + return; + g->client = client; + g->conn = conn; + g->client_id = *clients[0]->id; + silc_client_command_call(client, conn, NULL, "GETKEY", + clients[0]->nickname, NULL); + silc_client_command_pending(conn, SILC_COMMAND_GETKEY, + conn->cmd_ident, + (SilcCommandCb)silcpurple_buddy_getkey_cb, g); + silc_free(clients); + silc_free(nickname); +} + +static void +silcpurple_buddy_getkey_menu(PurpleBlistNode *node, gpointer data) +{ + PurpleBuddy *buddy; + PurpleConnection *gc; + + g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node)); + + buddy = (PurpleBuddy *) node; + gc = purple_account_get_connection(buddy->account); + + silcpurple_buddy_getkey(gc, buddy->name); +} + +static void +silcpurple_buddy_showkey(PurpleBlistNode *node, gpointer data) +{ + PurpleBuddy *b; + PurpleConnection *gc; + SilcPurple sg; + SilcPublicKey public_key; + const char *pkfile; + + g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node)); + + b = (PurpleBuddy *) node; + gc = purple_account_get_connection(b->account); + sg = gc->proto_data; + + pkfile = purple_blist_node_get_string(node, "public-key"); + if (!silc_pkcs_load_public_key(pkfile, &public_key, SILC_PKCS_FILE_PEM) && + !silc_pkcs_load_public_key(pkfile, &public_key, SILC_PKCS_FILE_BIN)) { + purple_notify_error(gc, + _("Show Public Key"), + _("Could not load public key"), NULL); + return; + } + + silcpurple_show_public_key(sg, b->name, public_key, NULL, NULL); + silc_pkcs_public_key_free(public_key); +} + + +/**************************** Buddy routines *********************************/ + +/* The buddies are implemented by using the WHOIS and WATCH commands that + can be used to search users by their public key. Since nicknames aren't + unique in SILC we cannot trust the buddy list using their nickname. We + associate public keys to buddies and use those to search and watch + in the network. + + The problem is that Purple does not return PurpleBuddy contexts to the + callbacks but the buddy names. Naturally, this is not going to work + with SILC. But, for now, we have to do what we can... */ + +typedef struct { + SilcClient client; + SilcClientConnection conn; + SilcClientID client_id; + PurpleBuddy *b; + unsigned char *offline_pk; + SilcUInt32 offline_pk_len; + unsigned int offline : 1; + unsigned int pubkey_search : 1; + unsigned int init : 1; +} *SilcPurpleBuddyRes; + +static void +silcpurple_add_buddy_ask_pk_cb(SilcPurpleBuddyRes r, gint id); +static void +silcpurple_add_buddy_resolved(SilcClient client, + SilcClientConnection conn, + SilcClientEntry *clients, + SilcUInt32 clients_count, + void *context); + +void silcpurple_get_info(PurpleConnection *gc, const char *who) +{ + SilcPurple sg = gc->proto_data; + SilcClient client = sg->client; + SilcClientConnection conn = sg->conn; + SilcClientEntry client_entry; + PurpleBuddy *b; + const char *filename, *nick = who; + char tmp[256]; + + if (!who) + return; + if (strlen(who) > 1 && who[0] == '@') + nick = who + 1; + if (strlen(who) > 1 && who[0] == '*') + nick = who + 1; + if (strlen(who) > 2 && who[0] == '*' && who[1] == '@') + nick = who + 2; + + b = purple_find_buddy(gc->account, nick); + if (b) { + /* See if we have this buddy's public key. If we do use that + to search the details. */ + filename = purple_blist_node_get_string((PurpleBlistNode *)b, "public-key"); + if (filename) { + /* Call WHOIS. The user info is displayed in the WHOIS + command reply. */ + silc_client_command_call(client, conn, NULL, "WHOIS", + "-details", "-pubkey", filename, NULL); + return; + } + + if (!b->proto_data) { + g_snprintf(tmp, sizeof(tmp), + _("User %s is not present in the network"), b->name); + purple_notify_error(gc, _("User Information"), + _("Cannot get user information"), tmp); + return; + } + + client_entry = silc_client_get_client_by_id(client, conn, b->proto_data); + if (client_entry) { + /* Call WHOIS. The user info is displayed in the WHOIS + command reply. */ + silc_client_command_call(client, conn, NULL, "WHOIS", + client_entry->nickname, "-details", NULL); + } + } else { + /* Call WHOIS just with nickname. */ + silc_client_command_call(client, conn, NULL, "WHOIS", nick, NULL); + } +} + +static void +silcpurple_add_buddy_pk_no(SilcPurpleBuddyRes r) +{ + char tmp[512]; + g_snprintf(tmp, sizeof(tmp), _("The %s buddy is not trusted"), + r->b->name); + purple_notify_error(r->client->application, _("Add Buddy"), tmp, + _("You cannot receive buddy notifications until you " + "import his/her public key. You can use the Get Public Key " + "command to get the public key.")); + purple_prpl_got_user_status(purple_buddy_get_account(r->b), purple_buddy_get_name(r->b), SILCPURPLE_STATUS_ID_OFFLINE, NULL); +} + +static void +silcpurple_add_buddy_save(bool success, void *context) +{ + SilcPurpleBuddyRes r = context; + PurpleBuddy *b = r->b; + SilcClient client = r->client; + SilcClientEntry client_entry; + SilcAttributePayload attr; + SilcAttribute attribute; + SilcVCardStruct vcard; + SilcAttributeObjMime message, extension; +#ifdef SILC_ATTRIBUTE_USER_ICON + SilcAttributeObjMime usericon; +#endif + SilcAttributeObjPk serverpk, usersign, serversign; + gboolean usign_success = TRUE, ssign_success = TRUE; + char filename[512], filename2[512], *fingerprint = NULL, *tmp; + SilcUInt32 len; + int i; + + if (!success) { + /* The user did not trust the public key. */ + silcpurple_add_buddy_pk_no(r); + silc_free(r); + return; + } + + if (r->offline) { + /* User is offline. Associate the imported public key with + this user. */ + fingerprint = silc_hash_fingerprint(NULL, r->offline_pk, + r->offline_pk_len); + for (i = 0; i < strlen(fingerprint); i++) + if (fingerprint[i] == ' ') + fingerprint[i] = '_'; + g_snprintf(filename, sizeof(filename) - 1, + "%s" G_DIR_SEPARATOR_S "clientkeys" G_DIR_SEPARATOR_S "clientkey_%s.pub", + silcpurple_silcdir(), fingerprint); + purple_blist_node_set_string((PurpleBlistNode *)b, "public-key", filename); + purple_prpl_got_user_status(purple_buddy_get_account(r->b), purple_buddy_get_name(r->b), SILCPURPLE_STATUS_ID_OFFLINE, NULL); + silc_free(fingerprint); + silc_free(r->offline_pk); + silc_free(r); + return; + } + + /* Get the client entry. */ + client_entry = silc_client_get_client_by_id(r->client, r->conn, + &r->client_id); + if (!client_entry) { + silc_free(r); + return; + } + + memset(&vcard, 0, sizeof(vcard)); + memset(&message, 0, sizeof(message)); + memset(&extension, 0, sizeof(extension)); +#ifdef SILC_ATTRIBUTE_USER_ICON + memset(&usericon, 0, sizeof(usericon)); +#endif + memset(&serverpk, 0, sizeof(serverpk)); + memset(&usersign, 0, sizeof(usersign)); + memset(&serversign, 0, sizeof(serversign)); + + /* Now that we have the public key and we trust it now we + save the attributes of the buddy and update its status. */ + + if (client_entry->attrs) { + silc_dlist_start(client_entry->attrs); + while ((attr = silc_dlist_get(client_entry->attrs)) + != SILC_LIST_END) { + attribute = silc_attribute_get_attribute(attr); + + switch (attribute) { + case SILC_ATTRIBUTE_USER_INFO: + if (!silc_attribute_get_object(attr, (void *)&vcard, + sizeof(vcard))) + continue; + break; + + case SILC_ATTRIBUTE_STATUS_MESSAGE: + if (!silc_attribute_get_object(attr, (void *)&message, + sizeof(message))) + continue; + break; + + case SILC_ATTRIBUTE_EXTENSION: + if (!silc_attribute_get_object(attr, (void *)&extension, + sizeof(extension))) + continue; + break; + +#ifdef SILC_ATTRIBUTE_USER_ICON + case SILC_ATTRIBUTE_USER_ICON: + if (!silc_attribute_get_object(attr, (void *)&usericon, + sizeof(usericon))) + continue; + break; +#endif + + case SILC_ATTRIBUTE_SERVER_PUBLIC_KEY: + if (serverpk.type) + continue; + if (!silc_attribute_get_object(attr, (void *)&serverpk, + sizeof(serverpk))) + continue; + break; + + case SILC_ATTRIBUTE_USER_DIGITAL_SIGNATURE: + if (usersign.data) + continue; + if (!silc_attribute_get_object(attr, (void *)&usersign, + sizeof(usersign))) + continue; + break; + + case SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE: + if (serversign.data) + continue; + if (!silc_attribute_get_object(attr, (void *)&serversign, + sizeof(serversign))) + continue; + break; + + default: + break; + } + } + } + + /* Verify the attribute signatures */ + + if (usersign.data) { + SilcPKCS pkcs; + unsigned char *verifyd; + SilcUInt32 verify_len; + + silc_pkcs_alloc((unsigned char*)"rsa", &pkcs); + verifyd = silc_attribute_get_verify_data(client_entry->attrs, + FALSE, &verify_len); + if (verifyd && silc_pkcs_public_key_set(pkcs, client_entry->public_key)){ + if (!silc_pkcs_verify_with_hash(pkcs, client->sha1hash, + usersign.data, + usersign.data_len, + verifyd, verify_len)) + usign_success = FALSE; + } + silc_free(verifyd); + } + + if (serversign.data && !strcmp(serverpk.type, "silc-rsa")) { + SilcPublicKey public_key; + SilcPKCS pkcs; + unsigned char *verifyd; + SilcUInt32 verify_len; + + if (silc_pkcs_public_key_decode(serverpk.data, serverpk.data_len, + &public_key)) { + silc_pkcs_alloc((unsigned char *)"rsa", &pkcs); + verifyd = silc_attribute_get_verify_data(client_entry->attrs, + TRUE, &verify_len); + if (verifyd && silc_pkcs_public_key_set(pkcs, public_key)) { + if (!silc_pkcs_verify_with_hash(pkcs, client->sha1hash, + serversign.data, + serversign.data_len, + verifyd, verify_len)) + ssign_success = FALSE; + } + silc_pkcs_public_key_free(public_key); + silc_free(verifyd); + } + } + + fingerprint = silc_fingerprint(client_entry->fingerprint, + client_entry->fingerprint_len); + for (i = 0; i < strlen(fingerprint); i++) + if (fingerprint[i] == ' ') + fingerprint[i] = '_'; + + if (usign_success || ssign_success) { + struct passwd *pw; + struct stat st; + + memset(filename2, 0, sizeof(filename2)); + + /* Filename for dir */ + tmp = fingerprint + strlen(fingerprint) - 9; + g_snprintf(filename, sizeof(filename) - 1, + "%s" G_DIR_SEPARATOR_S "friends" G_DIR_SEPARATOR_S "%s", + silcpurple_silcdir(), tmp); + + pw = getpwuid(getuid()); + if (!pw) + return; + + /* Create dir if it doesn't exist */ + if ((g_stat(filename, &st)) == -1) { + if (errno == ENOENT) { + if (pw->pw_uid == geteuid()) + g_mkdir(filename, 0755); + } + } + + /* Save VCard */ + g_snprintf(filename2, sizeof(filename2) - 1, + "%s" G_DIR_SEPARATOR_S "vcard", filename); + if (vcard.full_name) { + tmp = (char *)silc_vcard_encode(&vcard, &len); + silc_file_writefile(filename2, tmp, len); + silc_free(tmp); + } + + /* Save status message */ + if (message.mime) { + memset(filename2, 0, sizeof(filename2)); + g_snprintf(filename2, sizeof(filename2) - 1, + "%s" G_DIR_SEPARATOR_S "status_message.mime", + filename); + silc_file_writefile(filename2, (char *)message.mime, + message.mime_len); + } + + /* Save extension data */ + if (extension.mime) { + memset(filename2, 0, sizeof(filename2)); + g_snprintf(filename2, sizeof(filename2) - 1, + "%s" G_DIR_SEPARATOR_S "extension.mime", + filename); + silc_file_writefile(filename2, (char *)extension.mime, + extension.mime_len); + } + +#ifdef SILC_ATTRIBUTE_USER_ICON + /* Save user icon */ + if (usericon.mime) { + SilcMime m = silc_mime_decode(usericon.mime, + usericon.mime_len); + if (m) { + const char *type = silc_mime_get_field(m, "Content-Type"); + if (!strcmp(type, "image/jpeg") || + !strcmp(type, "image/gif") || + !strcmp(type, "image/bmp") || + !strcmp(type, "image/png")) { + const unsigned char *data; + SilcUInt32 data_len; + data = silc_mime_get_data(m, &data_len); + if (data) { + /* TODO: Check if SILC gives us something to use as the checksum instead */ + purple_buddy_icons_set_for_user(purple_buddy_get_account(r->b), purple_buddy_get_name(r->b), g_memdup(data, data_len), data_len, NULL); + } + } + silc_mime_free(m); + } + } +#endif + } + + /* Save the public key path to buddy properties, as it is used + to identify the buddy in the network (and not the nickname). */ + memset(filename, 0, sizeof(filename)); + g_snprintf(filename, sizeof(filename) - 1, + "%s" G_DIR_SEPARATOR_S "clientkeys" G_DIR_SEPARATOR_S "clientkey_%s.pub", + silcpurple_silcdir(), fingerprint); + purple_blist_node_set_string((PurpleBlistNode *)b, "public-key", filename); + + /* Update online status */ + purple_prpl_got_user_status(purple_buddy_get_account(r->b), purple_buddy_get_name(r->b), SILCPURPLE_STATUS_ID_AVAILABLE, NULL); + + /* Finally, start watching this user so we receive its status + changes from the server */ + g_snprintf(filename2, sizeof(filename2) - 1, "+%s", filename); + silc_client_command_call(r->client, r->conn, NULL, "WATCH", "-pubkey", + filename2, NULL); + + silc_free(fingerprint); + silc_free(r); +} + +static void +silcpurple_add_buddy_ask_import(void *user_data, const char *name) +{ + SilcPurpleBuddyRes r = (SilcPurpleBuddyRes)user_data; + SilcPublicKey public_key; + + /* Load the public key */ + if (!silc_pkcs_load_public_key(name, &public_key, SILC_PKCS_FILE_PEM) && + !silc_pkcs_load_public_key(name, &public_key, SILC_PKCS_FILE_BIN)) { + silcpurple_add_buddy_ask_pk_cb(r, 0); + purple_notify_error(r->client->application, + _("Add Buddy"), _("Could not load public key"), NULL); + return; + } + + /* Now verify the public key */ + r->offline_pk = silc_pkcs_public_key_encode(public_key, &r->offline_pk_len); + silcpurple_verify_public_key(r->client, r->conn, r->b->name, + SILC_SOCKET_TYPE_CLIENT, + r->offline_pk, r->offline_pk_len, + SILC_SKE_PK_TYPE_SILC, + silcpurple_add_buddy_save, r); +} + +static void +silcpurple_add_buddy_ask_pk_cancel(void *user_data, const char *name) +{ + SilcPurpleBuddyRes r = (SilcPurpleBuddyRes)user_data; + + /* The user did not import public key. The buddy is unusable. */ + silcpurple_add_buddy_pk_no(r); + silc_free(r); +} + +static void +silcpurple_add_buddy_ask_pk_cb(SilcPurpleBuddyRes r, gint id) +{ + if (id != 0) { + /* The user did not import public key. The buddy is unusable. */ + silcpurple_add_buddy_pk_no(r); + silc_free(r); + return; + } + + /* Open file selector to select the public key. */ + purple_request_file(r->client->application, _("Open..."), NULL, FALSE, + G_CALLBACK(silcpurple_add_buddy_ask_import), + G_CALLBACK(silcpurple_add_buddy_ask_pk_cancel), + purple_buddy_get_account(r->b), purple_buddy_get_name(r->b), NULL, r); + +} + +static void +silcpurple_add_buddy_ask_pk(SilcPurpleBuddyRes r) +{ + char tmp[512]; + g_snprintf(tmp, sizeof(tmp), _("The %s buddy is not present in the network"), + r->b->name); + purple_request_action(r->client->application, _("Add Buddy"), tmp, + _("To add the buddy you must import his/her public key. " + "Press Import to import a public key."), 0, + purple_buddy_get_account(r->b), purple_buddy_get_name(r->b), NULL, r, 2, + _("Cancel"), G_CALLBACK(silcpurple_add_buddy_ask_pk_cb), + _("_Import..."), G_CALLBACK(silcpurple_add_buddy_ask_pk_cb)); +} + +static void +silcpurple_add_buddy_getkey_cb(SilcPurpleBuddyRes r, + SilcClientCommandReplyContext cmd) +{ + SilcClientEntry client_entry; + unsigned char *pk; + SilcUInt32 pk_len; + + /* Get the client entry. */ + client_entry = silc_client_get_client_by_id(r->client, r->conn, + &r->client_id); + if (!client_entry || !client_entry->public_key) { + /* The buddy is offline/nonexistent. We will require user + to associate a public key with the buddy or the buddy + cannot be added. */ + r->offline = TRUE; + silcpurple_add_buddy_ask_pk(r); + return; + } + + /* Now verify the public key */ + pk = silc_pkcs_public_key_encode(client_entry->public_key, &pk_len); + silcpurple_verify_public_key(r->client, r->conn, client_entry->nickname, + SILC_SOCKET_TYPE_CLIENT, + pk, pk_len, SILC_SKE_PK_TYPE_SILC, + silcpurple_add_buddy_save, r); + silc_free(pk); +} + +static void +silcpurple_add_buddy_select_cb(SilcPurpleBuddyRes r, PurpleRequestFields *fields) +{ + PurpleRequestField *f; + const GList *list; + SilcClientEntry client_entry; + + f = purple_request_fields_get_field(fields, "list"); + list = purple_request_field_list_get_selected(f); + if (!list) { + /* The user did not select any user. */ + silcpurple_add_buddy_pk_no(r); + silc_free(r); + return; + } + + client_entry = purple_request_field_list_get_data(f, list->data); + silcpurple_add_buddy_resolved(r->client, r->conn, &client_entry, 1, r); +} + +static void +silcpurple_add_buddy_select_cancel(SilcPurpleBuddyRes r, PurpleRequestFields *fields) +{ + /* The user did not select any user. */ + silcpurple_add_buddy_pk_no(r); + silc_free(r); +} + +static void +silcpurple_add_buddy_select(SilcPurpleBuddyRes r, + SilcClientEntry *clients, + SilcUInt32 clients_count) +{ + PurpleRequestFields *fields; + PurpleRequestFieldGroup *g; + PurpleRequestField *f; + char tmp[512], tmp2[128]; + int i; + char *fingerprint; + + fields = purple_request_fields_new(); + g = purple_request_field_group_new(NULL); + f = purple_request_field_list_new("list", NULL); + purple_request_field_group_add_field(g, f); + purple_request_field_list_set_multi_select(f, FALSE); + purple_request_fields_add_group(fields, g); + + for (i = 0; i < clients_count; i++) { + fingerprint = NULL; + if (clients[i]->fingerprint) { + fingerprint = silc_fingerprint(clients[i]->fingerprint, + clients[i]->fingerprint_len); + g_snprintf(tmp2, sizeof(tmp2), "\n%s", fingerprint); + } + g_snprintf(tmp, sizeof(tmp), "%s - %s (%s@%s)%s", + clients[i]->realname, clients[i]->nickname, + clients[i]->username, clients[i]->hostname ? + clients[i]->hostname : "", + fingerprint ? tmp2 : ""); + purple_request_field_list_add(f, tmp, clients[i]); + silc_free(fingerprint); + } + + purple_request_fields(r->client->application, _("Add Buddy"), + _("Select correct user"), + r->pubkey_search + ? _("More than one user was found with the same public key. Select " + "the correct user from the list to add to the buddy list.") + : _("More than one user was found with the same name. Select " + "the correct user from the list to add to the buddy list."), + fields, + _("OK"), G_CALLBACK(silcpurple_add_buddy_select_cb), + _("Cancel"), G_CALLBACK(silcpurple_add_buddy_select_cancel), + purple_buddy_get_account(r->b), purple_buddy_get_name(r->b), NULL, r); +} + +static void +silcpurple_add_buddy_resolved(SilcClient client, + SilcClientConnection conn, + SilcClientEntry *clients, + SilcUInt32 clients_count, + void *context) +{ + SilcPurpleBuddyRes r = context; + PurpleBuddy *b = r->b; + SilcAttributePayload pub; + SilcAttributeObjPk userpk; + unsigned char *pk; + SilcUInt32 pk_len; + const char *filename; + + filename = purple_blist_node_get_string((PurpleBlistNode *)b, "public-key"); + + /* If the buddy is offline/nonexistent, we will require user + to associate a public key with the buddy or the buddy + cannot be added. */ + if (!clients_count) { + if (r->init) { + silc_free(r); + return; + } + + r->offline = TRUE; + /* If the user has already associated a public key, try loading it + * before prompting the user to load it again */ + if (filename != NULL) + silcpurple_add_buddy_ask_import(r, filename); + else + silcpurple_add_buddy_ask_pk(r); + return; + } + + /* If more than one client was found with nickname, we need to verify + from user which one is the correct. */ + if (clients_count > 1 && !r->pubkey_search) { + if (r->init) { + silc_free(r); + return; + } + + silcpurple_add_buddy_select(r, clients, clients_count); + return; + } + + /* If we searched using public keys and more than one entry was found + the same person is logged on multiple times. */ + if (clients_count > 1 && r->pubkey_search && b->name) { + if (r->init) { + /* Find the entry that closest matches to the + buddy nickname. */ + int i; + for (i = 0; i < clients_count; i++) { + if (!strncasecmp(b->name, clients[i]->nickname, + strlen(b->name))) { + clients[0] = clients[i]; + break; + } + } + } else { + /* Verify from user which one is correct */ + silcpurple_add_buddy_select(r, clients, clients_count); + return; + } + } + + /* The client was found. Now get its public key and verify + that before adding the buddy. */ + memset(&userpk, 0, sizeof(userpk)); + b->proto_data = silc_memdup(clients[0]->id, sizeof(*clients[0]->id)); + r->client_id = *clients[0]->id; + + /* Get the public key from attributes, if not present then + resolve it with GETKEY unless we have it cached already. */ + if (clients[0]->attrs && !clients[0]->public_key) { + pub = silcpurple_get_attr(clients[0]->attrs, + SILC_ATTRIBUTE_USER_PUBLIC_KEY); + if (!pub || !silc_attribute_get_object(pub, (void *)&userpk, + sizeof(userpk))) { + /* Get public key with GETKEY */ + silc_client_command_call(client, conn, NULL, + "GETKEY", clients[0]->nickname, NULL); + silc_client_command_pending(conn, SILC_COMMAND_GETKEY, + conn->cmd_ident, + (SilcCommandCb)silcpurple_add_buddy_getkey_cb, + r); + return; + } + if (!silc_pkcs_public_key_decode(userpk.data, userpk.data_len, + &clients[0]->public_key)) + return; + silc_free(userpk.data); + } else if (filename && !clients[0]->public_key) { + if (!silc_pkcs_load_public_key(filename, &clients[0]->public_key, + SILC_PKCS_FILE_PEM) && + !silc_pkcs_load_public_key(filename, &clients[0]->public_key, + SILC_PKCS_FILE_BIN)) { + /* Get public key with GETKEY */ + silc_client_command_call(client, conn, NULL, + "GETKEY", clients[0]->nickname, NULL); + silc_client_command_pending(conn, SILC_COMMAND_GETKEY, + conn->cmd_ident, + (SilcCommandCb)silcpurple_add_buddy_getkey_cb, + r); + return; + } + } else if (!clients[0]->public_key) { + /* Get public key with GETKEY */ + silc_client_command_call(client, conn, NULL, + "GETKEY", clients[0]->nickname, NULL); + silc_client_command_pending(conn, SILC_COMMAND_GETKEY, + conn->cmd_ident, + (SilcCommandCb)silcpurple_add_buddy_getkey_cb, + r); + return; + } + + /* We have the public key, verify it. */ + pk = silc_pkcs_public_key_encode(clients[0]->public_key, &pk_len); + silcpurple_verify_public_key(client, conn, clients[0]->nickname, + SILC_SOCKET_TYPE_CLIENT, + pk, pk_len, SILC_SKE_PK_TYPE_SILC, + silcpurple_add_buddy_save, r); + silc_free(pk); +} + +static void +silcpurple_add_buddy_i(PurpleConnection *gc, PurpleBuddy *b, gboolean init) +{ + SilcPurple sg = gc->proto_data; + SilcClient client = sg->client; + SilcClientConnection conn = sg->conn; + SilcPurpleBuddyRes r; + SilcBuffer attrs; + const char *filename, *name = b->name; + + r = silc_calloc(1, sizeof(*r)); + if (!r) + return; + r->client = client; + r->conn = conn; + r->b = b; + r->init = init; + + /* See if we have this buddy's public key. If we do use that + to search the details. */ + filename = purple_blist_node_get_string((PurpleBlistNode *)b, "public-key"); + if (filename) { + SilcPublicKey public_key; + SilcAttributeObjPk userpk; + + if (!silc_pkcs_load_public_key(filename, &public_key, + SILC_PKCS_FILE_PEM) && + !silc_pkcs_load_public_key(filename, &public_key, + SILC_PKCS_FILE_BIN)) + return; + + /* Get all attributes, and use the public key to search user */ + name = NULL; + attrs = silc_client_attributes_request(SILC_ATTRIBUTE_USER_INFO, + SILC_ATTRIBUTE_SERVICE, + SILC_ATTRIBUTE_STATUS_MOOD, + SILC_ATTRIBUTE_STATUS_FREETEXT, + SILC_ATTRIBUTE_STATUS_MESSAGE, + SILC_ATTRIBUTE_PREFERRED_LANGUAGE, + SILC_ATTRIBUTE_PREFERRED_CONTACT, + SILC_ATTRIBUTE_TIMEZONE, + SILC_ATTRIBUTE_GEOLOCATION, +#ifdef SILC_ATTRIBUTE_USER_ICON + SILC_ATTRIBUTE_USER_ICON, +#endif + SILC_ATTRIBUTE_DEVICE_INFO, 0); + userpk.type = "silc-rsa"; + userpk.data = silc_pkcs_public_key_encode(public_key, &userpk.data_len); + attrs = silc_attribute_payload_encode(attrs, + SILC_ATTRIBUTE_USER_PUBLIC_KEY, + SILC_ATTRIBUTE_FLAG_VALID, + &userpk, sizeof(userpk)); + silc_free(userpk.data); + silc_pkcs_public_key_free(public_key); + r->pubkey_search = TRUE; + } else { + /* Get all attributes */ + attrs = silc_client_attributes_request(0); + } + + /* Resolve */ + silc_client_get_clients_whois(client, conn, name, NULL, attrs, + silcpurple_add_buddy_resolved, r); + silc_buffer_free(attrs); +} + +void silcpurple_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group) +{ + silcpurple_add_buddy_i(gc, buddy, FALSE); +} + +void silcpurple_send_buddylist(PurpleConnection *gc) +{ + PurpleBuddyList *blist; + PurpleBlistNode *gnode, *cnode, *bnode; + PurpleBuddy *buddy; + PurpleAccount *account; + + account = purple_connection_get_account(gc); + + if ((blist = purple_get_blist()) != NULL) + { + for (gnode = blist->root; gnode != NULL; gnode = gnode->next) + { + if (!PURPLE_BLIST_NODE_IS_GROUP(gnode)) + continue; + for (cnode = gnode->child; cnode != NULL; cnode = cnode->next) + { + if (!PURPLE_BLIST_NODE_IS_CONTACT(cnode)) + continue; + for (bnode = cnode->child; bnode != NULL; bnode = bnode->next) + { + if (!PURPLE_BLIST_NODE_IS_BUDDY(bnode)) + continue; + buddy = (PurpleBuddy *)bnode; + if (purple_buddy_get_account(buddy) == account) + silcpurple_add_buddy_i(gc, buddy, TRUE); + } + } + } + } +} + +void silcpurple_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy, + PurpleGroup *group) +{ + silc_free(buddy->proto_data); +} + +void silcpurple_idle_set(PurpleConnection *gc, int idle) + +{ + SilcPurple sg = gc->proto_data; + SilcClient client = sg->client; + SilcClientConnection conn = sg->conn; + SilcAttributeObjService service; + const char *server; + int port; + + server = purple_account_get_string(sg->account, "server", + "silc.silcnet.org"); + port = purple_account_get_int(sg->account, "port", 706), + + memset(&service, 0, sizeof(service)); + silc_client_attribute_del(client, conn, + SILC_ATTRIBUTE_SERVICE, NULL); + service.port = port; + g_snprintf(service.address, sizeof(service.address), "%s", server); + service.idle = idle; + silc_client_attribute_add(client, conn, SILC_ATTRIBUTE_SERVICE, + &service, sizeof(service)); +} + +char *silcpurple_status_text(PurpleBuddy *b) +{ + SilcPurple sg = b->account->gc->proto_data; + SilcClient client = sg->client; + SilcClientConnection conn = sg->conn; + SilcClientID *client_id = b->proto_data; + SilcClientEntry client_entry; + SilcAttributePayload attr; + SilcAttributeMood mood = 0; + + /* Get the client entry. */ + client_entry = silc_client_get_client_by_id(client, conn, client_id); + if (!client_entry) + return NULL; + + /* If user is online, we show the mood status, if available. + If user is offline or away that status is indicated. */ + + if (client_entry->mode & SILC_UMODE_DETACHED) + return g_strdup(_("Detached")); + if (client_entry->mode & SILC_UMODE_GONE) + return g_strdup(_("Away")); + if (client_entry->mode & SILC_UMODE_INDISPOSED) + return g_strdup(_("Indisposed")); + if (client_entry->mode & SILC_UMODE_BUSY) + return g_strdup(_("Busy")); + if (client_entry->mode & SILC_UMODE_PAGE) + return g_strdup(_("Wake Me Up")); + if (client_entry->mode & SILC_UMODE_HYPER) + return g_strdup(_("Hyper Active")); + if (client_entry->mode & SILC_UMODE_ROBOT) + return g_strdup(_("Robot")); + + attr = silcpurple_get_attr(client_entry->attrs, SILC_ATTRIBUTE_STATUS_MOOD); + if (attr && silc_attribute_get_object(attr, &mood, sizeof(mood))) { + /* The mood is a bit mask, so we could show multiple moods, + but let's show only one for now. */ + if (mood & SILC_ATTRIBUTE_MOOD_HAPPY) + return g_strdup(_("Happy")); + if (mood & SILC_ATTRIBUTE_MOOD_SAD) + return g_strdup(_("Sad")); + if (mood & SILC_ATTRIBUTE_MOOD_ANGRY) + return g_strdup(_("Angry")); + if (mood & SILC_ATTRIBUTE_MOOD_JEALOUS) + return g_strdup(_("Jealous")); + if (mood & SILC_ATTRIBUTE_MOOD_ASHAMED) + return g_strdup(_("Ashamed")); + if (mood & SILC_ATTRIBUTE_MOOD_INVINCIBLE) + return g_strdup(_("Invincible")); + if (mood & SILC_ATTRIBUTE_MOOD_INLOVE) + return g_strdup(_("In Love")); + if (mood & SILC_ATTRIBUTE_MOOD_SLEEPY) + return g_strdup(_("Sleepy")); + if (mood & SILC_ATTRIBUTE_MOOD_BORED) + return g_strdup(_("Bored")); + if (mood & SILC_ATTRIBUTE_MOOD_EXCITED) + return g_strdup(_("Excited")); + if (mood & SILC_ATTRIBUTE_MOOD_ANXIOUS) + return g_strdup(_("Anxious")); + } + + return NULL; +} + +void silcpurple_tooltip_text(PurpleBuddy *b, PurpleNotifyUserInfo *user_info, gboolean full) +{ + SilcPurple sg = b->account->gc->proto_data; + SilcClient client = sg->client; + SilcClientConnection conn = sg->conn; + SilcClientID *client_id = b->proto_data; + SilcClientEntry client_entry; + char *moodstr, *statusstr, *contactstr, *langstr, *devicestr, *tzstr, *geostr; + char tmp[256]; + + /* Get the client entry. */ + client_entry = silc_client_get_client_by_id(client, conn, client_id); + if (!client_entry) + return; + + if (client_entry->nickname) + purple_notify_user_info_add_pair(user_info, _("Nickname"), + client_entry->nickname); + if (client_entry->username && client_entry->hostname) { + g_snprintf(tmp, sizeof(tmp), "%s@%s", client_entry->username, client_entry->hostname); + purple_notify_user_info_add_pair(user_info, _("Username"), tmp); + } + if (client_entry->mode) { + memset(tmp, 0, sizeof(tmp)); + silcpurple_get_umode_string(client_entry->mode, + tmp, sizeof(tmp) - strlen(tmp)); + purple_notify_user_info_add_pair(user_info, _("User Modes"), tmp); + } + + silcpurple_parse_attrs(client_entry->attrs, &moodstr, &statusstr, &contactstr, &langstr, &devicestr, &tzstr, &geostr); + + if (statusstr) { + purple_notify_user_info_add_pair(user_info, _("Message"), statusstr); + g_free(statusstr); + } + + if (full) { + if (moodstr) { + purple_notify_user_info_add_pair(user_info, _("Mood"), moodstr); + g_free(moodstr); + } + + if (contactstr) { + purple_notify_user_info_add_pair(user_info, _("Preferred Contact"), contactstr); + g_free(contactstr); + } + + if (langstr) { + purple_notify_user_info_add_pair(user_info, _("Preferred Language"), langstr); + g_free(langstr); + } + + if (devicestr) { + purple_notify_user_info_add_pair(user_info, _("Device"), devicestr); + g_free(devicestr); + } + + if (tzstr) { + purple_notify_user_info_add_pair(user_info, _("Timezone"), tzstr); + g_free(tzstr); + } + + if (geostr) { + purple_notify_user_info_add_pair(user_info, _("Geolocation"), geostr); + g_free(geostr); + } + } +} + +static void +silcpurple_buddy_kill(PurpleBlistNode *node, gpointer data) +{ + PurpleBuddy *b; + PurpleConnection *gc; + SilcPurple sg; + + g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node)); + + b = (PurpleBuddy *) node; + gc = purple_account_get_connection(b->account); + sg = gc->proto_data; + + /* Call KILL */ + silc_client_command_call(sg->client, sg->conn, NULL, "KILL", + b->name, "Killed by operator", NULL); +} + +typedef struct { + SilcPurple sg; + SilcClientEntry client_entry; +} *SilcPurpleBuddyWb; + +static void +silcpurple_buddy_wb(PurpleBlistNode *node, gpointer data) +{ + SilcPurpleBuddyWb wb = data; + silcpurple_wb_init(wb->sg, wb->client_entry); + silc_free(wb); +} + +GList *silcpurple_buddy_menu(PurpleBuddy *buddy) +{ + PurpleConnection *gc = purple_account_get_connection(buddy->account); + SilcPurple sg = gc->proto_data; + SilcClientConnection conn = sg->conn; + const char *pkfile = NULL; + SilcClientEntry client_entry = NULL; + PurpleMenuAction *act; + GList *m = NULL; + SilcPurpleBuddyWb wb; + + pkfile = purple_blist_node_get_string((PurpleBlistNode *) buddy, "public-key"); + client_entry = silc_client_get_client_by_id(sg->client, + sg->conn, + buddy->proto_data); + + if (client_entry && client_entry->send_key) { + act = purple_menu_action_new(_("Reset IM Key"), + PURPLE_CALLBACK(silcpurple_buddy_resetkey), + NULL, NULL); + m = g_list_append(m, act); + + } else { + act = purple_menu_action_new(_("IM with Key Exchange"), + PURPLE_CALLBACK(silcpurple_buddy_keyagr), + NULL, NULL); + m = g_list_append(m, act); + + act = purple_menu_action_new(_("IM with Password"), + PURPLE_CALLBACK(silcpurple_buddy_privkey_menu), + NULL, NULL); + m = g_list_append(m, act); + } + + if (pkfile) { + act = purple_menu_action_new(_("Show Public Key"), + PURPLE_CALLBACK(silcpurple_buddy_showkey), + NULL, NULL); + m = g_list_append(m, act); + + } else { + act = purple_menu_action_new(_("Get Public Key..."), + PURPLE_CALLBACK(silcpurple_buddy_getkey_menu), + NULL, NULL); + m = g_list_append(m, act); + } + + if (conn && conn->local_entry->mode & SILC_UMODE_ROUTER_OPERATOR) { + act = purple_menu_action_new(_("Kill User"), + PURPLE_CALLBACK(silcpurple_buddy_kill), + NULL, NULL); + m = g_list_append(m, act); + } + + if (client_entry) { + wb = silc_calloc(1, sizeof(*wb)); + wb->sg = sg; + wb->client_entry = client_entry; + act = purple_menu_action_new(_("Draw On Whiteboard"), + PURPLE_CALLBACK(silcpurple_buddy_wb), + (void *)wb, NULL); + m = g_list_append(m, act); + } + return m; +} + +#ifdef SILC_ATTRIBUTE_USER_ICON +void silcpurple_buddy_set_icon(PurpleConnection *gc, PurpleStoredImage *img) +{ + SilcPurple sg = gc->proto_data; + SilcClient client = sg->client; + SilcClientConnection conn = sg->conn; + SilcMime mime; + char type[32]; + unsigned char *icon; + const char *t; + SilcAttributeObjMime obj; + + /* Remove */ + if (!img) { + silc_client_attribute_del(client, conn, + SILC_ATTRIBUTE_USER_ICON, NULL); + return; + } + + /* Add */ + mime = silc_mime_alloc(); + if (!mime) + return; + + t = purple_imgstore_get_extension(img); + if (!t || !strcmp(t, "icon")) { + silc_mime_free(mime); + return; + } + if (!strcmp(t, "jpg")) + t = "jpeg"; + g_snprintf(type, sizeof(type), "image/%s", t); + silc_mime_add_field(mime, "Content-Type", type); + silc_mime_add_data(mime, purple_imgstore_get_data(img), purple_imgstore_get_size(img)); + + obj.mime = icon = silc_mime_encode(mime, &obj.mime_len); + if (obj.mime) + silc_client_attribute_add(client, conn, + SILC_ATTRIBUTE_USER_ICON, &obj, sizeof(obj)); + + silc_free(icon); + silc_mime_free(mime); +} +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/silc10/chat.c Mon Jun 18 01:48:35 2007 +0000 @@ -0,0 +1,1456 @@ +/* + + silcpurple_chat.c + + Author: Pekka Riikonen <priikone@silcnet.org> + + Copyright (C) 2004 Pekka Riikonen + + 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; version 2 of the License. + + 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. + +*/ + +#include "silcincludes.h" +#include "silcclient.h" +#include "silcpurple.h" +#include "wb.h" + +/***************************** Channel Routines ******************************/ + +GList *silcpurple_chat_info(PurpleConnection *gc) +{ + GList *ci = NULL; + struct proto_chat_entry *pce; + + pce = g_new0(struct proto_chat_entry, 1); + pce->label = _("_Channel:"); + pce->identifier = "channel"; + pce->required = TRUE; + ci = g_list_append(ci, pce); + + pce = g_new0(struct proto_chat_entry, 1); + pce->label = _("_Passphrase:"); + pce->identifier = "passphrase"; + pce->secret = TRUE; + ci = g_list_append(ci, pce); + + return ci; +} + +GHashTable *silcpurple_chat_info_defaults(PurpleConnection *gc, const char *chat_name) +{ + GHashTable *defaults; + + defaults = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, g_free); + + if (chat_name != NULL) + g_hash_table_insert(defaults, "channel", g_strdup(chat_name)); + + return defaults; +} + +static void +silcpurple_chat_getinfo(PurpleConnection *gc, GHashTable *components); + +static void +silcpurple_chat_getinfo_res(SilcClient client, + SilcClientConnection conn, + SilcChannelEntry *channels, + SilcUInt32 channels_count, + void *context) +{ + GHashTable *components = context; + PurpleConnection *gc = client->application; + const char *chname; + char tmp[256]; + + chname = g_hash_table_lookup(components, "channel"); + if (!chname) + return; + + if (!channels) { + g_snprintf(tmp, sizeof(tmp), + _("Channel %s does not exist in the network"), chname); + purple_notify_error(gc, _("Channel Information"), + _("Cannot get channel information"), tmp); + return; + } + + silcpurple_chat_getinfo(gc, components); +} + + +static void +silcpurple_chat_getinfo(PurpleConnection *gc, GHashTable *components) +{ + SilcPurple sg = gc->proto_data; + const char *chname; + char *buf, tmp[256], *tmp2; + GString *s; + SilcChannelEntry channel; + SilcHashTableList htl; + SilcChannelUser chu; + + if (!components) + return; + + chname = g_hash_table_lookup(components, "channel"); + if (!chname) + return; + channel = silc_client_get_channel(sg->client, sg->conn, + (char *)chname); + if (!channel) { + silc_client_get_channel_resolve(sg->client, sg->conn, + (char *)chname, + silcpurple_chat_getinfo_res, + components); + return; + } + + s = g_string_new(""); + tmp2 = g_markup_escape_text(channel->channel_name, -1); + g_string_append_printf(s, _("<b>Channel Name:</b> %s"), tmp2); + g_free(tmp2); + if (channel->user_list && silc_hash_table_count(channel->user_list)) + g_string_append_printf(s, _("<br><b>User Count:</b> %d"), + (int)silc_hash_table_count(channel->user_list)); + + silc_hash_table_list(channel->user_list, &htl); + while (silc_hash_table_get(&htl, NULL, (void *)&chu)) { + if (chu->mode & SILC_CHANNEL_UMODE_CHANFO) { + tmp2 = g_markup_escape_text(chu->client->nickname, -1); + g_string_append_printf(s, _("<br><b>Channel Founder:</b> %s"), + tmp2); + g_free(tmp2); + break; + } + } + silc_hash_table_list_reset(&htl); + + if (channel->channel_key) + g_string_append_printf(s, _("<br><b>Channel Cipher:</b> %s"), + silc_cipher_get_name(channel->channel_key)); + if (channel->hmac) + /* Definition of HMAC: http://en.wikipedia.org/wiki/HMAC */ + g_string_append_printf(s, _("<br><b>Channel HMAC:</b> %s"), + silc_hmac_get_name(channel->hmac)); + + if (channel->topic) { + tmp2 = g_markup_escape_text(channel->topic, -1); + g_string_append_printf(s, _("<br><b>Channel Topic:</b><br>%s"), tmp2); + g_free(tmp2); + } + + if (channel->mode) { + g_string_append_printf(s, _("<br><b>Channel Modes:</b> ")); + silcpurple_get_chmode_string(channel->mode, tmp, sizeof(tmp)); + g_string_append(s, tmp); + } + + if (channel->founder_key) { + char *fingerprint, *babbleprint; + unsigned char *pk; + SilcUInt32 pk_len; + pk = silc_pkcs_public_key_encode(channel->founder_key, &pk_len); + fingerprint = silc_hash_fingerprint(NULL, pk, pk_len); + babbleprint = silc_hash_babbleprint(NULL, pk, pk_len); + + g_string_append_printf(s, _("<br><b>Founder Key Fingerprint:</b><br>%s"), fingerprint); + g_string_append_printf(s, _("<br><b>Founder Key Babbleprint:</b><br>%s"), babbleprint); + + silc_free(fingerprint); + silc_free(babbleprint); + silc_free(pk); + } + + buf = g_string_free(s, FALSE); + purple_notify_formatted(gc, NULL, _("Channel Information"), NULL, buf, NULL, NULL); + g_free(buf); +} + + +static void +silcpurple_chat_getinfo_menu(PurpleBlistNode *node, gpointer data) +{ + PurpleChat *chat = (PurpleChat *)node; + silcpurple_chat_getinfo(chat->account->gc, chat->components); +} + + +#if 0 /* XXX For now these are not implemented. We need better + listview dialog from Purple for these. */ +/************************** Channel Invite List ******************************/ + +static void +silcpurple_chat_invitelist(PurpleBlistNode *node, gpointer data); +{ + +} + + +/**************************** Channel Ban List *******************************/ + +static void +silcpurple_chat_banlist(PurpleBlistNode *node, gpointer data); +{ + +} +#endif + + +/************************* Channel Authentication ****************************/ + +typedef struct { + SilcPurple sg; + SilcChannelEntry channel; + PurpleChat *c; + SilcBuffer pubkeys; +} *SilcPurpleChauth; + +static void +silcpurple_chat_chpk_add(void *user_data, const char *name) +{ + SilcPurpleChauth sgc = (SilcPurpleChauth)user_data; + SilcPurple sg = sgc->sg; + SilcClient client = sg->client; + SilcClientConnection conn = sg->conn; + SilcPublicKey public_key; + SilcBuffer chpks, pk, chidp; + unsigned char mode[4]; + SilcUInt32 m; + + /* Load the public key */ + if (!silc_pkcs_load_public_key(name, &public_key, SILC_PKCS_FILE_PEM) && + !silc_pkcs_load_public_key(name, &public_key, SILC_PKCS_FILE_BIN)) { + silcpurple_chat_chauth_show(sgc->sg, sgc->channel, sgc->pubkeys); + silc_buffer_free(sgc->pubkeys); + silc_free(sgc); + purple_notify_error(client->application, + _("Add Channel Public Key"), + _("Could not load public key"), NULL); + return; + } + + pk = silc_pkcs_public_key_payload_encode(public_key); + chpks = silc_buffer_alloc_size(2); + SILC_PUT16_MSB(1, chpks->head); + chpks = silc_argument_payload_encode_one(chpks, pk->data, + pk->len, 0x00); + silc_buffer_free(pk); + + m = sgc->channel->mode; + m |= SILC_CHANNEL_MODE_CHANNEL_AUTH; + + /* Send CMODE */ + SILC_PUT32_MSB(m, mode); + chidp = silc_id_payload_encode(sgc->channel->id, SILC_ID_CHANNEL); + silc_client_command_send(client, conn, SILC_COMMAND_CMODE, + ++conn->cmd_ident, 3, + 1, chidp->data, chidp->len, + 2, mode, sizeof(mode), + 9, chpks->data, chpks->len); + silc_buffer_free(chpks); + silc_buffer_free(chidp); + silc_buffer_free(sgc->pubkeys); + silc_free(sgc); +} + +static void +silcpurple_chat_chpk_cancel(void *user_data, const char *name) +{ + SilcPurpleChauth sgc = (SilcPurpleChauth)user_data; + silcpurple_chat_chauth_show(sgc->sg, sgc->channel, sgc->pubkeys); + silc_buffer_free(sgc->pubkeys); + silc_free(sgc); +} + +static void +silcpurple_chat_chpk_cb(SilcPurpleChauth sgc, PurpleRequestFields *fields) +{ + SilcPurple sg = sgc->sg; + SilcClient client = sg->client; + SilcClientConnection conn = sg->conn; + PurpleRequestField *f; + const GList *list; + SilcPublicKey public_key; + SilcBuffer chpks, pk, chidp; + SilcUInt16 c = 0, ct; + unsigned char mode[4]; + SilcUInt32 m; + + f = purple_request_fields_get_field(fields, "list"); + if (!purple_request_field_list_get_selected(f)) { + /* Add new public key */ + purple_request_file(sg->gc, _("Open Public Key..."), NULL, FALSE, + G_CALLBACK(silcpurple_chat_chpk_add), + G_CALLBACK(silcpurple_chat_chpk_cancel), + purple_connection_get_account(sg->gc), NULL, NULL, sgc); + return; + } + + list = purple_request_field_list_get_items(f); + chpks = silc_buffer_alloc_size(2); + + for (ct = 0; list; list = list->next, ct++) { + public_key = purple_request_field_list_get_data(f, list->data); + if (purple_request_field_list_is_selected(f, list->data)) { + /* Delete this public key */ + pk = silc_pkcs_public_key_payload_encode(public_key); + chpks = silc_argument_payload_encode_one(chpks, pk->data, + pk->len, 0x01); + silc_buffer_free(pk); + c++; + } + silc_pkcs_public_key_free(public_key); + } + if (!c) { + silc_buffer_free(chpks); + return; + } + SILC_PUT16_MSB(c, chpks->head); + + m = sgc->channel->mode; + if (ct == c) + m &= ~SILC_CHANNEL_MODE_CHANNEL_AUTH; + + /* Send CMODE */ + SILC_PUT32_MSB(m, mode); + chidp = silc_id_payload_encode(sgc->channel->id, SILC_ID_CHANNEL); + silc_client_command_send(client, conn, SILC_COMMAND_CMODE, + ++conn->cmd_ident, 3, + 1, chidp->data, chidp->len, + 2, mode, sizeof(mode), + 9, chpks->data, chpks->len); + silc_buffer_free(chpks); + silc_buffer_free(chidp); + silc_buffer_free(sgc->pubkeys); + silc_free(sgc); +} + +static void +silcpurple_chat_chauth_ok(SilcPurpleChauth sgc, PurpleRequestFields *fields) +{ + SilcPurple sg = sgc->sg; + PurpleRequestField *f; + const char *curpass, *val; + int set; + + f = purple_request_fields_get_field(fields, "passphrase"); + val = purple_request_field_string_get_value(f); + curpass = purple_blist_node_get_string((PurpleBlistNode *)sgc->c, "passphrase"); + + if (!val && curpass) + set = 0; + else if (val && !curpass) + set = 1; + else if (val && curpass && strcmp(val, curpass)) + set = 1; + else + set = -1; + + if (set == 1) { + silc_client_command_call(sg->client, sg->conn, NULL, "CMODE", + sgc->channel->channel_name, "+a", val, NULL); + purple_blist_node_set_string((PurpleBlistNode *)sgc->c, "passphrase", val); + } else if (set == 0) { + silc_client_command_call(sg->client, sg->conn, NULL, "CMODE", + sgc->channel->channel_name, "-a", NULL); + purple_blist_node_remove_setting((PurpleBlistNode *)sgc->c, "passphrase"); + } + + silc_buffer_free(sgc->pubkeys); + silc_free(sgc); +} + +void silcpurple_chat_chauth_show(SilcPurple sg, SilcChannelEntry channel, + SilcBuffer channel_pubkeys) +{ + SilcUInt16 argc; + SilcArgumentPayload chpks; + unsigned char *pk; + SilcUInt32 pk_len, type; + char *fingerprint, *babbleprint; + SilcPublicKey pubkey; + SilcPublicKeyIdentifier ident; + char tmp2[1024], t[512]; + PurpleRequestFields *fields; + PurpleRequestFieldGroup *g; + PurpleRequestField *f; + SilcPurpleChauth sgc; + const char *curpass = NULL; + + sgc = silc_calloc(1, sizeof(*sgc)); + if (!sgc) + return; + sgc->sg = sg; + sgc->channel = channel; + + fields = purple_request_fields_new(); + + if (sgc->c) + curpass = purple_blist_node_get_string((PurpleBlistNode *)sgc->c, "passphrase"); + + g = purple_request_field_group_new(NULL); + f = purple_request_field_string_new("passphrase", _("Channel Passphrase"), + curpass, FALSE); + purple_request_field_string_set_masked(f, TRUE); + purple_request_field_group_add_field(g, f); + purple_request_fields_add_group(fields, g); + + g = purple_request_field_group_new(NULL); + f = purple_request_field_label_new("l1", _("Channel Public Keys List")); + purple_request_field_group_add_field(g, f); + purple_request_fields_add_group(fields, g); + + g_snprintf(t, sizeof(t), + _("Channel authentication is used to secure the channel from " + "unauthorized access. The authentication may be based on " + "passphrase and digital signatures. If passphrase is set, it " + "is required to be able to join. If channel public keys are set " + "then only users whose public keys are listed are able to join.")); + + if (!channel_pubkeys) { + f = purple_request_field_list_new("list", NULL); + purple_request_field_group_add_field(g, f); + purple_request_fields(sg->gc, _("Channel Authentication"), + _("Channel Authentication"), t, fields, + _("Add / Remove"), G_CALLBACK(silcpurple_chat_chpk_cb), + _("OK"), G_CALLBACK(silcpurple_chat_chauth_ok), + purple_connection_get_account(sg->gc), NULL, NULL, sgc); + return; + } + sgc->pubkeys = silc_buffer_copy(channel_pubkeys); + + g = purple_request_field_group_new(NULL); + f = purple_request_field_list_new("list", NULL); + purple_request_field_group_add_field(g, f); + purple_request_fields_add_group(fields, g); + + SILC_GET16_MSB(argc, channel_pubkeys->data); + chpks = silc_argument_payload_parse(channel_pubkeys->data + 2, + channel_pubkeys->len - 2, argc); + if (!chpks) + return; + + pk = silc_argument_get_first_arg(chpks, &type, &pk_len); + while (pk) { + fingerprint = silc_hash_fingerprint(NULL, pk + 4, pk_len - 4); + babbleprint = silc_hash_babbleprint(NULL, pk + 4, pk_len - 4); + silc_pkcs_public_key_payload_decode(pk, pk_len, &pubkey); + ident = silc_pkcs_decode_identifier(pubkey->identifier); + + 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); + + silc_free(fingerprint); + silc_free(babbleprint); + silc_pkcs_free_identifier(ident); + pk = silc_argument_get_next_arg(chpks, &type, &pk_len); + } + + purple_request_field_list_set_multi_select(f, FALSE); + purple_request_fields(sg->gc, _("Channel Authentication"), + _("Channel Authentication"), t, fields, + _("Add / Remove"), G_CALLBACK(silcpurple_chat_chpk_cb), + _("OK"), G_CALLBACK(silcpurple_chat_chauth_ok), + purple_connection_get_account(sg->gc), NULL, NULL, sgc); + + silc_argument_payload_free(chpks); +} + +static void +silcpurple_chat_chauth(PurpleBlistNode *node, gpointer data) +{ + PurpleChat *chat; + PurpleConnection *gc; + SilcPurple sg; + + g_return_if_fail(PURPLE_BLIST_NODE_IS_CHAT(node)); + + chat = (PurpleChat *) node; + gc = purple_account_get_connection(chat->account); + sg = gc->proto_data; + + silc_client_command_call(sg->client, sg->conn, NULL, "CMODE", + g_hash_table_lookup(chat->components, "channel"), + "+C", NULL); +} + + +/************************** Channel Private Groups **************************/ + +/* Private groups are "virtual" channels. They are groups inside a channel. + This is implemented by using channel private keys. By knowing a channel + private key user becomes part of that group and is able to talk on that + group. Other users, on the same channel, won't be able to see the + messages of that group. It is possible to have multiple groups inside + a channel - and thus having multiple private keys on the channel. */ + +typedef struct { + SilcPurple sg; + PurpleChat *c; + const char *channel; +} *SilcPurpleCharPrv; + +static void +silcpurple_chat_prv_add(SilcPurpleCharPrv p, PurpleRequestFields *fields) +{ + SilcPurple sg = p->sg; + char tmp[512]; + PurpleRequestField *f; + const char *name, *passphrase, *alias; + GHashTable *comp; + PurpleGroup *g; + PurpleChat *cn; + + f = purple_request_fields_get_field(fields, "name"); + name = purple_request_field_string_get_value(f); + if (!name) { + silc_free(p); + return; + } + f = purple_request_fields_get_field(fields, "passphrase"); + passphrase = purple_request_field_string_get_value(f); + f = purple_request_fields_get_field(fields, "alias"); + alias = purple_request_field_string_get_value(f); + + /* Add private group to buddy list */ + g_snprintf(tmp, sizeof(tmp), "%s [Private Group]", name); + comp = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); + g_hash_table_replace(comp, g_strdup("channel"), g_strdup(tmp)); + g_hash_table_replace(comp, g_strdup("passphrase"), g_strdup(passphrase)); + + cn = purple_chat_new(sg->account, alias, comp); + g = (PurpleGroup *)p->c->node.parent; + purple_blist_add_chat(cn, g, (PurpleBlistNode *)p->c); + + /* Associate to a real channel */ + purple_blist_node_set_string((PurpleBlistNode *)cn, "parentch", p->channel); + + /* Join the group */ + silcpurple_chat_join(sg->gc, comp); + + silc_free(p); +} + +static void +silcpurple_chat_prv_cancel(SilcPurpleCharPrv p, PurpleRequestFields *fields) +{ + silc_free(p); +} + +static void +silcpurple_chat_prv(PurpleBlistNode *node, gpointer data) +{ + PurpleChat *chat; + PurpleConnection *gc; + SilcPurple sg; + + SilcPurpleCharPrv p; + PurpleRequestFields *fields; + PurpleRequestFieldGroup *g; + PurpleRequestField *f; + char tmp[512]; + + g_return_if_fail(PURPLE_BLIST_NODE_IS_CHAT(node)); + + chat = (PurpleChat *) node; + gc = purple_account_get_connection(chat->account); + sg = gc->proto_data; + + p = silc_calloc(1, sizeof(*p)); + if (!p) + return; + p->sg = sg; + + p->channel = g_hash_table_lookup(chat->components, "channel"); + p->c = purple_blist_find_chat(sg->account, p->channel); + + fields = purple_request_fields_new(); + + g = purple_request_field_group_new(NULL); + f = purple_request_field_string_new("name", _("Group Name"), + NULL, FALSE); + purple_request_field_group_add_field(g, f); + + f = purple_request_field_string_new("passphrase", _("Passphrase"), + NULL, FALSE); + purple_request_field_string_set_masked(f, TRUE); + purple_request_field_group_add_field(g, f); + + f = purple_request_field_string_new("alias", _("Alias"), + NULL, FALSE); + purple_request_field_group_add_field(g, f); + purple_request_fields_add_group(fields, g); + + g_snprintf(tmp, sizeof(tmp), + _("Please enter the %s channel private group name and passphrase."), + p->channel); + purple_request_fields(gc, _("Add Channel Private Group"), NULL, tmp, fields, + _("Add"), G_CALLBACK(silcpurple_chat_prv_add), + _("Cancel"), G_CALLBACK(silcpurple_chat_prv_cancel), + purple_connection_get_account(gc), NULL, NULL, p); +} + + +/****************************** Channel Modes ********************************/ + +static void +silcpurple_chat_permanent_reset(PurpleBlistNode *node, gpointer data) +{ + PurpleChat *chat; + PurpleConnection *gc; + SilcPurple sg; + + g_return_if_fail(PURPLE_BLIST_NODE_IS_CHAT(node)); + + chat = (PurpleChat *) node; + gc = purple_account_get_connection(chat->account); + sg = gc->proto_data; + + silc_client_command_call(sg->client, sg->conn, NULL, "CMODE", + g_hash_table_lookup(chat->components, "channel"), + "-f", NULL); +} + +static void +silcpurple_chat_permanent(PurpleBlistNode *node, gpointer data) +{ + PurpleChat *chat; + PurpleConnection *gc; + SilcPurple sg; + const char *channel; + + g_return_if_fail(PURPLE_BLIST_NODE_IS_CHAT(node)); + + chat = (PurpleChat *) node; + gc = purple_account_get_connection(chat->account); + sg = gc->proto_data; + + if (!sg->conn) + return; + + /* XXX we should have ability to define which founder + key to use. Now we use the user's own public key + (default key). */ + + /* Call CMODE */ + channel = g_hash_table_lookup(chat->components, "channel"); + silc_client_command_call(sg->client, sg->conn, NULL, "CMODE", channel, + "+f", NULL); +} + +typedef struct { + SilcPurple sg; + const char *channel; +} *SilcPurpleChatInput; + +static void +silcpurple_chat_ulimit_cb(SilcPurpleChatInput s, const char *limit) +{ + SilcChannelEntry channel; + int ulimit = 0; + + channel = silc_client_get_channel(s->sg->client, s->sg->conn, + (char *)s->channel); + if (!channel) + return; + if (limit) + ulimit = atoi(limit); + + if (!limit || !(*limit) || *limit == '0') { + if (limit && ulimit == channel->user_limit) { + silc_free(s); + return; + } + silc_client_command_call(s->sg->client, s->sg->conn, NULL, "CMODE", + s->channel, "-l", NULL); + + silc_free(s); + return; + } + + if (ulimit == channel->user_limit) { + silc_free(s); + return; + } + + /* Call CMODE */ + silc_client_command_call(s->sg->client, s->sg->conn, NULL, "CMODE", + s->channel, "+l", limit, NULL); + + silc_free(s); +} + +static void +silcpurple_chat_ulimit(PurpleBlistNode *node, gpointer data) +{ + PurpleChat *chat; + PurpleConnection *gc; + SilcPurple sg; + + SilcPurpleChatInput s; + SilcChannelEntry channel; + const char *ch; + char tmp[32]; + + g_return_if_fail(PURPLE_BLIST_NODE_IS_CHAT(node)); + + chat = (PurpleChat *) node; + gc = purple_account_get_connection(chat->account); + sg = gc->proto_data; + + if (!sg->conn) + return; + + ch = g_strdup(g_hash_table_lookup(chat->components, "channel")); + channel = silc_client_get_channel(sg->client, sg->conn, (char *)ch); + if (!channel) + return; + + s = silc_calloc(1, sizeof(*s)); + if (!s) + return; + s->channel = ch; + s->sg = sg; + g_snprintf(tmp, sizeof(tmp), "%d", (int)channel->user_limit); + purple_request_input(gc, _("User Limit"), NULL, + _("Set user limit on channel. Set to zero to reset user limit."), + tmp, FALSE, FALSE, NULL, + _("OK"), G_CALLBACK(silcpurple_chat_ulimit_cb), + _("Cancel"), G_CALLBACK(silcpurple_chat_ulimit_cb), + purple_connection_get_account(gc), NULL, NULL, s); +} + +static void +silcpurple_chat_resettopic(PurpleBlistNode *node, gpointer data) +{ + PurpleChat *chat; + PurpleConnection *gc; + SilcPurple sg; + + g_return_if_fail(PURPLE_BLIST_NODE_IS_CHAT(node)); + + chat = (PurpleChat *) node; + gc = purple_account_get_connection(chat->account); + sg = gc->proto_data; + + silc_client_command_call(sg->client, sg->conn, NULL, "CMODE", + g_hash_table_lookup(chat->components, "channel"), + "-t", NULL); +} + +static void +silcpurple_chat_settopic(PurpleBlistNode *node, gpointer data) +{ + PurpleChat *chat; + PurpleConnection *gc; + SilcPurple sg; + + g_return_if_fail(PURPLE_BLIST_NODE_IS_CHAT(node)); + + chat = (PurpleChat *) node; + gc = purple_account_get_connection(chat->account); + sg = gc->proto_data; + + silc_client_command_call(sg->client, sg->conn, NULL, "CMODE", + g_hash_table_lookup(chat->components, "channel"), + "+t", NULL); +} + +static void +silcpurple_chat_resetprivate(PurpleBlistNode *node, gpointer data) +{ + PurpleChat *chat; + PurpleConnection *gc; + SilcPurple sg; + + g_return_if_fail(PURPLE_BLIST_NODE_IS_CHAT(node)); + + chat = (PurpleChat *) node; + gc = purple_account_get_connection(chat->account); + sg = gc->proto_data; + + silc_client_command_call(sg->client, sg->conn, NULL, "CMODE", + g_hash_table_lookup(chat->components, "channel"), + "-p", NULL); +} + +static void +silcpurple_chat_setprivate(PurpleBlistNode *node, gpointer data) +{ + PurpleChat *chat; + PurpleConnection *gc; + SilcPurple sg; + + g_return_if_fail(PURPLE_BLIST_NODE_IS_CHAT(node)); + + chat = (PurpleChat *) node; + gc = purple_account_get_connection(chat->account); + sg = gc->proto_data; + + silc_client_command_call(sg->client, sg->conn, NULL, "CMODE", + g_hash_table_lookup(chat->components, "channel"), + "+p", NULL); +} + +static void +silcpurple_chat_resetsecret(PurpleBlistNode *node, gpointer data) +{ + PurpleChat *chat; + PurpleConnection *gc; + SilcPurple sg; + + g_return_if_fail(PURPLE_BLIST_NODE_IS_CHAT(node)); + + chat = (PurpleChat *) node; + gc = purple_account_get_connection(chat->account); + sg = gc->proto_data; + + silc_client_command_call(sg->client, sg->conn, NULL, "CMODE", + g_hash_table_lookup(chat->components, "channel"), + "-s", NULL); +} + +static void +silcpurple_chat_setsecret(PurpleBlistNode *node, gpointer data) +{ + PurpleChat *chat; + PurpleConnection *gc; + SilcPurple sg; + + g_return_if_fail(PURPLE_BLIST_NODE_IS_CHAT(node)); + + chat = (PurpleChat *) node; + gc = purple_account_get_connection(chat->account); + sg = gc->proto_data; + + silc_client_command_call(sg->client, sg->conn, NULL, "CMODE", + g_hash_table_lookup(chat->components, "channel"), + "+s", NULL); +} + +typedef struct { + SilcPurple sg; + SilcChannelEntry channel; +} *SilcPurpleChatWb; + +static void +silcpurple_chat_wb(PurpleBlistNode *node, gpointer data) +{ + SilcPurpleChatWb wb = data; + silcpurple_wb_init_ch(wb->sg, wb->channel); + silc_free(wb); +} + +GList *silcpurple_chat_menu(PurpleChat *chat) +{ + GHashTable *components = chat->components; + PurpleConnection *gc = purple_account_get_connection(chat->account); + SilcPurple sg = gc->proto_data; + SilcClientConnection conn = sg->conn; + const char *chname = NULL; + SilcChannelEntry channel = NULL; + SilcChannelUser chu = NULL; + SilcUInt32 mode = 0; + + GList *m = NULL; + PurpleMenuAction *act; + + if (components) + chname = g_hash_table_lookup(components, "channel"); + if (chname) + channel = silc_client_get_channel(sg->client, sg->conn, + (char *)chname); + if (channel) { + chu = silc_client_on_channel(channel, conn->local_entry); + if (chu) + mode = chu->mode; + } + + if (strstr(chname, "[Private Group]")) + return NULL; + + act = purple_menu_action_new(_("Get Info"), + PURPLE_CALLBACK(silcpurple_chat_getinfo_menu), + NULL, NULL); + m = g_list_append(m, act); + +#if 0 /* XXX For now these are not implemented. We need better + listview dialog from Purple for these. */ + if (mode & SILC_CHANNEL_UMODE_CHANOP) { + act = purple_menu_action_new(_("Invite List"), + PURPLE_CALLBACK(silcpurple_chat_invitelist), + NULL, NULL); + m = g_list_append(m, act); + + act = purple_menu_action_new(_("Ban List"), + PURPLE_CALLBACK(silcpurple_chat_banlist), + NULL, NULL); + m = g_list_append(m, act); + } +#endif + + if (chu) { + act = purple_menu_action_new(_("Add Private Group"), + PURPLE_CALLBACK(silcpurple_chat_prv), + NULL, NULL); + m = g_list_append(m, act); + } + + if (mode & SILC_CHANNEL_UMODE_CHANFO) { + act = purple_menu_action_new(_("Channel Authentication"), + PURPLE_CALLBACK(silcpurple_chat_chauth), + NULL, NULL); + m = g_list_append(m, act); + + if (channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) { + act = purple_menu_action_new(_("Reset Permanent"), + PURPLE_CALLBACK(silcpurple_chat_permanent_reset), + NULL, NULL); + m = g_list_append(m, act); + } else { + act = purple_menu_action_new(_("Set Permanent"), + PURPLE_CALLBACK(silcpurple_chat_permanent), + NULL, NULL); + m = g_list_append(m, act); + } + } + + if (mode & SILC_CHANNEL_UMODE_CHANOP) { + act = purple_menu_action_new(_("Set User Limit"), + PURPLE_CALLBACK(silcpurple_chat_ulimit), + NULL, NULL); + m = g_list_append(m, act); + + if (channel->mode & SILC_CHANNEL_MODE_TOPIC) { + act = purple_menu_action_new(_("Reset Topic Restriction"), + PURPLE_CALLBACK(silcpurple_chat_resettopic), + NULL, NULL); + m = g_list_append(m, act); + } else { + act = purple_menu_action_new(_("Set Topic Restriction"), + PURPLE_CALLBACK(silcpurple_chat_settopic), + NULL, NULL); + m = g_list_append(m, act); + } + + if (channel->mode & SILC_CHANNEL_MODE_PRIVATE) { + act = purple_menu_action_new(_("Reset Private Channel"), + PURPLE_CALLBACK(silcpurple_chat_resetprivate), + NULL, NULL); + m = g_list_append(m, act); + } else { + act = purple_menu_action_new(_("Set Private Channel"), + PURPLE_CALLBACK(silcpurple_chat_setprivate), + NULL, NULL); + m = g_list_append(m, act); + } + + if (channel->mode & SILC_CHANNEL_MODE_SECRET) { + act = purple_menu_action_new(_("Reset Secret Channel"), + PURPLE_CALLBACK(silcpurple_chat_resetsecret), + NULL, NULL); + m = g_list_append(m, act); + } else { + act = purple_menu_action_new(_("Set Secret Channel"), + PURPLE_CALLBACK(silcpurple_chat_setsecret), + NULL, NULL); + m = g_list_append(m, act); + } + } + + if (channel) { + SilcPurpleChatWb wb; + wb = silc_calloc(1, sizeof(*wb)); + wb->sg = sg; + wb->channel = channel; + act = purple_menu_action_new(_("Draw On Whiteboard"), + PURPLE_CALLBACK(silcpurple_chat_wb), + (void *)wb, NULL); + m = g_list_append(m, act); + } + + return m; +} + + +/******************************* Joining Etc. ********************************/ + +void silcpurple_chat_join_done(SilcClient client, + SilcClientConnection conn, + SilcClientEntry *clients, + SilcUInt32 clients_count, + void *context) +{ + PurpleConnection *gc = client->application; + SilcPurple sg = gc->proto_data; + SilcChannelEntry channel = context; + PurpleConversation *convo; + SilcUInt32 retry = SILC_PTR_TO_32(channel->context); + SilcHashTableList htl; + SilcChannelUser chu; + GList *users = NULL, *flags = NULL; + char tmp[256]; + + if (!clients && retry < 1) { + /* Resolving users failed, try again. */ + channel->context = SILC_32_TO_PTR(retry + 1); + silc_client_get_clients_by_channel(client, conn, channel, + silcpurple_chat_join_done, channel); + return; + } + + /* Add channel to Purple */ + channel->context = SILC_32_TO_PTR(++sg->channel_ids); + serv_got_joined_chat(gc, sg->channel_ids, channel->channel_name); + convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, + channel->channel_name, sg->account); + if (!convo) + return; + + /* Add all users to channel */ + silc_hash_table_list(channel->user_list, &htl); + while (silc_hash_table_get(&htl, NULL, (void *)&chu)) { + PurpleConvChatBuddyFlags f = PURPLE_CBFLAGS_NONE; + if (!chu->client->nickname) + continue; + chu->context = SILC_32_TO_PTR(sg->channel_ids); + + if (chu->mode & SILC_CHANNEL_UMODE_CHANFO) + f |= PURPLE_CBFLAGS_FOUNDER; + if (chu->mode & SILC_CHANNEL_UMODE_CHANOP) + f |= PURPLE_CBFLAGS_OP; + users = g_list_append(users, g_strdup(chu->client->nickname)); + flags = g_list_append(flags, GINT_TO_POINTER(f)); + + if (chu->mode & SILC_CHANNEL_UMODE_CHANFO) { + if (chu->client == conn->local_entry) + g_snprintf(tmp, sizeof(tmp), + _("You are channel founder on <I>%s</I>"), + channel->channel_name); + else + g_snprintf(tmp, sizeof(tmp), + _("Channel founder on <I>%s</I> is <I>%s</I>"), + channel->channel_name, chu->client->nickname); + + purple_conversation_write(convo, NULL, tmp, + PURPLE_MESSAGE_SYSTEM, time(NULL)); + + } + } + silc_hash_table_list_reset(&htl); + + purple_conv_chat_add_users(PURPLE_CONV_CHAT(convo), users, NULL, flags, FALSE); + g_list_free(users); + g_list_free(flags); + + /* Set topic */ + if (channel->topic) + purple_conv_chat_set_topic(PURPLE_CONV_CHAT(convo), NULL, channel->topic); + + /* Set nick */ + purple_conv_chat_set_nick(PURPLE_CONV_CHAT(convo), conn->local_entry->nickname); +} + +char *silcpurple_get_chat_name(GHashTable *data) +{ + return g_strdup(g_hash_table_lookup(data, "channel")); +} + +void silcpurple_chat_join(PurpleConnection *gc, GHashTable *data) +{ + SilcPurple sg = gc->proto_data; + SilcClient client = sg->client; + SilcClientConnection conn = sg->conn; + const char *channel, *passphrase, *parentch; + + if (!conn) + return; + + channel = g_hash_table_lookup(data, "channel"); + passphrase = g_hash_table_lookup(data, "passphrase"); + + /* Check if we are joining a private group. Handle it + purely locally as it's not a real channel */ + if (strstr(channel, "[Private Group]")) { + SilcChannelEntry channel_entry; + SilcChannelPrivateKey key; + PurpleChat *c; + SilcPurplePrvgrp grp; + + c = purple_blist_find_chat(sg->account, channel); + parentch = purple_blist_node_get_string((PurpleBlistNode *)c, "parentch"); + if (!parentch) + return; + + channel_entry = silc_client_get_channel(sg->client, sg->conn, + (char *)parentch); + if (!channel_entry || + !silc_client_on_channel(channel_entry, sg->conn->local_entry)) { + char tmp[512]; + g_snprintf(tmp, sizeof(tmp), + _("You have to join the %s channel before you are " + "able to join the private group"), parentch); + purple_notify_error(gc, _("Join Private Group"), + _("Cannot join private group"), tmp); + return; + } + + /* Add channel private key */ + if (!silc_client_add_channel_private_key(client, conn, + channel_entry, channel, + NULL, NULL, + (unsigned char *)passphrase, + strlen(passphrase), &key)) + return; + + /* Join the group */ + grp = silc_calloc(1, sizeof(*grp)); + if (!grp) + return; + grp->id = ++sg->channel_ids + SILCPURPLE_PRVGRP; + grp->chid = SILC_PTR_TO_32(channel_entry->context); + grp->parentch = parentch; + grp->channel = channel; + grp->key = key; + sg->grps = g_list_append(sg->grps, grp); + serv_got_joined_chat(gc, grp->id, channel); + return; + } + + /* XXX We should have other properties here as well: + 1. whether to try to authenticate to the channel + 1a. with default key, + 1b. with specific key. + 2. whether to try to authenticate to become founder. + 2a. with default key, + 2b. with specific key. + + Since now such variety is not possible in the join dialog + we always use -founder and -auth options, which try to + do both 1 and 2 with default keys. */ + + /* Call JOIN */ + if ((passphrase != NULL) && (*passphrase != '\0')) + silc_client_command_call(client, conn, NULL, "JOIN", + channel, passphrase, "-auth", "-founder", NULL); + else + silc_client_command_call(client, conn, NULL, "JOIN", + channel, "-auth", "-founder", NULL); +} + +void silcpurple_chat_invite(PurpleConnection *gc, int id, const char *msg, + const char *name) +{ + SilcPurple sg = gc->proto_data; + SilcClient client = sg->client; + SilcClientConnection conn = sg->conn; + SilcHashTableList htl; + SilcChannelUser chu; + gboolean found = FALSE; + + if (!conn) + return; + + /* See if we are inviting on a private group. Invite + to the actual channel */ + if (id > SILCPURPLE_PRVGRP) { + GList *l; + SilcPurplePrvgrp prv; + + for (l = sg->grps; l; l = l->next) + if (((SilcPurplePrvgrp)l->data)->id == id) + break; + if (!l) + return; + prv = l->data; + id = prv->chid; + } + + /* Find channel by id */ + silc_hash_table_list(conn->local_entry->channels, &htl); + while (silc_hash_table_get(&htl, NULL, (void *)&chu)) { + if (SILC_PTR_TO_32(chu->channel->context) == id ) { + found = TRUE; + break; + } + } + silc_hash_table_list_reset(&htl); + if (!found) + return; + + /* Call INVITE */ + silc_client_command_call(client, conn, NULL, "INVITE", + chu->channel->channel_name, + name, NULL); +} + +void silcpurple_chat_leave(PurpleConnection *gc, int id) +{ + SilcPurple sg = gc->proto_data; + SilcClient client = sg->client; + SilcClientConnection conn = sg->conn; + SilcHashTableList htl; + SilcChannelUser chu; + gboolean found = FALSE; + GList *l; + SilcPurplePrvgrp prv; + + if (!conn) + return; + + /* See if we are leaving a private group */ + if (id > SILCPURPLE_PRVGRP) { + SilcChannelEntry channel; + + for (l = sg->grps; l; l = l->next) + if (((SilcPurplePrvgrp)l->data)->id == id) + break; + if (!l) + return; + prv = l->data; + channel = silc_client_get_channel(sg->client, sg->conn, + (char *)prv->parentch); + if (!channel) + return; + silc_client_del_channel_private_key(client, conn, + channel, prv->key); + silc_free(prv); + sg->grps = g_list_remove(sg->grps, prv); + serv_got_chat_left(gc, id); + return; + } + + /* Find channel by id */ + silc_hash_table_list(conn->local_entry->channels, &htl); + while (silc_hash_table_get(&htl, NULL, (void *)&chu)) { + if (SILC_PTR_TO_32(chu->channel->context) == id ) { + found = TRUE; + break; + } + } + silc_hash_table_list_reset(&htl); + if (!found) + return; + + /* Call LEAVE */ + silc_client_command_call(client, conn, NULL, "LEAVE", + chu->channel->channel_name, NULL); + + serv_got_chat_left(gc, id); + + /* Leave from private groups on this channel as well */ + for (l = sg->grps; l; l = l->next) + if (((SilcPurplePrvgrp)l->data)->chid == id) { + prv = l->data; + silc_client_del_channel_private_key(client, conn, + chu->channel, + prv->key); + serv_got_chat_left(gc, prv->id); + silc_free(prv); + sg->grps = g_list_remove(sg->grps, prv); + if (!sg->grps) + break; + } +} + +int silcpurple_chat_send(PurpleConnection *gc, int id, const char *msg, PurpleMessageFlags msgflags) +{ + SilcPurple sg = gc->proto_data; + SilcClient client = sg->client; + SilcClientConnection conn = sg->conn; + SilcHashTableList htl; + SilcChannelUser chu; + SilcChannelEntry channel = NULL; + SilcChannelPrivateKey key = NULL; + SilcUInt32 flags; + int ret; + char *msg2, *tmp; + gboolean found = FALSE; + gboolean sign = purple_account_get_bool(sg->account, "sign-verify", FALSE); + + if (!msg || !conn) + return 0; + + flags = SILC_MESSAGE_FLAG_UTF8; + + tmp = msg2 = purple_unescape_html(msg); + + if (!g_ascii_strncasecmp(msg2, "/me ", 4)) + { + msg2 += 4; + if (!*msg2) { + g_free(tmp); + return 0; + } + flags |= SILC_MESSAGE_FLAG_ACTION; + } else if (strlen(msg) > 1 && msg[0] == '/') { + if (!silc_client_command_call(client, conn, msg + 1)) + purple_notify_error(gc, _("Call Command"), _("Cannot call command"), + _("Unknown command")); + g_free(tmp); + return 0; + } + + + if (sign) + flags |= SILC_MESSAGE_FLAG_SIGNED; + + /* Get the channel private key if we are sending on + private group */ + if (id > SILCPURPLE_PRVGRP) { + GList *l; + SilcPurplePrvgrp prv; + + for (l = sg->grps; l; l = l->next) + if (((SilcPurplePrvgrp)l->data)->id == id) + break; + if (!l) { + g_free(tmp); + return 0; + } + prv = l->data; + channel = silc_client_get_channel(sg->client, sg->conn, + (char *)prv->parentch); + if (!channel) { + g_free(tmp); + return 0; + } + key = prv->key; + } + + if (!channel) { + /* Find channel by id */ + silc_hash_table_list(conn->local_entry->channels, &htl); + while (silc_hash_table_get(&htl, NULL, (void *)&chu)) { + if (SILC_PTR_TO_32(chu->channel->context) == id ) { + found = TRUE; + break; + } + } + silc_hash_table_list_reset(&htl); + if (!found) { + g_free(tmp); + return 0; + } + channel = chu->channel; + } + + /* Send channel message */ + ret = silc_client_send_channel_message(client, conn, channel, key, + flags, (unsigned char *)msg2, + strlen(msg2), TRUE); + if (ret) { + serv_got_chat_in(gc, id, purple_connection_get_display_name(gc), 0, msg, + time(NULL)); + } + g_free(tmp); + + return ret; +} + +void silcpurple_chat_set_topic(PurpleConnection *gc, int id, const char *topic) +{ + SilcPurple sg = gc->proto_data; + SilcClient client = sg->client; + SilcClientConnection conn = sg->conn; + SilcHashTableList htl; + SilcChannelUser chu; + gboolean found = FALSE; + + if (!conn) + return; + + /* See if setting topic on private group. Set it + on the actual channel */ + if (id > SILCPURPLE_PRVGRP) { + GList *l; + SilcPurplePrvgrp prv; + + for (l = sg->grps; l; l = l->next) + if (((SilcPurplePrvgrp)l->data)->id == id) + break; + if (!l) + return; + prv = l->data; + id = prv->chid; + } + + /* Find channel by id */ + silc_hash_table_list(conn->local_entry->channels, &htl); + while (silc_hash_table_get(&htl, NULL, (void *)&chu)) { + if (SILC_PTR_TO_32(chu->channel->context) == id ) { + found = TRUE; + break; + } + } + silc_hash_table_list_reset(&htl); + if (!found) + return; + + /* Call TOPIC */ + silc_client_command_call(client, conn, NULL, "TOPIC", + chu->channel->channel_name, topic, NULL); +} + +PurpleRoomlist *silcpurple_roomlist_get_list(PurpleConnection *gc) +{ + SilcPurple sg = gc->proto_data; + SilcClient client = sg->client; + SilcClientConnection conn = sg->conn; + GList *fields = NULL; + PurpleRoomlistField *f; + + if (!conn) + return NULL; + + if (sg->roomlist) + purple_roomlist_unref(sg->roomlist); + + sg->roomlist_canceled = FALSE; + + sg->roomlist = purple_roomlist_new(purple_connection_get_account(gc)); + f = purple_roomlist_field_new(PURPLE_ROOMLIST_FIELD_STRING, "", "channel", TRUE); + fields = g_list_append(fields, f); + f = purple_roomlist_field_new(PURPLE_ROOMLIST_FIELD_INT, + _("Users"), "users", FALSE); + fields = g_list_append(fields, f); + f = purple_roomlist_field_new(PURPLE_ROOMLIST_FIELD_STRING, + _("Topic"), "topic", FALSE); + fields = g_list_append(fields, f); + purple_roomlist_set_fields(sg->roomlist, fields); + + /* Call LIST */ + silc_client_command_call(client, conn, "LIST"); + + purple_roomlist_set_in_progress(sg->roomlist, TRUE); + + return sg->roomlist; +} + +void silcpurple_roomlist_cancel(PurpleRoomlist *list) +{ + PurpleConnection *gc = purple_account_get_connection(list->account); + SilcPurple sg; + + if (!gc) + return; + sg = gc->proto_data; + + purple_roomlist_set_in_progress(list, FALSE); + if (sg->roomlist == list) { + purple_roomlist_unref(sg->roomlist); + sg->roomlist = NULL; + sg->roomlist_canceled = TRUE; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/silc10/ft.c Mon Jun 18 01:48:35 2007 +0000 @@ -0,0 +1,412 @@ +/* + + silcpurple_ft.c + + Author: Pekka Riikonen <priikone@silcnet.org> + + Copyright (C) 2004 Pekka Riikonen + + 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; version 2 of the License. + + 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. + +*/ + +#include "silcincludes.h" +#include "silcclient.h" +#include "silcpurple.h" + +/****************************** File Transfer ********************************/ + +/* This implements the secure file transfer protocol (SFTP) using the SILC + SFTP library implementation. The API we use from the SILC Toolkit is the + SILC Client file transfer API, as it provides a simple file transfer we + need in this case. We could use the SILC SFTP API directly, but it would + be an overkill since we'd effectively re-implement the file transfer what + the SILC Client's file transfer API already provides. + + From Purple we do NOT use the FT API to do the transfer as it is very limiting. + In fact it does not suite to file transfers like SFTP at all. For example, + it assumes that read operations are synchronous what they are not in SFTP. + It also assumes that the file transfer socket is to be handled by the Purple + eventloop, and this naturally is something we don't want to do in case of + SILC Toolkit. The FT API suites well to purely stream based file transfers + like HTTP GET and similar. + + For this reason, we directly access the Purple GKT FT API and hack the FT + API to merely provide the user interface experience and all the magic + is done in the SILC Toolkit. Ie. we update the statistics information in + the FT API for user interface, and that's it. A bit dirty but until the + FT API gets better this is the way to go. Good thing that FT API allowed + us to do this. */ + +typedef struct { + SilcPurple sg; + SilcClientEntry client_entry; + SilcUInt32 session_id; + char *hostname; + SilcUInt16 port; + PurpleXfer *xfer; + + SilcClientFileName completion; + void *completion_context; +} *SilcPurpleXfer; + +static void +silcpurple_ftp_monitor(SilcClient client, + SilcClientConnection conn, + SilcClientMonitorStatus status, + SilcClientFileError error, + SilcUInt64 offset, + SilcUInt64 filesize, + SilcClientEntry client_entry, + SilcUInt32 session_id, + const char *filepath, + void *context) +{ + SilcPurpleXfer xfer = context; + PurpleConnection *gc = xfer->sg->gc; + char tmp[256]; + + if (status == SILC_CLIENT_FILE_MONITOR_CLOSED) { + purple_xfer_unref(xfer->xfer); + silc_free(xfer); + return; + } + + if (status == SILC_CLIENT_FILE_MONITOR_KEY_AGREEMENT) + return; + + if (status == SILC_CLIENT_FILE_MONITOR_ERROR) { + if (error == SILC_CLIENT_FILE_NO_SUCH_FILE) { + g_snprintf(tmp, sizeof(tmp), "No such file %s", + filepath ? filepath : "[N/A]"); + purple_notify_error(gc, _("Secure File Transfer"), + _("Error during file transfer"), tmp); + } else if (error == SILC_CLIENT_FILE_PERMISSION_DENIED) { + purple_notify_error(gc, _("Secure File Transfer"), + _("Error during file transfer"), + _("Permission denied")); + } else if (error == SILC_CLIENT_FILE_KEY_AGREEMENT_FAILED) { + purple_notify_error(gc, _("Secure File Transfer"), + _("Error during file transfer"), + _("Key agreement failed")); + } else if (error == SILC_CLIENT_FILE_UNKNOWN_SESSION) { + purple_notify_error(gc, _("Secure File Transfer"), + _("Error during file transfer"), + _("File transfer session does not exist")); + } else { + purple_notify_error(gc, _("Secure File Transfer"), + _("Error during file transfer"), NULL); + } + silc_client_file_close(client, conn, session_id); + purple_xfer_unref(xfer->xfer); + silc_free(xfer); + return; + } + + /* Update file transfer UI */ + if (!offset && filesize) + purple_xfer_set_size(xfer->xfer, filesize); + if (offset && filesize) { + xfer->xfer->bytes_sent = offset; + xfer->xfer->bytes_remaining = filesize - offset; + } + purple_xfer_update_progress(xfer->xfer); + + if (status == SILC_CLIENT_FILE_MONITOR_SEND || + status == SILC_CLIENT_FILE_MONITOR_RECEIVE) { + if (offset == filesize) { + /* Download finished */ + purple_xfer_set_completed(xfer->xfer, TRUE); + silc_client_file_close(client, conn, session_id); + } + } +} + +static void +silcpurple_ftp_cancel(PurpleXfer *x) +{ + SilcPurpleXfer xfer = x->data; + xfer->xfer->status = PURPLE_XFER_STATUS_CANCEL_LOCAL; + purple_xfer_update_progress(xfer->xfer); + silc_client_file_close(xfer->sg->client, xfer->sg->conn, xfer->session_id); +} + +static void +silcpurple_ftp_ask_name_cancel(PurpleXfer *x) +{ + SilcPurpleXfer xfer = x->data; + + /* Cancel the transmission */ + xfer->completion(NULL, xfer->completion_context); + silc_client_file_close(xfer->sg->client, xfer->sg->conn, xfer->session_id); +} + +static void +silcpurple_ftp_ask_name_ok(PurpleXfer *x) +{ + SilcPurpleXfer xfer = x->data; + const char *name; + + name = purple_xfer_get_local_filename(x); + g_unlink(name); + xfer->completion(name, xfer->completion_context); +} + +static void +silcpurple_ftp_ask_name(SilcClient client, + SilcClientConnection conn, + SilcUInt32 session_id, + const char *remote_filename, + SilcClientFileName completion, + void *completion_context, + void *context) +{ + SilcPurpleXfer xfer = context; + + xfer->completion = completion; + xfer->completion_context = completion_context; + + purple_xfer_set_init_fnc(xfer->xfer, silcpurple_ftp_ask_name_ok); + purple_xfer_set_request_denied_fnc(xfer->xfer, silcpurple_ftp_ask_name_cancel); + + /* Request to save the file */ + purple_xfer_set_filename(xfer->xfer, remote_filename); + purple_xfer_request(xfer->xfer); +} + +static void +silcpurple_ftp_request_result(PurpleXfer *x) +{ + SilcPurpleXfer xfer = x->data; + SilcClientFileError status; + PurpleConnection *gc = xfer->sg->gc; + + if (purple_xfer_get_status(x) != PURPLE_XFER_STATUS_ACCEPTED) + return; + + /* Start the file transfer */ + status = silc_client_file_receive(xfer->sg->client, xfer->sg->conn, + silcpurple_ftp_monitor, xfer, + NULL, xfer->session_id, + silcpurple_ftp_ask_name, xfer); + switch (status) { + case SILC_CLIENT_FILE_OK: + return; + break; + + case SILC_CLIENT_FILE_UNKNOWN_SESSION: + purple_notify_error(gc, _("Secure File Transfer"), + _("No file transfer session active"), NULL); + break; + + case SILC_CLIENT_FILE_ALREADY_STARTED: + purple_notify_error(gc, _("Secure File Transfer"), + _("File transfer already started"), NULL); + break; + + case SILC_CLIENT_FILE_KEY_AGREEMENT_FAILED: + purple_notify_error(gc, _("Secure File Transfer"), + _("Could not perform key agreement for file transfer"), + NULL); + break; + + default: + purple_notify_error(gc, _("Secure File Transfer"), + _("Could not start the file transfer"), NULL); + break; + } + + /* Error */ + purple_xfer_unref(xfer->xfer); + g_free(xfer->hostname); + silc_free(xfer); +} + +static void +silcpurple_ftp_request_denied(PurpleXfer *x) +{ + +} + +void silcpurple_ftp_request(SilcClient client, SilcClientConnection conn, + SilcClientEntry client_entry, SilcUInt32 session_id, + const char *hostname, SilcUInt16 port) +{ + PurpleConnection *gc = client->application; + SilcPurple sg = gc->proto_data; + SilcPurpleXfer xfer; + + xfer = silc_calloc(1, sizeof(*xfer)); + if (!xfer) { + silc_client_file_close(sg->client, sg->conn, session_id); + return; + } + + xfer->sg = sg; + xfer->client_entry = client_entry; + xfer->session_id = session_id; + xfer->hostname = g_strdup(hostname); + xfer->port = port; + xfer->xfer = purple_xfer_new(xfer->sg->account, PURPLE_XFER_RECEIVE, + xfer->client_entry->nickname); + if (!xfer->xfer) { + silc_client_file_close(xfer->sg->client, xfer->sg->conn, xfer->session_id); + g_free(xfer->hostname); + silc_free(xfer); + return; + } + purple_xfer_set_init_fnc(xfer->xfer, silcpurple_ftp_request_result); + purple_xfer_set_request_denied_fnc(xfer->xfer, silcpurple_ftp_request_denied); + purple_xfer_set_cancel_recv_fnc(xfer->xfer, silcpurple_ftp_cancel); + xfer->xfer->remote_ip = g_strdup(hostname); + xfer->xfer->remote_port = port; + xfer->xfer->data = xfer; + + /* File transfer request */ + purple_xfer_request(xfer->xfer); +} + +static void +silcpurple_ftp_send_cancel(PurpleXfer *x) +{ + SilcPurpleXfer xfer = x->data; + silc_client_file_close(xfer->sg->client, xfer->sg->conn, xfer->session_id); + purple_xfer_unref(xfer->xfer); + g_free(xfer->hostname); + silc_free(xfer); +} + +static void +silcpurple_ftp_send(PurpleXfer *x) +{ + SilcPurpleXfer xfer = x->data; + const char *name; + char *local_ip = NULL, *remote_ip = NULL; + gboolean local = TRUE; + + name = purple_xfer_get_local_filename(x); + + /* Do the same magic what we do with key agreement (see silcpurple_buddy.c) + to see if we are behind NAT. */ + if (silc_net_check_local_by_sock(xfer->sg->conn->sock->sock, + NULL, &local_ip)) { + /* Check if the IP is private */ + if (silcpurple_ip_is_private(local_ip)) { + local = FALSE; + /* Local IP is private, resolve the remote server IP to see whether + we are talking to Internet or just on LAN. */ + if (silc_net_check_host_by_sock(xfer->sg->conn->sock->sock, NULL, + &remote_ip)) + if (silcpurple_ip_is_private(remote_ip)) + /* We assume we are in LAN. Let's provide the connection point. */ + local = TRUE; + } + } + + if (local && !local_ip) + local_ip = silc_net_localip(); + + /* Send the file */ + silc_client_file_send(xfer->sg->client, xfer->sg->conn, + silcpurple_ftp_monitor, xfer, + local_ip, 0, !local, xfer->client_entry, + name, &xfer->session_id); + + silc_free(local_ip); + silc_free(remote_ip); +} + +static void +silcpurple_ftp_send_file_resolved(SilcClient client, + SilcClientConnection conn, + SilcClientEntry *clients, + SilcUInt32 clients_count, + void *context) +{ + PurpleConnection *gc = client->application; + char tmp[256]; + + if (!clients) { + g_snprintf(tmp, sizeof(tmp), + _("User %s is not present in the network"), + (const char *)context); + purple_notify_error(gc, _("Secure File Transfer"), + _("Cannot send file"), tmp); + silc_free(context); + return; + } + + silcpurple_ftp_send_file(client->application, (const char *)context, NULL); + silc_free(context); +} + +PurpleXfer *silcpurple_ftp_new_xfer(PurpleConnection *gc, const char *name) +{ + SilcPurple sg = gc->proto_data; + SilcClient client = sg->client; + SilcClientConnection conn = sg->conn; + SilcClientEntry *clients; + SilcUInt32 clients_count; + SilcPurpleXfer xfer; + char *nickname; + + g_return_val_if_fail(name != NULL, NULL); + + if (!silc_parse_userfqdn(name, &nickname, NULL)) + return NULL; + + /* Find client entry */ + clients = silc_client_get_clients_local(client, conn, nickname, name, + &clients_count); + if (!clients) { + silc_client_get_clients(client, conn, nickname, NULL, + silcpurple_ftp_send_file_resolved, + strdup(name)); + silc_free(nickname); + return NULL; + } + + xfer = silc_calloc(1, sizeof(*xfer)); + + g_return_val_if_fail(xfer != NULL, NULL); + + xfer->sg = sg; + xfer->client_entry = clients[0]; + xfer->xfer = purple_xfer_new(xfer->sg->account, PURPLE_XFER_SEND, + xfer->client_entry->nickname); + if (!xfer->xfer) { + silc_client_file_close(xfer->sg->client, xfer->sg->conn, xfer->session_id); + g_free(xfer->hostname); + silc_free(xfer); + return NULL; + } + purple_xfer_set_init_fnc(xfer->xfer, silcpurple_ftp_send); + purple_xfer_set_request_denied_fnc(xfer->xfer, silcpurple_ftp_request_denied); + purple_xfer_set_cancel_send_fnc(xfer->xfer, silcpurple_ftp_send_cancel); + xfer->xfer->data = xfer; + + silc_free(clients); + silc_free(nickname); + + return xfer->xfer; +} + +void silcpurple_ftp_send_file(PurpleConnection *gc, const char *name, const char *file) +{ + PurpleXfer *xfer = silcpurple_ftp_new_xfer(gc, name); + + g_return_if_fail(xfer != NULL); + + /* Choose file to send */ + if (file) + purple_xfer_request_accepted(xfer, file); + else + purple_xfer_request(xfer); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/silc10/ops.c Mon Jun 18 01:48:35 2007 +0000 @@ -0,0 +1,2057 @@ +/* + + silcpurple_ops.c + + Author: Pekka Riikonen <priikone@silcnet.org> + + Copyright (C) 2004 Pekka Riikonen + + 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; version 2 of the License. + + 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. + +*/ + +#include "silcincludes.h" +#include "silcclient.h" +#include "silcpurple.h" +#include "imgstore.h" +#include "wb.h" + +static void +silc_channel_message(SilcClient client, SilcClientConnection conn, + SilcClientEntry sender, SilcChannelEntry channel, + SilcMessagePayload payload, SilcChannelPrivateKey key, + SilcMessageFlags flags, const unsigned char *message, + SilcUInt32 message_len); +static void +silc_private_message(SilcClient client, SilcClientConnection conn, + SilcClientEntry sender, SilcMessagePayload payload, + SilcMessageFlags flags, const unsigned char *message, + SilcUInt32 message_len); + +/* Message sent to the application by library. `conn' associates the + message to a specific connection. `conn', however, may be NULL. + The `type' indicates the type of the message sent by the library. + The application can for example filter the message according the + type. */ + +static void +silc_say(SilcClient client, SilcClientConnection conn, + SilcClientMessageType type, char *msg, ...) +{ + /* Nothing */ +} + +#ifdef HAVE_SILCMIME_H +/* Processes incoming MIME message. Can be private message or channel + message. */ + +static void +silcpurple_mime_message(SilcClient client, SilcClientConnection conn, + SilcClientEntry sender, SilcChannelEntry channel, + SilcMessagePayload payload, SilcChannelPrivateKey key, + SilcMessageFlags flags, SilcMime mime, + gboolean recursive) +{ + PurpleConnection *gc = client->application; + SilcPurple sg = gc->proto_data; + const char *type; + const unsigned char *data; + SilcUInt32 data_len; + PurpleMessageFlags cflags = 0; + PurpleConversation *convo = NULL; + + if (!mime) + return; + + /* Check for fragmented MIME message */ + if (silc_mime_is_partial(mime)) { + if (!sg->mimeass) + sg->mimeass = silc_mime_assembler_alloc(); + + /* Defragment */ + mime = silc_mime_assemble(sg->mimeass, mime); + if (!mime) + /* More fragments to come */ + return; + + /* Process the complete message */ + silcpurple_mime_message(client, conn, sender, channel, + payload, key, flags, mime, FALSE); + return; + } + + /* Check for multipart message */ + if (silc_mime_is_multipart(mime)) { + SilcMime p; + const char *mtype; + SilcDList parts = silc_mime_get_multiparts(mime, &mtype); + + /* Only "mixed" type supported */ + if (strcmp(mtype, "mixed")) + goto out; + + silc_dlist_start(parts); + while ((p = silc_dlist_get(parts)) != SILC_LIST_END) { + /* Recursively process parts */ + silcpurple_mime_message(client, conn, sender, channel, + payload, key, flags, p, TRUE); + } + goto out; + } + + /* Get content type and MIME data */ + type = silc_mime_get_field(mime, "Content-Type"); + if (!type) + goto out; + data = silc_mime_get_data(mime, &data_len); + if (!data) + goto out; + + /* Process according to content type */ + + /* Plain text */ + if (strstr(type, "text/plain")) { + /* Default is UTF-8, don't check for other charsets */ + if (!strstr(type, "utf-8")) + goto out; + + if (channel) + silc_channel_message(client, conn, sender, channel, + payload, key, + SILC_MESSAGE_FLAG_UTF8, data, + data_len); + else + silc_private_message(client, conn, sender, payload, + SILC_MESSAGE_FLAG_UTF8, data, + data_len); + goto out; + } + + /* Image */ + if (strstr(type, "image/png") || + strstr(type, "image/jpeg") || + strstr(type, "image/gif") || + strstr(type, "image/tiff")) { + char tmp[32]; + int imgid; + + /* Get channel convo (if message is for channel) */ + if (key && channel) { + GList *l; + SilcPurplePrvgrp prv; + + for (l = sg->grps; l; l = l->next) + if (((SilcPurplePrvgrp)l->data)->key == key) { + prv = l->data; + convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, + prv->channel, sg->account); + break; + } + } + if (channel && !convo) + convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, + channel->channel_name, sg->account); + if (channel && !convo) + goto out; + + imgid = purple_imgstore_add_with_id(g_memdup(data, data_len), data_len, ""); + if (imgid) { + cflags |= PURPLE_MESSAGE_IMAGES | PURPLE_MESSAGE_RECV; + g_snprintf(tmp, sizeof(tmp), "<IMG ID=\"%d\">", imgid); + + if (channel) + serv_got_chat_in(gc, purple_conv_chat_get_id(PURPLE_CONV_CHAT(convo)), + sender->nickname ? + sender->nickname : + "<unknown>", cflags, + tmp, time(NULL)); + else + serv_got_im(gc, sender->nickname ? + sender->nickname : "<unknown>", + tmp, cflags, time(NULL)); + + purple_imgstore_unref_by_id(imgid); + cflags = 0; + } + goto out; + } + + /* Whiteboard message */ + if (strstr(type, "application/x-wb") && + !purple_account_get_bool(sg->account, "block-wb", FALSE)) { + if (channel) + silcpurple_wb_receive_ch(client, conn, sender, channel, + payload, flags, data, data_len); + else + silcpurple_wb_receive(client, conn, sender, payload, + flags, data, data_len); + goto out; + } + + out: + if (!recursive) + silc_mime_free(mime); +} +#endif /* HAVE_SILCMIME_H */ + +/* Message for a channel. The `sender' is the sender of the message + The `channel' is the channel. The `message' is the message. Note + that `message' maybe NULL. The `flags' indicates message flags + and it is used to determine how the message can be interpreted + (like it may tell the message is multimedia message). */ + +static void +silc_channel_message(SilcClient client, SilcClientConnection conn, + SilcClientEntry sender, SilcChannelEntry channel, + SilcMessagePayload payload, SilcChannelPrivateKey key, + SilcMessageFlags flags, const unsigned char *message, + SilcUInt32 message_len) +{ + PurpleConnection *gc = client->application; + SilcPurple sg = gc->proto_data; + PurpleConversation *convo = NULL; + char *msg, *tmp; + + if (!message) + return; + + if (key) { + GList *l; + SilcPurplePrvgrp prv; + + for (l = sg->grps; l; l = l->next) + if (((SilcPurplePrvgrp)l->data)->key == key) { + prv = l->data; + convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, + prv->channel, sg->account); + break; + } + } + if (!convo) + convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, + channel->channel_name, sg->account); + if (!convo) + return; + + if (flags & SILC_MESSAGE_FLAG_SIGNED && + purple_account_get_bool(sg->account, "sign-verify", FALSE)) { + /* XXX */ + } + + if (flags & SILC_MESSAGE_FLAG_DATA) { + /* Process MIME message */ +#ifdef HAVE_SILCMIME_H + SilcMime mime; + mime = silc_mime_decode(message, message_len); + silcpurple_mime_message(client, conn, sender, channel, payload, + key, flags, mime, FALSE); +#else + char type[128], enc[128]; + unsigned char *data; + SilcUInt32 data_len; + + memset(type, 0, sizeof(type)); + memset(enc, 0, sizeof(enc)); + + if (!silc_mime_parse(message, message_len, NULL, 0, + type, sizeof(type) - 1, enc, sizeof(enc) - 1, &data, + &data_len)) + return; + + if (!strcmp(type, "application/x-wb") && + !strcmp(enc, "binary") && + !purple_account_get_bool(sg->account, "block-wb", FALSE)) + silcpurple_wb_receive_ch(client, conn, sender, channel, + payload, flags, data, data_len); +#endif + return; + } + + if (flags & SILC_MESSAGE_FLAG_ACTION) { + msg = g_strdup_printf("/me %s", + (const char *)message); + if (!msg) + return; + + tmp = g_markup_escape_text(msg, -1); + /* Send to Purple */ + serv_got_chat_in(gc, purple_conv_chat_get_id(PURPLE_CONV_CHAT(convo)), + sender->nickname ? + sender->nickname : "<unknown>", 0, + tmp, time(NULL)); + g_free(tmp); + g_free(msg); + return; + } + + if (flags & SILC_MESSAGE_FLAG_NOTICE) { + msg = g_strdup_printf("(notice) <I>%s</I> %s", + sender->nickname ? + sender->nickname : "<unknown>", + (const char *)message); + if (!msg) + return; + + /* Send to Purple */ + purple_conversation_write(convo, NULL, (const char *)msg, + PURPLE_MESSAGE_SYSTEM, time(NULL)); + g_free(msg); + return; + } + + if (flags & SILC_MESSAGE_FLAG_UTF8) { + tmp = g_markup_escape_text((const char *)message, -1); + /* Send to Purple */ + serv_got_chat_in(gc, purple_conv_chat_get_id(PURPLE_CONV_CHAT(convo)), + sender->nickname ? + sender->nickname : "<unknown>", 0, + tmp, time(NULL)); + g_free(tmp); + } +} + + +/* Private message to the client. The `sender' is the sender of the + message. The message is `message'and maybe NULL. The `flags' + indicates message flags and it is used to determine how the message + can be interpreted (like it may tell the message is multimedia + message). */ + +static void +silc_private_message(SilcClient client, SilcClientConnection conn, + SilcClientEntry sender, SilcMessagePayload payload, + SilcMessageFlags flags, const unsigned char *message, + SilcUInt32 message_len) +{ + PurpleConnection *gc = client->application; + SilcPurple sg = gc->proto_data; + PurpleConversation *convo = NULL; + char *msg, *tmp; + + if (!message) + return; + + if (sender->nickname) + /* XXX - Should this be PURPLE_CONV_TYPE_IM? */ + convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_ANY, + sender->nickname, sg->account); + + if (flags & SILC_MESSAGE_FLAG_SIGNED && + purple_account_get_bool(sg->account, "sign-verify", FALSE)) { + /* XXX */ + } + + if (flags & SILC_MESSAGE_FLAG_DATA) { +#ifdef HAVE_SILCMIME_H + /* Process MIME message */ + SilcMime mime; + mime = silc_mime_decode(message, message_len); + silcpurple_mime_message(client, conn, sender, NULL, payload, + NULL, flags, mime, FALSE); +#else + char type[128], enc[128]; + unsigned char *data; + SilcUInt32 data_len; + + memset(type, 0, sizeof(type)); + memset(enc, 0, sizeof(enc)); + + if (!silc_mime_parse(message, message_len, NULL, 0, + type, sizeof(type) - 1, enc, sizeof(enc) - 1, &data, + &data_len)) + return; + + if (!strcmp(type, "application/x-wb") && + !strcmp(enc, "binary") && + !purple_account_get_bool(sg->account, "block-wb", FALSE)) + silcpurple_wb_receive(client, conn, sender, payload, + flags, data, data_len); +#endif + return; + } + + if (flags & SILC_MESSAGE_FLAG_ACTION && convo) { + msg = g_strdup_printf("/me %s", + (const char *)message); + if (!msg) + return; + + tmp = g_markup_escape_text(msg, -1); + /* Send to Purple */ + serv_got_im(gc, sender->nickname ? + sender->nickname : "<unknown>", + tmp, 0, time(NULL)); + g_free(msg); + g_free(tmp); + return; + } + + if (flags & SILC_MESSAGE_FLAG_NOTICE && convo) { + msg = g_strdup_printf("(notice) <I>%s</I> %s", + sender->nickname ? + sender->nickname : "<unknown>", + (const char *)message); + if (!msg) + return; + + /* Send to Purple */ + purple_conversation_write(convo, NULL, (const char *)msg, + PURPLE_MESSAGE_SYSTEM, time(NULL)); + g_free(msg); + return; + } + + if (flags & SILC_MESSAGE_FLAG_UTF8) { + tmp = g_markup_escape_text((const char *)message, -1); + /* Send to Purple */ + serv_got_im(gc, sender->nickname ? + sender->nickname : "<unknown>", + tmp, 0, time(NULL)); + g_free(tmp); + } +} + + +/* Notify message to the client. The notify arguments are sent in the + same order as servers sends them. The arguments are same as received + from the server except for ID's. If ID is received application receives + the corresponding entry to the ID. For example, if Client ID is received + application receives SilcClientEntry. Also, if the notify type is + for channel the channel entry is sent to application (even if server + does not send it because client library gets the channel entry from + the Channel ID in the packet's header). */ + +static void +silc_notify(SilcClient client, SilcClientConnection conn, + SilcNotifyType type, ...) +{ + va_list va; + PurpleConnection *gc = client->application; + SilcPurple sg = gc->proto_data; + PurpleConversation *convo; + SilcClientEntry client_entry, client_entry2; + SilcChannelEntry channel; + SilcServerEntry server_entry; + SilcIdType idtype; + void *entry; + SilcUInt32 mode; + SilcHashTableList htl; + SilcChannelUser chu; + char buf[512], buf2[512], *tmp, *name; + SilcNotifyType notify; + PurpleBuddy *b; + int i; + + va_start(va, type); + memset(buf, 0, sizeof(buf)); + + switch (type) { + + case SILC_NOTIFY_TYPE_NONE: + break; + + case SILC_NOTIFY_TYPE_INVITE: + { + GHashTable *components; + va_arg(va, SilcChannelEntry); + name = va_arg(va, char *); + client_entry = va_arg(va, SilcClientEntry); + + components = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); + g_hash_table_insert(components, strdup("channel"), strdup(name)); + serv_got_chat_invite(gc, name, client_entry->nickname, NULL, components); + } + break; + + case SILC_NOTIFY_TYPE_JOIN: + client_entry = va_arg(va, SilcClientEntry); + channel = va_arg(va, SilcChannelEntry); + + /* If we joined channel, do nothing */ + if (client_entry == conn->local_entry) + break; + + convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, + channel->channel_name, sg->account); + if (!convo) + break; + + /* Join user to channel */ + g_snprintf(buf, sizeof(buf), "%s@%s", + client_entry->username, client_entry->hostname); + purple_conv_chat_add_user(PURPLE_CONV_CHAT(convo), + g_strdup(client_entry->nickname), buf, PURPLE_CBFLAGS_NONE, TRUE); + + break; + + case SILC_NOTIFY_TYPE_LEAVE: + client_entry = va_arg(va, SilcClientEntry); + channel = va_arg(va, SilcChannelEntry); + + convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, + channel->channel_name, sg->account); + if (!convo) + break; + + /* Remove user from channel */ + purple_conv_chat_remove_user(PURPLE_CONV_CHAT(convo), + client_entry->nickname, NULL); + + break; + + case SILC_NOTIFY_TYPE_SIGNOFF: + client_entry = va_arg(va, SilcClientEntry); + tmp = va_arg(va, char *); + + if (!client_entry->nickname) + break; + + /* Remove from all channels */ + silc_hash_table_list(client_entry->channels, &htl); + while (silc_hash_table_get(&htl, NULL, (void *)&chu)) { + convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, + chu->channel->channel_name, sg->account); + if (!convo) + continue; + purple_conv_chat_remove_user(PURPLE_CONV_CHAT(convo), + client_entry->nickname, + tmp); + } + silc_hash_table_list_reset(&htl); + + break; + + case SILC_NOTIFY_TYPE_TOPIC_SET: + { + char *esc, *tmp2; + idtype = va_arg(va, int); + entry = va_arg(va, void *); + tmp = va_arg(va, char *); + channel = va_arg(va, SilcChannelEntry); + + convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, + channel->channel_name, sg->account); + if (!convo) + break; + + if (!tmp) + break; + + esc = g_markup_escape_text(tmp, -1); + tmp2 = purple_markup_linkify(esc); + g_free(esc); + + if (idtype == SILC_ID_CLIENT) { + client_entry = (SilcClientEntry)entry; + g_snprintf(buf, sizeof(buf), + _("%s has changed the topic of <I>%s</I> to: %s"), + client_entry->nickname, channel->channel_name, tmp2); + purple_conv_chat_write(PURPLE_CONV_CHAT(convo), client_entry->nickname, + buf, PURPLE_MESSAGE_SYSTEM, time(NULL)); + purple_conv_chat_set_topic(PURPLE_CONV_CHAT(convo), + client_entry->nickname, tmp); + } else if (idtype == SILC_ID_SERVER) { + server_entry = (SilcServerEntry)entry; + g_snprintf(buf, sizeof(buf), + _("%s has changed the topic of <I>%s</I> to: %s"), + server_entry->server_name, channel->channel_name, tmp2); + purple_conv_chat_write(PURPLE_CONV_CHAT(convo), server_entry->server_name, + buf, PURPLE_MESSAGE_SYSTEM, time(NULL)); + purple_conv_chat_set_topic(PURPLE_CONV_CHAT(convo), + server_entry->server_name, tmp); + } else if (idtype == SILC_ID_CHANNEL) { + channel = (SilcChannelEntry)entry; + g_snprintf(buf, sizeof(buf), + _("%s has changed the topic of <I>%s</I> to: %s"), + channel->channel_name, channel->channel_name, tmp2); + purple_conv_chat_write(PURPLE_CONV_CHAT(convo), channel->channel_name, + buf, PURPLE_MESSAGE_SYSTEM, time(NULL)); + purple_conv_chat_set_topic(PURPLE_CONV_CHAT(convo), + channel->channel_name, tmp); + } else { + purple_conv_chat_set_topic(PURPLE_CONV_CHAT(convo), NULL, tmp); + } + + g_free(tmp2); + + break; + + } + case SILC_NOTIFY_TYPE_NICK_CHANGE: + client_entry = va_arg(va, SilcClientEntry); + client_entry2 = va_arg(va, SilcClientEntry); + + if (!strcmp(client_entry->nickname, client_entry2->nickname)) + break; + + /* Change nick on all channels */ + silc_hash_table_list(client_entry2->channels, &htl); + while (silc_hash_table_get(&htl, NULL, (void *)&chu)) { + convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, + chu->channel->channel_name, sg->account); + if (!convo) + continue; + if (purple_conv_chat_find_user(PURPLE_CONV_CHAT(convo), client_entry->nickname)) + purple_conv_chat_rename_user(PURPLE_CONV_CHAT(convo), + client_entry->nickname, + client_entry2->nickname); + } + silc_hash_table_list_reset(&htl); + + break; + + case SILC_NOTIFY_TYPE_CMODE_CHANGE: + idtype = va_arg(va, int); + entry = va_arg(va, void *); + mode = va_arg(va, SilcUInt32); + (void)va_arg(va, char *); + (void)va_arg(va, char *); + (void)va_arg(va, char *); + (void)va_arg(va, SilcPublicKey); + (void)va_arg(va, SilcBuffer); + channel = va_arg(va, SilcChannelEntry); + + convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, + channel->channel_name, sg->account); + if (!convo) + break; + + if (idtype == SILC_ID_CLIENT) + name = ((SilcClientEntry)entry)->nickname; + else if (idtype == SILC_ID_SERVER) + name = ((SilcServerEntry)entry)->server_name; + else + name = ((SilcChannelEntry)entry)->channel_name; + if (!name) + break; + + if (mode) { + silcpurple_get_chmode_string(mode, buf2, sizeof(buf2)); + g_snprintf(buf, sizeof(buf), + _("<I>%s</I> set channel <I>%s</I> modes to: %s"), name, + channel->channel_name, buf2); + } else { + g_snprintf(buf, sizeof(buf), + _("<I>%s</I> removed all channel <I>%s</I> modes"), name, + channel->channel_name); + } + purple_conv_chat_write(PURPLE_CONV_CHAT(convo), channel->channel_name, + buf, PURPLE_MESSAGE_SYSTEM, time(NULL)); + break; + + case SILC_NOTIFY_TYPE_CUMODE_CHANGE: + { + PurpleConvChatBuddyFlags flags = PURPLE_CBFLAGS_NONE; + idtype = va_arg(va, int); + entry = va_arg(va, void *); + mode = va_arg(va, SilcUInt32); + client_entry2 = va_arg(va, SilcClientEntry); + channel = va_arg(va, SilcChannelEntry); + + convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, + channel->channel_name, sg->account); + if (!convo) + break; + + if (idtype == SILC_ID_CLIENT) + name = ((SilcClientEntry)entry)->nickname; + else if (idtype == SILC_ID_SERVER) + name = ((SilcServerEntry)entry)->server_name; + else + name = ((SilcChannelEntry)entry)->channel_name; + if (!name) + break; + + if (mode) { + silcpurple_get_chumode_string(mode, buf2, sizeof(buf2)); + g_snprintf(buf, sizeof(buf), + _("<I>%s</I> set <I>%s's</I> modes to: %s"), name, + client_entry2->nickname, buf2); + if (mode & SILC_CHANNEL_UMODE_CHANFO) + flags |= PURPLE_CBFLAGS_FOUNDER; + if (mode & SILC_CHANNEL_UMODE_CHANOP) + flags |= PURPLE_CBFLAGS_OP; + } else { + g_snprintf(buf, sizeof(buf), + _("<I>%s</I> removed all <I>%s's</I> modes"), name, + client_entry2->nickname); + } + purple_conv_chat_write(PURPLE_CONV_CHAT(convo), channel->channel_name, + buf, PURPLE_MESSAGE_SYSTEM, time(NULL)); + purple_conv_chat_user_set_flags(PURPLE_CONV_CHAT(convo), client_entry2->nickname, flags); + break; + } + + case SILC_NOTIFY_TYPE_MOTD: + tmp = va_arg(va, char *); + silc_free(sg->motd); + sg->motd = silc_memdup(tmp, strlen(tmp)); + break; + + case SILC_NOTIFY_TYPE_KICKED: + client_entry = va_arg(va, SilcClientEntry); + tmp = va_arg(va, char *); + client_entry2 = va_arg(va, SilcClientEntry); + channel = va_arg(va, SilcChannelEntry); + + convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, + channel->channel_name, sg->account); + if (!convo) + break; + + if (client_entry == conn->local_entry) { + /* Remove us from channel */ + g_snprintf(buf, sizeof(buf), + _("You have been kicked off <I>%s</I> by <I>%s</I> (%s)"), + channel->channel_name, client_entry2->nickname, + tmp ? tmp : ""); + purple_conv_chat_write(PURPLE_CONV_CHAT(convo), client_entry->nickname, + buf, PURPLE_MESSAGE_SYSTEM, time(NULL)); + serv_got_chat_left(gc, purple_conv_chat_get_id(PURPLE_CONV_CHAT(convo))); + } else { + /* Remove user from channel */ + g_snprintf(buf, sizeof(buf), _("Kicked by %s (%s)"), + client_entry2->nickname, tmp ? tmp : ""); + purple_conv_chat_remove_user(PURPLE_CONV_CHAT(convo), + client_entry->nickname, + buf); + } + + break; + + case SILC_NOTIFY_TYPE_KILLED: + client_entry = va_arg(va, SilcClientEntry); + tmp = va_arg(va, char *); + idtype = va_arg(va, int); + entry = va_arg(va, SilcClientEntry); + + if (!client_entry->nickname) + break; + + if (client_entry == conn->local_entry) { + if (idtype == SILC_ID_CLIENT) { + client_entry2 = (SilcClientEntry)entry; + g_snprintf(buf, sizeof(buf), + _("You have been killed by %s (%s)"), + client_entry2->nickname, tmp ? tmp : ""); + } else if (idtype == SILC_ID_SERVER) { + server_entry = (SilcServerEntry)entry; + g_snprintf(buf, sizeof(buf), + _("You have been killed by %s (%s)"), + server_entry->server_name, tmp ? tmp : ""); + } else if (idtype == SILC_ID_CHANNEL) { + channel = (SilcChannelEntry)entry; + g_snprintf(buf, sizeof(buf), + _("You have been killed by %s (%s)"), + channel->channel_name, tmp ? tmp : ""); + } + + /* Remove us from all channels */ + silc_hash_table_list(client_entry->channels, &htl); + while (silc_hash_table_get(&htl, NULL, (void *)&chu)) { + convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, + chu->channel->channel_name, sg->account); + if (!convo) + continue; + purple_conv_chat_write(PURPLE_CONV_CHAT(convo), client_entry->nickname, + buf, PURPLE_MESSAGE_SYSTEM, time(NULL)); + serv_got_chat_left(gc, purple_conv_chat_get_id(PURPLE_CONV_CHAT(convo))); + } + silc_hash_table_list_reset(&htl); + + } else { + if (idtype == SILC_ID_CLIENT) { + client_entry2 = (SilcClientEntry)entry; + g_snprintf(buf, sizeof(buf), + _("Killed by %s (%s)"), + client_entry2->nickname, tmp ? tmp : ""); + } else if (idtype == SILC_ID_SERVER) { + server_entry = (SilcServerEntry)entry; + g_snprintf(buf, sizeof(buf), + _("Killed by %s (%s)"), + server_entry->server_name, tmp ? tmp : ""); + } else if (idtype == SILC_ID_CHANNEL) { + channel = (SilcChannelEntry)entry; + g_snprintf(buf, sizeof(buf), + _("Killed by %s (%s)"), + channel->channel_name, tmp ? tmp : ""); + } + + /* Remove user from all channels */ + silc_hash_table_list(client_entry->channels, &htl); + while (silc_hash_table_get(&htl, NULL, (void *)&chu)) { + convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, + chu->channel->channel_name, sg->account); + if (!convo) + continue; + purple_conv_chat_remove_user(PURPLE_CONV_CHAT(convo), + client_entry->nickname, tmp); + } + silc_hash_table_list_reset(&htl); + } + + break; + + case SILC_NOTIFY_TYPE_CHANNEL_CHANGE: + break; + + case SILC_NOTIFY_TYPE_SERVER_SIGNOFF: + { + int i; + SilcClientEntry *clients; + SilcUInt32 clients_count; + + (void)va_arg(va, void *); + clients = va_arg(va, SilcClientEntry *); + clients_count = va_arg(va, SilcUInt32); + + for (i = 0; i < clients_count; i++) { + if (!clients[i]->nickname) + break; + + /* Remove from all channels */ + silc_hash_table_list(clients[i]->channels, &htl); + while (silc_hash_table_get(&htl, NULL, (void *)&chu)) { + convo = + purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, + chu->channel->channel_name, sg->account); + if (!convo) + continue; + purple_conv_chat_remove_user(PURPLE_CONV_CHAT(convo), + clients[i]->nickname, + _("Server signoff")); + } + silc_hash_table_list_reset(&htl); + } + } + break; + + case SILC_NOTIFY_TYPE_ERROR: + { + SilcStatus error = va_arg(va, int); + purple_notify_error(gc, "Error Notify", + silc_get_status_message(error), + NULL); + } + break; + + case SILC_NOTIFY_TYPE_WATCH: + { + SilcPublicKey public_key; + unsigned char *pk; + SilcUInt32 pk_len; + char *fingerprint; + + client_entry = va_arg(va, SilcClientEntry); + (void)va_arg(va, char *); + mode = va_arg(va, SilcUInt32); + notify = va_arg(va, int); + public_key = va_arg(va, SilcPublicKey); + + b = NULL; + if (public_key) { + PurpleBlistNode *gnode, *cnode, *bnode; + const char *f; + + pk = silc_pkcs_public_key_encode(public_key, &pk_len); + if (!pk) + break; + fingerprint = silc_hash_fingerprint(NULL, pk, pk_len); + for (i = 0; i < strlen(fingerprint); i++) + if (fingerprint[i] == ' ') + fingerprint[i] = '_'; + g_snprintf(buf, sizeof(buf) - 1, + "%s" G_DIR_SEPARATOR_S "clientkeys" + G_DIR_SEPARATOR_S "clientkey_%s.pub", + silcpurple_silcdir(), fingerprint); + silc_free(fingerprint); + silc_free(pk); + + /* Find buddy by associated public key */ + for (gnode = purple_get_blist()->root; gnode; + gnode = gnode->next) { + if (!PURPLE_BLIST_NODE_IS_GROUP(gnode)) + continue; + for (cnode = gnode->child; cnode; cnode = cnode->next) { + if( !PURPLE_BLIST_NODE_IS_CONTACT(cnode)) + continue; + for (bnode = cnode->child; bnode; + bnode = bnode->next) { + if (!PURPLE_BLIST_NODE_IS_BUDDY(bnode)) + continue; + b = (PurpleBuddy *)bnode; + if (b->account != gc->account) + continue; + f = purple_blist_node_get_string(bnode, "public-key"); + if (f && !strcmp(f, buf)) + goto cont; + b = NULL; + } + } + } + } + cont: + if (!b) { + /* Find buddy by nickname */ + b = purple_find_buddy(sg->account, client_entry->nickname); + if (!b) { + purple_debug_warning("silc", "WATCH for %s, unknown buddy", + client_entry->nickname); + break; + } + } + + silc_free(b->proto_data); + b->proto_data = silc_memdup(client_entry->id, + sizeof(*client_entry->id)); + if (notify == SILC_NOTIFY_TYPE_NICK_CHANGE) { + break; + } else if (notify == SILC_NOTIFY_TYPE_UMODE_CHANGE) { + /* See if client was away and is now present */ + if (!(mode & (SILC_UMODE_GONE | SILC_UMODE_INDISPOSED | + SILC_UMODE_BUSY | SILC_UMODE_PAGE | + SILC_UMODE_DETACHED)) && + (client_entry->mode & SILC_UMODE_GONE || + client_entry->mode & SILC_UMODE_INDISPOSED || + client_entry->mode & SILC_UMODE_BUSY || + client_entry->mode & SILC_UMODE_PAGE || + client_entry->mode & SILC_UMODE_DETACHED)) { + client_entry->mode = mode; + purple_prpl_got_user_status(purple_buddy_get_account(b), purple_buddy_get_name(b), SILCPURPLE_STATUS_ID_AVAILABLE, NULL); + } + else if ((mode & SILC_UMODE_GONE) || + (mode & SILC_UMODE_INDISPOSED) || + (mode & SILC_UMODE_BUSY) || + (mode & SILC_UMODE_PAGE) || + (mode & SILC_UMODE_DETACHED)) { + client_entry->mode = mode; + purple_prpl_got_user_status(purple_buddy_get_account(b), purple_buddy_get_name(b), SILCPURPLE_STATUS_ID_OFFLINE, NULL); + } + } else if (notify == SILC_NOTIFY_TYPE_SIGNOFF || + notify == SILC_NOTIFY_TYPE_SERVER_SIGNOFF || + notify == SILC_NOTIFY_TYPE_KILLED) { + client_entry->mode = mode; + purple_prpl_got_user_status(purple_buddy_get_account(b), purple_buddy_get_name(b), SILCPURPLE_STATUS_ID_OFFLINE, NULL); + } else if (notify == SILC_NOTIFY_TYPE_NONE) { + client_entry->mode = mode; + purple_prpl_got_user_status(purple_buddy_get_account(b), purple_buddy_get_name(b), SILCPURPLE_STATUS_ID_AVAILABLE, NULL); + } + } + break; + + default: + purple_debug_info("silc", "Unhandled notification: %d\n", type); + break; + } + + va_end(va); +} + + +/* Command handler. This function is called always in the command function. + If error occurs it will be called as well. `conn' is the associated + client connection. `cmd_context' is the command context that was + originally sent to the command. `success' is FALSE if error occurred + during command. `command' is the command being processed. It must be + noted that this is not reply from server. This is merely called just + after application has called the command. Just to tell application + that the command really was processed. */ + +static void +silc_command(SilcClient client, SilcClientConnection conn, + SilcClientCommandContext cmd_context, bool success, + SilcCommand command, SilcStatus status) +{ + PurpleConnection *gc = client->application; + SilcPurple sg = gc->proto_data; + + switch (command) { + + case SILC_COMMAND_CMODE: + if (cmd_context->argc == 3 && + !strcmp((char *)cmd_context->argv[2], "+C")) + sg->chpk = TRUE; + else + sg->chpk = FALSE; + break; + + default: + break; + } +} + +#if 0 +static void +silcpurple_whois_more(SilcClientEntry client_entry, gint id) +{ + SilcAttributePayload attr; + SilcAttribute attribute; + char *buf; + GString *s; + SilcVCardStruct vcard; + int i; + + if (id != 0) + return; + + memset(&vcard, 0, sizeof(vcard)); + + s = g_string_new(""); + + silc_dlist_start(client_entry->attrs); + while ((attr = silc_dlist_get(client_entry->attrs)) != SILC_LIST_END) { + attribute = silc_attribute_get_attribute(attr); + switch (attribute) { + + case SILC_ATTRIBUTE_USER_INFO: + if (!silc_attribute_get_object(attr, (void *)&vcard, + sizeof(vcard))) + continue; + g_string_append_printf(s, "%s:\n\n", _("Personal Information")); + if (vcard.full_name) + g_string_append_printf(s, "%s:\t\t%s\n", + _("Full Name"), + vcard.full_name); + if (vcard.first_name) + g_string_append_printf(s, "%s:\t%s\n", + _("First Name"), + vcard.first_name); + if (vcard.middle_names) + g_string_append_printf(s, "%s:\t%s\n", + _("Middle Name"), + vcard.middle_names); + if (vcard.family_name) + g_string_append_printf(s, "%s:\t%s\n", + _("Family Name"), + vcard.family_name); + if (vcard.nickname) + g_string_append_printf(s, "%s:\t\t%s\n", + _("Nickname"), + vcard.nickname); + if (vcard.bday) + g_string_append_printf(s, "%s:\t\t%s\n", + _("Birth Day"), + vcard.bday); + if (vcard.title) + g_string_append_printf(s, "%s:\t\t%s\n", + _("Job Title"), + vcard.title); + if (vcard.role) + g_string_append_printf(s, "%s:\t\t%s\n", + _("Job Role"), + vcard.role); + if (vcard.org_name) + g_string_append_printf(s, "%s:\t%s\n", + _("Organization"), + vcard.org_name); + if (vcard.org_unit) + g_string_append_printf(s, "%s:\t\t%s\n", + _("Unit"), + vcard.org_unit); + if (vcard.url) + g_string_append_printf(s, "%s:\t%s\n", + _("Homepage"), + vcard.url); + if (vcard.label) + g_string_append_printf(s, "%s:\t%s\n", + _("Address"), + vcard.label); + for (i = 0; i < vcard.num_tels; i++) { + if (vcard.tels[i].telnum) + g_string_append_printf(s, "%s:\t\t\t%s\n", + _("Phone"), + vcard.tels[i].telnum); + } + for (i = 0; i < vcard.num_emails; i++) { + if (vcard.emails[i].address) + g_string_append_printf(s, "%s:\t\t%s\n", + _("E-Mail"), + vcard.emails[i].address); + } + if (vcard.note) + g_string_append_printf(s, "\n%s:\t\t%s\n", + _("Note"), + vcard.note); + break; + } + } + + buf = g_string_free(s, FALSE); + purple_notify_info(NULL, _("User Information"), _("User Information"), + buf); + g_free(buf); +} +#endif + +/* Command reply handler. This function is called always in the command reply + function. If error occurs it will be called as well. Normal scenario + is that it will be called after the received command data has been parsed + and processed. The function is used to pass the received command data to + the application. + + `conn' is the associated client connection. `cmd_payload' is the command + payload data received from server and it can be ignored. It is provided + if the application would like to re-parse the received command data, + however, it must be noted that the data is parsed already by the library + thus the payload can be ignored. `success' is FALSE if error occurred. + In this case arguments are not sent to the application. The `status' is + the command reply status server returned. The `command' is the command + reply being processed. The function has variable argument list and each + command defines the number and type of arguments it passes to the + application (on error they are not sent). */ + +static void +silc_command_reply(SilcClient client, SilcClientConnection conn, + SilcCommandPayload cmd_payload, bool success, + SilcCommand command, SilcStatus status, ...) +{ + PurpleConnection *gc = client->application; + SilcPurple sg = gc->proto_data; + PurpleConversation *convo; + va_list vp; + + va_start(vp, status); + + switch (command) { + case SILC_COMMAND_JOIN: + { + SilcChannelEntry channel_entry; + + if (!success) { + purple_notify_error(gc, _("Join Chat"), _("Cannot join channel"), + silc_get_status_message(status)); + return; + } + + (void)va_arg(vp, char *); + channel_entry = va_arg(vp, SilcChannelEntry); + + /* Resolve users on channel */ + silc_client_get_clients_by_channel(client, conn, channel_entry, + silcpurple_chat_join_done, + channel_entry); + } + break; + + case SILC_COMMAND_LEAVE: + break; + + case SILC_COMMAND_USERS: + break; + + case SILC_COMMAND_WHOIS: + { + SilcUInt32 idle, mode; + SilcBuffer channels, user_modes; + SilcClientEntry client_entry; + char tmp[1024], *tmp2; + char *moodstr, *statusstr, *contactstr, *langstr, *devicestr, *tzstr, *geostr; + PurpleNotifyUserInfo *user_info; + + if (!success) { + purple_notify_error(gc, _("User Information"), + _("Cannot get user information"), + silc_get_status_message(status)); + break; + } + + client_entry = va_arg(vp, SilcClientEntry); + if (!client_entry->nickname) + break; + (void)va_arg(vp, char *); + (void)va_arg(vp, char *); + (void)va_arg(vp, char *); + channels = va_arg(vp, SilcBuffer); + mode = va_arg(vp, SilcUInt32); + idle = va_arg(vp, SilcUInt32); + (void)va_arg(vp, unsigned char *); + user_modes = va_arg(vp, SilcBuffer); + + user_info = purple_notify_user_info_new(); + tmp2 = g_markup_escape_text(client_entry->nickname, -1); + purple_notify_user_info_add_pair(user_info, _("Nickname"), tmp2); + g_free(tmp2); + if (client_entry->realname) { + tmp2 = g_markup_escape_text(client_entry->realname, -1); + purple_notify_user_info_add_pair(user_info, _("Real Name"), tmp2); + g_free(tmp2); + } + if (client_entry->username) { + tmp2 = g_markup_escape_text(client_entry->username, -1); + if (client_entry->hostname) { + gchar *tmp3; + tmp3 = g_strdup_printf("%s@%s", tmp2, client_entry->hostname); + purple_notify_user_info_add_pair(user_info, _("Username"), tmp3); + g_free(tmp3); + } else + purple_notify_user_info_add_pair(user_info, _("Username"), tmp2); + g_free(tmp2); + } + + if (client_entry->mode) { + memset(tmp, 0, sizeof(tmp)); + silcpurple_get_umode_string(client_entry->mode, + tmp, sizeof(tmp) - strlen(tmp)); + purple_notify_user_info_add_pair(user_info, _("User Modes"), tmp); + } + + silcpurple_parse_attrs(client_entry->attrs, &moodstr, &statusstr, &contactstr, &langstr, &devicestr, &tzstr, &geostr); + if (moodstr) { + purple_notify_user_info_add_pair(user_info, _("Mood"), moodstr); + g_free(moodstr); + } + + if (statusstr) { + tmp2 = g_markup_escape_text(statusstr, -1); + purple_notify_user_info_add_pair(user_info, _("Status Text"), tmp2); + g_free(statusstr); + g_free(tmp2); + } + + if (contactstr) { + purple_notify_user_info_add_pair(user_info, _("Preferred Contact"), contactstr); + g_free(contactstr); + } + + if (langstr) { + purple_notify_user_info_add_pair(user_info, _("Preferred Language"), langstr); + g_free(langstr); + } + + if (devicestr) { + purple_notify_user_info_add_pair(user_info, _("Device"), devicestr); + g_free(devicestr); + } + + if (tzstr) { + purple_notify_user_info_add_pair(user_info, _("Timezone"), tzstr); + g_free(tzstr); + } + + if (geostr) { + purple_notify_user_info_add_pair(user_info, _("Geolocation"), geostr); + g_free(geostr); + } + + if (client_entry->server) + purple_notify_user_info_add_pair(user_info, _("Server"), client_entry->server); + + if (channels && user_modes) { + SilcUInt32 *umodes; + SilcDList list = + silc_channel_payload_parse_list(channels->data, + channels->len); + if (list && silc_get_mode_list(user_modes, + silc_dlist_count(list), + &umodes)) { + SilcChannelPayload entry; + int i = 0; + + memset(tmp, 0, sizeof(tmp)); + silc_dlist_start(list); + while ((entry = silc_dlist_get(list)) + != SILC_LIST_END) { + SilcUInt32 name_len; + char *m = silc_client_chumode_char(umodes[i++]); + char *name = (char *)silc_channel_get_name(entry, &name_len); + if (m) + silc_strncat(tmp, sizeof(tmp) - 1, m, strlen(m)); + silc_strncat(tmp, sizeof(tmp) - 1, name, name_len); + silc_strncat(tmp, sizeof(tmp) - 1, " ", 1); + silc_free(m); + + } + tmp2 = g_markup_escape_text(tmp, -1); + purple_notify_user_info_add_pair(user_info, _("Currently on"), tmp2); + g_free(tmp2); + silc_free(umodes); + } + } + + if (client_entry->public_key) { + char *fingerprint, *babbleprint; + unsigned char *pk; + SilcUInt32 pk_len; + pk = silc_pkcs_public_key_encode(client_entry->public_key, &pk_len); + fingerprint = silc_hash_fingerprint(NULL, pk, pk_len); + babbleprint = silc_hash_babbleprint(NULL, pk, pk_len); + purple_notify_user_info_add_pair(user_info, _("Public Key Fingerprint"), fingerprint); + purple_notify_user_info_add_pair(user_info, _("Public Key Babbleprint"), babbleprint); + silc_free(fingerprint); + silc_free(babbleprint); + silc_free(pk); + } + +#if 0 /* XXX for now, let's not show attrs here */ + if (client_entry->attrs) + purple_request_action(gc, _("User Information"), + _("User Information"), + buf, 1, client_entry, 2, + _("OK"), G_CALLBACK(silcpurple_whois_more), + _("_More..."), G_CALLBACK(silcpurple_whois_more), gc->account, NULL, NULL); + else +#endif + purple_notify_userinfo(gc, client_entry->nickname, user_info, NULL, NULL); + purple_notify_user_info_destroy(user_info); + } + break; + + case SILC_COMMAND_WHOWAS: + { + SilcClientEntry client_entry; + char *nickname, *realname, *username, *tmp; + PurpleNotifyUserInfo *user_info; + + if (!success) { + purple_notify_error(gc, _("User Information"), + _("Cannot get user information"), + silc_get_status_message(status)); + break; + } + + client_entry = va_arg(vp, SilcClientEntry); + nickname = va_arg(vp, char *); + username = va_arg(vp, char *); + realname = va_arg(vp, char *); + if (!nickname) + break; + + user_info = purple_notify_user_info_new(); + tmp = g_markup_escape_text(nickname, -1); + purple_notify_user_info_add_pair(user_info, _("Nickname"), tmp); + g_free(tmp); + if (realname) { + tmp = g_markup_escape_text(realname, -1); + purple_notify_user_info_add_pair(user_info, _("Real Name"), tmp); + g_free(tmp); + } + if (username) { + tmp = g_markup_escape_text(username, -1); + if (client_entry && client_entry->hostname) { + gchar *tmp3; + tmp3 = g_strdup_printf("%s@%s", tmp, client_entry->hostname); + purple_notify_user_info_add_pair(user_info, _("Username"), tmp3); + g_free(tmp3); + } else + purple_notify_user_info_add_pair(user_info, _("Username"), tmp); + g_free(tmp); + } + if (client_entry && client_entry->server) + purple_notify_user_info_add_pair(user_info, _("Server"), client_entry->server); + + + if (client_entry && client_entry->public_key) { + char *fingerprint, *babbleprint; + unsigned char *pk; + SilcUInt32 pk_len; + pk = silc_pkcs_public_key_encode(client_entry->public_key, &pk_len); + fingerprint = silc_hash_fingerprint(NULL, pk, pk_len); + babbleprint = silc_hash_babbleprint(NULL, pk, pk_len); + purple_notify_user_info_add_pair(user_info, _("Public Key Fingerprint"), fingerprint); + purple_notify_user_info_add_pair(user_info, _("Public Key Babbleprint"), babbleprint); + silc_free(fingerprint); + silc_free(babbleprint); + silc_free(pk); + } + + purple_notify_userinfo(gc, nickname, user_info, NULL, NULL); + purple_notify_user_info_destroy(user_info); + } + break; + + case SILC_COMMAND_DETACH: + if (!success) { + purple_notify_error(gc, _("Detach From Server"), _("Cannot detach"), + silc_get_status_message(status)); + return; + } + break; + + case SILC_COMMAND_TOPIC: + { + SilcChannelEntry channel; + + if (!success) { + purple_notify_error(gc, _("Topic"), _("Cannot set topic"), + silc_get_status_message(status)); + return; + } + + channel = va_arg(vp, SilcChannelEntry); + + convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, + channel->channel_name, sg->account); + if (!convo) { + purple_debug_error("silc", "Got a topic for %s, which doesn't exist\n", + channel->channel_name); + break; + } + + /* Set topic */ + if (channel->topic) + purple_conv_chat_set_topic(PURPLE_CONV_CHAT(convo), NULL, channel->topic); + } + break; + + case SILC_COMMAND_NICK: + { + /* I don't think we should need to do this because the server should + * be sending a SILC_NOTIFY_TYPE_NICK_CHANGE when we change our own + * nick, but it isn't, so we deal with it here instead. Stu. */ + SilcClientEntry local_entry; + SilcHashTableList htl; + SilcChannelUser chu; + const char *oldnick; + + if (!success) { + purple_notify_error(gc, _("Nick"), _("Failed to change nickname"), + silc_get_status_message(status)); + return; + } + + local_entry = va_arg(vp, SilcClientEntry); + + /* Change nick on all channels */ + silc_hash_table_list(local_entry->channels, &htl); + while (silc_hash_table_get(&htl, NULL, (void *)&chu)) { + convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, + chu->channel->channel_name, sg->account); + if (!convo) + continue; + oldnick = purple_conv_chat_get_nick(PURPLE_CONV_CHAT(convo)); + if (strcmp(oldnick, purple_normalize(purple_conversation_get_account(convo), local_entry->nickname))) { + purple_conv_chat_rename_user(PURPLE_CONV_CHAT(convo), + oldnick, local_entry->nickname); + purple_conv_chat_set_nick(PURPLE_CONV_CHAT(convo), local_entry->nickname); + } + } + silc_hash_table_list_reset(&htl); + + purple_connection_set_display_name(gc, local_entry->nickname); + } + break; + + case SILC_COMMAND_LIST: + { + char *topic, *name; + int usercount; + PurpleRoomlistRoom *room; + + if (sg->roomlist_canceled) + break; + + if (!success) { + purple_notify_error(gc, _("Error"), _("Error retrieving room list"), + silc_get_status_message(status)); + purple_roomlist_set_in_progress(sg->roomlist, FALSE); + purple_roomlist_unref(sg->roomlist); + sg->roomlist = NULL; + return; + } + + (void)va_arg(vp, SilcChannelEntry); + name = va_arg(vp, char *); + if (!name) { + purple_notify_error(gc, _("Roomlist"), _("Cannot get room list"), + silc_get_status_message(status)); + purple_roomlist_set_in_progress(sg->roomlist, FALSE); + purple_roomlist_unref(sg->roomlist); + sg->roomlist = NULL; + return; + } + topic = va_arg(vp, char *); + usercount = va_arg(vp, int); + + room = purple_roomlist_room_new(PURPLE_ROOMLIST_ROOMTYPE_ROOM, name, NULL); + purple_roomlist_room_add_field(sg->roomlist, room, name); + purple_roomlist_room_add_field(sg->roomlist, room, + SILC_32_TO_PTR(usercount)); + purple_roomlist_room_add_field(sg->roomlist, room, + topic ? topic : ""); + purple_roomlist_room_add(sg->roomlist, room); + + if (status == SILC_STATUS_LIST_END || + status == SILC_STATUS_OK) { + purple_roomlist_set_in_progress(sg->roomlist, FALSE); + purple_roomlist_unref(sg->roomlist); + sg->roomlist = NULL; + } + } + break; + + case SILC_COMMAND_GETKEY: + { + SilcPublicKey public_key; + + if (!success) { + purple_notify_error(gc, _("Get Public Key"), + _("Cannot fetch the public key"), + silc_get_status_message(status)); + return; + } + + (void)va_arg(vp, SilcUInt32); + (void)va_arg(vp, void *); + public_key = va_arg(vp, SilcPublicKey); + + if (!public_key) + purple_notify_error(gc, _("Get Public Key"), + _("Cannot fetch the public key"), + _("No public key was received")); + } + break; + + case SILC_COMMAND_INFO: + { + + char *server_name; + char *server_info; + char tmp[256]; + + if (!success) { + purple_notify_error(gc, _("Server Information"), + _("Cannot get server information"), + silc_get_status_message(status)); + return; + } + + (void)va_arg(vp, SilcServerEntry); + server_name = va_arg(vp, char *); + server_info = va_arg(vp, char *); + + if (server_name && server_info) { + g_snprintf(tmp, sizeof(tmp), "Server: %s\n%s", + server_name, server_info); + purple_notify_info(gc, NULL, _("Server Information"), tmp); + } + } + break; + + case SILC_COMMAND_STATS: + { + SilcUInt32 starttime, uptime, my_clients, my_channels, my_server_ops, + my_router_ops, cell_clients, cell_channels, cell_servers, + clients, channels, servers, routers, server_ops, router_ops; + SilcUInt32 buffer_length; + SilcBufferStruct buf; + + unsigned char *server_stats; + char *msg; + + if (!success) { + purple_notify_error(gc, _("Server Statistics"), + _("Cannot get server statistics"), + silc_get_status_message(status)); + return; + } + + server_stats = va_arg(vp, unsigned char *); + buffer_length = va_arg(vp, SilcUInt32); + if (!server_stats || !buffer_length) { + purple_notify_error(gc, _("Server Statistics"), + _("No server statistics available"), NULL); + break; + } + silc_buffer_set(&buf, server_stats, buffer_length); + silc_buffer_unformat(&buf, + SILC_STR_UI_INT(&starttime), + SILC_STR_UI_INT(&uptime), + SILC_STR_UI_INT(&my_clients), + SILC_STR_UI_INT(&my_channels), + SILC_STR_UI_INT(&my_server_ops), + SILC_STR_UI_INT(&my_router_ops), + SILC_STR_UI_INT(&cell_clients), + SILC_STR_UI_INT(&cell_channels), + SILC_STR_UI_INT(&cell_servers), + SILC_STR_UI_INT(&clients), + SILC_STR_UI_INT(&channels), + SILC_STR_UI_INT(&servers), + SILC_STR_UI_INT(&routers), + SILC_STR_UI_INT(&server_ops), + SILC_STR_UI_INT(&router_ops), + SILC_STR_END); + + msg = g_strdup_printf(_("Local server start time: %s\n" + "Local server uptime: %s\n" + "Local server clients: %d\n" + "Local server channels: %d\n" + "Local server operators: %d\n" + "Local router operators: %d\n" + "Local cell clients: %d\n" + "Local cell channels: %d\n" + "Local cell servers: %d\n" + "Total clients: %d\n" + "Total channels: %d\n" + "Total servers: %d\n" + "Total routers: %d\n" + "Total server operators: %d\n" + "Total router operators: %d\n"), + silc_get_time(starttime), + purple_str_seconds_to_string((int)uptime), + (int)my_clients, (int)my_channels, (int)my_server_ops, (int)my_router_ops, + (int)cell_clients, (int)cell_channels, (int)cell_servers, + (int)clients, (int)channels, (int)servers, (int)routers, + (int)server_ops, (int)router_ops); + + purple_notify_info(gc, NULL, + _("Network Statistics"), msg); + g_free(msg); + } + break; + + case SILC_COMMAND_PING: + { + if (!success) { + purple_notify_error(gc, _("Ping"), _("Ping failed"), + silc_get_status_message(status)); + return; + } + + purple_notify_info(gc, _("Ping"), _("Ping reply received from server"), + NULL); + } + break; + + case SILC_COMMAND_KILL: + if (!success) { + purple_notify_error(gc, _("Kill User"), + _("Could not kill user"), + silc_get_status_message(status)); + return; + } + break; + + case SILC_COMMAND_CMODE: + { + SilcChannelEntry channel_entry; + SilcBuffer channel_pubkeys; + + if (!success) + return; + + channel_entry = va_arg(vp, SilcChannelEntry); + (void)va_arg(vp, SilcUInt32); + (void)va_arg(vp, SilcPublicKey); + channel_pubkeys = va_arg(vp, SilcBuffer); + + if (sg->chpk) + silcpurple_chat_chauth_show(sg, channel_entry, channel_pubkeys); + } + break; + + default: + if (success) + purple_debug_info("silc", "Unhandled command: %d (succeeded)\n", command); + else + purple_debug_info("silc", "Unhandled command: %d (failed: %s)\n", command, + silc_get_status_message(status)); + break; + } + + va_end(vp); +} + + +/* Called to indicate that connection was either successfully established + or connecting failed. This is also the first time application receives + the SilcClientConnection object which it should save somewhere. + If the `success' is FALSE the application must always call the function + silc_client_close_connection. */ + +static void +silc_connected(SilcClient client, SilcClientConnection conn, + SilcClientConnectionStatus status) +{ + PurpleConnection *gc = client->application; + SilcPurple sg; + + if (gc == NULL) { + silc_client_close_connection(client, conn); + return; + } + sg = gc->proto_data; + + switch (status) { + case SILC_CLIENT_CONN_SUCCESS: + case SILC_CLIENT_CONN_SUCCESS_RESUME: + purple_connection_set_state(gc, PURPLE_CONNECTED); + + /* Send the server our buddy list */ + silcpurple_send_buddylist(gc); + + g_unlink(silcpurple_session_file(purple_account_get_username(sg->account))); + + /* Send any UMODEs configured for account */ + if (purple_account_get_bool(sg->account, "block-ims", FALSE)) { + silc_client_command_call(sg->client, sg->conn, NULL, + "UMODE", "+P", NULL); + } + + return; + break; + case SILC_CLIENT_CONN_ERROR: + purple_connection_error(gc, _("Error during connecting to SILC Server")); + g_unlink(silcpurple_session_file(purple_account_get_username(sg->account))); + break; + + case SILC_CLIENT_CONN_ERROR_KE: + purple_connection_error(gc, _("Key Exchange failed")); + break; + + case SILC_CLIENT_CONN_ERROR_AUTH: + purple_connection_error(gc, _("Authentication failed")); + break; + + case SILC_CLIENT_CONN_ERROR_RESUME: + purple_connection_error(gc, + _("Resuming detached session failed. " + "Press Reconnect to create new connection.")); + g_unlink(silcpurple_session_file(purple_account_get_username(sg->account))); + break; + + case SILC_CLIENT_CONN_ERROR_TIMEOUT: + purple_connection_error(gc, _("Connection Timeout")); + break; + } + + /* Error */ + sg->conn = NULL; + silc_client_close_connection(client, conn); +} + + +/* Called to indicate that connection was disconnected to the server. + The `status' may tell the reason of the disconnection, and if the + `message' is non-NULL it may include the disconnection message + received from server. */ + +static void +silc_disconnected(SilcClient client, SilcClientConnection conn, + SilcStatus status, const char *message) +{ + PurpleConnection *gc = client->application; + SilcPurple sg = gc->proto_data; + + if (sg->resuming && !sg->detaching) + g_unlink(silcpurple_session_file(purple_account_get_username(sg->account))); + + sg->conn = NULL; + + /* Close the connection */ + if (!sg->detaching) + purple_connection_error(gc, _("Disconnected by server")); + else + /* TODO: Does this work correctly? Maybe we need to set wants_to_die? */ + purple_account_disconnect(purple_connection_get_account(gc)); +} + + +typedef struct { + SilcGetAuthMeth completion; + void *context; +} *SilcPurpleGetAuthMethod; + +/* Callback called when we've received the authentication method information + from the server after we've requested it. */ + +static void silc_get_auth_method_callback(SilcClient client, + SilcClientConnection conn, + SilcAuthMethod auth_meth, + void *context) +{ + SilcPurpleGetAuthMethod internal = context; + + switch (auth_meth) { + case SILC_AUTH_NONE: + /* No authentication required. */ + (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context); + break; + + case SILC_AUTH_PASSWORD: + /* By returning NULL here the library will ask the passphrase from us + by calling the silc_ask_passphrase. */ + (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context); + break; + + case SILC_AUTH_PUBLIC_KEY: + /* Do not get the authentication data now, the library will generate + it using our default key, if we do not provide it here. */ + (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context); + break; + } + + silc_free(internal); +} + +/* Find authentication method and authentication data by hostname and + port. The hostname may be IP address as well. When the authentication + method has been resolved the `completion' callback with the found + authentication method and authentication data is called. The `conn' + may be NULL. */ + +static void +silc_get_auth_method(SilcClient client, SilcClientConnection conn, + char *hostname, SilcUInt16 port, + SilcGetAuthMeth completion, void *context) +{ + PurpleConnection *gc = client->application; + SilcPurple sg = gc->proto_data; + SilcPurpleGetAuthMethod internal; + const char *password; + + /* Progress */ + if (sg->resuming) + purple_connection_update_progress(gc, _("Resuming session"), 4, 5); + else + purple_connection_update_progress(gc, _("Authenticating connection"), 4, 5); + + /* Check configuration if we have this connection configured. If we + have then return that data immediately, as it's faster way. */ + if (purple_account_get_bool(sg->account, "pubkey-auth", FALSE)) { + completion(TRUE, SILC_AUTH_PUBLIC_KEY, NULL, 0, context); + return; + } + password = purple_connection_get_password(gc); + if (password && *password) { + completion(TRUE, SILC_AUTH_PASSWORD, (unsigned char *)password, strlen(password), context); + return; + } + + /* Resolve the authentication method from server, as we may not know it. */ + internal = silc_calloc(1, sizeof(*internal)); + if (!internal) + return; + internal->completion = completion; + internal->context = context; + silc_client_request_authentication_method(client, conn, + silc_get_auth_method_callback, + internal); +} + + +/* Verifies received public key. The `conn_type' indicates which entity + (server, client etc.) has sent the public key. If user decides to trust + the application may save the key as trusted public key for later + use. The `completion' must be called after the public key has been + verified. */ + +static void +silc_verify_public_key(SilcClient client, SilcClientConnection conn, + SilcSocketType conn_type, unsigned char *pk, + SilcUInt32 pk_len, SilcSKEPKType pk_type, + SilcVerifyPublicKey completion, void *context) +{ + PurpleConnection *gc = client->application; + SilcPurple sg = gc->proto_data; + + if (!sg->conn && (conn_type == SILC_SOCKET_TYPE_SERVER || + conn_type == SILC_SOCKET_TYPE_ROUTER)) { + /* Progress */ + if (sg->resuming) + purple_connection_update_progress(gc, _("Resuming session"), 3, 5); + else + purple_connection_update_progress(gc, _("Verifying server public key"), + 3, 5); + } + + /* Verify public key */ + silcpurple_verify_public_key(client, conn, NULL, conn_type, pk, + pk_len, pk_type, completion, context); +} + +typedef struct { + SilcAskPassphrase completion; + void *context; +} *SilcPurpleAskPassphrase; + +static void +silc_ask_passphrase_cb(SilcPurpleAskPassphrase internal, const char *passphrase) +{ + if (!passphrase || !(*passphrase)) + internal->completion(NULL, 0, internal->context); + else + internal->completion((unsigned char *)passphrase, + strlen(passphrase), internal->context); + silc_free(internal); +} + +/* Ask (interact, that is) a passphrase from user. The passphrase is + returned to the library by calling the `completion' callback with + the `context'. The returned passphrase SHOULD be in UTF-8 encoded, + if not then the library will attempt to encode. */ + +static void +silc_ask_passphrase(SilcClient client, SilcClientConnection conn, + SilcAskPassphrase completion, void *context) +{ + PurpleConnection *gc = client->application; + SilcPurpleAskPassphrase internal = silc_calloc(1, sizeof(*internal)); + + if (!internal) + return; + internal->completion = completion; + internal->context = context; + purple_request_input(gc, _("Passphrase"), NULL, + _("Passphrase required"), NULL, FALSE, TRUE, NULL, + _("OK"), G_CALLBACK(silc_ask_passphrase_cb), + _("Cancel"), G_CALLBACK(silc_ask_passphrase_cb), + purple_connection_get_account(gc), NULL, NULL, internal); +} + + +/* Notifies application that failure packet was received. This is called + if there is some protocol active in the client. The `protocol' is the + protocol context. The `failure' is opaque pointer to the failure + indication. Note, that the `failure' is protocol dependant and + application must explicitly cast it to correct type. Usually `failure' + is 32 bit failure type (see protocol specs for all protocol failure + types). */ + +static void +silc_failure(SilcClient client, SilcClientConnection conn, + SilcProtocol protocol, void *failure) +{ + PurpleConnection *gc = client->application; + char buf[128]; + + memset(buf, 0, sizeof(buf)); + + if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) { + SilcSKEStatus status = (SilcSKEStatus)SILC_PTR_TO_32(failure); + + if (status == SILC_SKE_STATUS_BAD_VERSION) + g_snprintf(buf, sizeof(buf), + _("Failure: Version mismatch, upgrade your client")); + if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY) + g_snprintf(buf, sizeof(buf), + _("Failure: Remote does not trust/support your public key")); + if (status == SILC_SKE_STATUS_UNKNOWN_GROUP) + g_snprintf(buf, sizeof(buf), + _("Failure: Remote does not support proposed KE group")); + if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER) + g_snprintf(buf, sizeof(buf), + _("Failure: Remote does not support proposed cipher")); + if (status == SILC_SKE_STATUS_UNKNOWN_PKCS) + g_snprintf(buf, sizeof(buf), + _("Failure: Remote does not support proposed PKCS")); + if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION) + g_snprintf(buf, sizeof(buf), + _("Failure: Remote does not support proposed hash function")); + if (status == SILC_SKE_STATUS_UNKNOWN_HMAC) + g_snprintf(buf, sizeof(buf), + _("Failure: Remote does not support proposed HMAC")); + if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE) + g_snprintf(buf, sizeof(buf), _("Failure: Incorrect signature")); + if (status == SILC_SKE_STATUS_INVALID_COOKIE) + g_snprintf(buf, sizeof(buf), _("Failure: Invalid cookie")); + + /* Show the error on the progress bar. A more generic error message + is going to be showed to user after this in the silc_connected. */ + purple_connection_update_progress(gc, buf, 2, 5); + } + + if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) { + SilcUInt32 err = SILC_PTR_TO_32(failure); + + if (err == SILC_AUTH_FAILED) + g_snprintf(buf, sizeof(buf), _("Failure: Authentication failed")); + + /* Show the error on the progress bar. A more generic error message + is going to be showed to user after this in the silc_connected. */ + purple_connection_update_progress(gc, buf, 4, 5); + } +} + +/* Asks whether the user would like to perform the key agreement protocol. + This is called after we have received an key agreement packet or an + reply to our key agreement packet. This returns TRUE if the user wants + the library to perform the key agreement protocol and FALSE if it is not + desired (application may start it later by calling the function + silc_client_perform_key_agreement). If TRUE is returned also the + `completion' and `context' arguments must be set by the application. */ + +static bool +silc_key_agreement(SilcClient client, SilcClientConnection conn, + SilcClientEntry client_entry, const char *hostname, + SilcUInt16 port, SilcKeyAgreementCallback *completion, + void **context) +{ + silcpurple_buddy_keyagr_request(client, conn, client_entry, hostname, port); + *completion = NULL; + *context = NULL; + return FALSE; +} + + +/* Notifies application that file transfer protocol session is being + requested by the remote client indicated by the `client_entry' from + the `hostname' and `port'. The `session_id' is the file transfer + session and it can be used to either accept or reject the file + transfer request, by calling the silc_client_file_receive or + silc_client_file_close, respectively. */ + +static void +silc_ftp(SilcClient client, SilcClientConnection conn, + SilcClientEntry client_entry, SilcUInt32 session_id, + const char *hostname, SilcUInt16 port) +{ + silcpurple_ftp_request(client, conn, client_entry, session_id, + hostname, port); +} + + +/* Delivers SILC session detachment data indicated by `detach_data' to the + application. If application has issued SILC_COMMAND_DETACH command + the client session in the SILC network is not quit. The client remains + in the network but is detached. The detachment data may be used later + to resume the session in the SILC Network. The appliation is + responsible of saving the `detach_data', to for example in a file. + + The detachment data can be given as argument to the functions + silc_client_connect_to_server, or silc_client_add_connection when + creating connection to remote server, inside SilcClientConnectionParams + structure. If it is provided the client library will attempt to resume + the session in the network. After the connection is created + successfully, the application is responsible of setting the user + interface for user into the same state it was before detaching (showing + same channels, channel modes, etc). It can do this by fetching the + information (like joined channels) from the client library. */ + +static void +silc_detach(SilcClient client, SilcClientConnection conn, + const unsigned char *detach_data, SilcUInt32 detach_data_len) +{ + PurpleConnection *gc = client->application; + SilcPurple sg = gc->proto_data; + const char *file; + + /* Save the detachment data to file. */ + file = silcpurple_session_file(purple_account_get_username(sg->account)); + g_unlink(file); + silc_file_writefile(file, (char *)detach_data, detach_data_len); +} + +SilcClientOperations ops = { + silc_say, + silc_channel_message, + silc_private_message, + silc_notify, + silc_command, + silc_command_reply, + silc_connected, + silc_disconnected, + silc_get_auth_method, + silc_verify_public_key, + silc_ask_passphrase, + silc_failure, + silc_key_agreement, + silc_ftp, + silc_detach +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/silc10/pk.c Mon Jun 18 01:48:35 2007 +0000 @@ -0,0 +1,274 @@ +/* + + silcpurple_pk.c + + Author: Pekka Riikonen <priikone@silcnet.org> + + Copyright (C) 2004 Pekka Riikonen + + 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; version 2 of the License. + + 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. + +*/ + +#include "silcincludes.h" +#include "silcclient.h" +#include "silcpurple.h" + +/************************* Public Key Verification ***************************/ + +typedef struct { + SilcClient client; + SilcClientConnection conn; + char *filename; + char *entity; + char *entity_name; + char *fingerprint; + char *babbleprint; + unsigned char *pk; + SilcUInt32 pk_len; + SilcSKEPKType pk_type; + SilcVerifyPublicKey completion; + void *context; + gboolean changed; +} *PublicKeyVerify; + +static void silcpurple_verify_ask(const char *entity, + const char *fingerprint, + const char *babbleprint, + PublicKeyVerify verify); + +static void silcpurple_verify_cb(PublicKeyVerify verify, gint id) +{ + if (id != 2) { + if (verify->completion) + verify->completion(FALSE, verify->context); + } else { + if (verify->completion) + verify->completion(TRUE, verify->context); + + /* Save the key for future checking */ + silc_pkcs_save_public_key_data(verify->filename, verify->pk, + verify->pk_len, SILC_PKCS_FILE_PEM); + } + + silc_free(verify->filename); + silc_free(verify->entity); + silc_free(verify->entity_name); + silc_free(verify->fingerprint); + silc_free(verify->babbleprint); + silc_free(verify->pk); + silc_free(verify); +} + +static void silcpurple_verify_details_cb(PublicKeyVerify verify) +{ + /* What a hack. We have to display the accept dialog _again_ + because Purple closes the dialog after you press the button. Purple + should have option for the dialogs whether the buttons close them + or not. */ + silcpurple_verify_ask(verify->entity, verify->fingerprint, + verify->babbleprint, verify); +} + +static void silcpurple_verify_details(PublicKeyVerify verify, gint id) +{ + SilcPublicKey public_key; + PurpleConnection *gc = verify->client->application; + SilcPurple sg = gc->proto_data; + + silc_pkcs_public_key_decode(verify->pk, verify->pk_len, + &public_key); + silcpurple_show_public_key(sg, verify->entity_name, public_key, + G_CALLBACK(silcpurple_verify_details_cb), + verify); + silc_pkcs_public_key_free(public_key); +} + +static void silcpurple_verify_ask(const char *entity, + const char *fingerprint, + const char *babbleprint, + PublicKeyVerify verify) +{ + PurpleConnection *gc = verify->client->application; + char tmp[256], tmp2[256]; + + if (verify->changed) { + g_snprintf(tmp, sizeof(tmp), + _("Received %s's public key. Your local copy does not match this " + "key. Would you still like to accept this public key?"), + entity); + } else { + g_snprintf(tmp, sizeof(tmp), + _("Received %s's public key. Would you like to accept this " + "public key?"), entity); + } + g_snprintf(tmp2, sizeof(tmp2), + _("Fingerprint and babbleprint for the %s key are:\n\n" + "%s\n%s\n"), entity, fingerprint, babbleprint); + + purple_request_action(gc, _("Verify Public Key"), tmp, tmp2, + PURPLE_DEFAULT_ACTION_NONE, + purple_connection_get_account(gc), entity, NULL, verify, 3, + _("Yes"), G_CALLBACK(silcpurple_verify_cb), + _("No"), G_CALLBACK(silcpurple_verify_cb), + _("_View..."), G_CALLBACK(silcpurple_verify_details)); +} + +void silcpurple_verify_public_key(SilcClient client, SilcClientConnection conn, + const char *name, SilcSocketType conn_type, + unsigned char *pk, SilcUInt32 pk_len, + SilcSKEPKType pk_type, + SilcVerifyPublicKey completion, void *context) +{ + PurpleConnection *gc = client->application; + int i; + char file[256], filename[256], filename2[256], *ipf, *hostf = NULL; + char *fingerprint, *babbleprint; + struct passwd *pw; + struct stat st; + char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER || + conn_type == SILC_SOCKET_TYPE_ROUTER) ? + "server" : "client"); + PublicKeyVerify verify; + + if (pk_type != SILC_SKE_PK_TYPE_SILC) { + purple_notify_error(gc, _("Verify Public Key"), + _("Unsupported public key type"), NULL); + if (completion) + completion(FALSE, context); + return; + } + + pw = getpwuid(getuid()); + if (!pw) { + if (completion) + completion(FALSE, context); + return; + } + + memset(filename, 0, sizeof(filename)); + memset(filename2, 0, sizeof(filename2)); + memset(file, 0, sizeof(file)); + + if (conn_type == SILC_SOCKET_TYPE_SERVER || + conn_type == SILC_SOCKET_TYPE_ROUTER) { + if (!name) { + g_snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity, + conn->sock->ip, conn->sock->port); + g_snprintf(filename, sizeof(filename) - 1, + "%s" G_DIR_SEPARATOR_S "%skeys" G_DIR_SEPARATOR_S "%s", + silcpurple_silcdir(), entity, file); + + g_snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity, + conn->sock->hostname, conn->sock->port); + g_snprintf(filename2, sizeof(filename2) - 1, + "%s" G_DIR_SEPARATOR_S "%skeys" G_DIR_SEPARATOR_S "%s", + silcpurple_silcdir(), entity, file); + + ipf = filename; + hostf = filename2; + } else { + g_snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity, + name, conn->sock->port); + g_snprintf(filename, sizeof(filename) - 1, + "%s" G_DIR_SEPARATOR_S "%skeys" G_DIR_SEPARATOR_S "%s", + silcpurple_silcdir(), entity, file); + + ipf = filename; + } + } else { + /* Replace all whitespaces with `_'. */ + fingerprint = silc_hash_fingerprint(NULL, pk, pk_len); + for (i = 0; i < strlen(fingerprint); i++) + if (fingerprint[i] == ' ') + fingerprint[i] = '_'; + + g_snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint); + g_snprintf(filename, sizeof(filename) - 1, + "%s" G_DIR_SEPARATOR_S "%skeys" G_DIR_SEPARATOR_S "%s", + silcpurple_silcdir(), entity, file); + silc_free(fingerprint); + + ipf = filename; + } + + verify = silc_calloc(1, sizeof(*verify)); + if (!verify) + return; + verify->client = client; + verify->conn = conn; + verify->filename = strdup(ipf); + verify->entity = strdup(entity); + verify->entity_name = (conn_type != SILC_SOCKET_TYPE_CLIENT ? + (name ? strdup(name) : strdup(conn->sock->hostname)) + : NULL); + verify->pk = silc_memdup(pk, pk_len); + verify->pk_len = pk_len; + verify->pk_type = pk_type; + verify->completion = completion; + verify->context = context; + fingerprint = verify->fingerprint = silc_hash_fingerprint(NULL, pk, pk_len); + babbleprint = verify->babbleprint = silc_hash_babbleprint(NULL, pk, pk_len); + + /* Check whether this key already exists */ + if (g_stat(ipf, &st) < 0 && (!hostf || g_stat(hostf, &st) < 0)) { + /* Key does not exist, ask user to verify the key and save it */ + silcpurple_verify_ask(name ? name : entity, + fingerprint, babbleprint, verify); + return; + } else { + /* The key already exists, verify it. */ + SilcPublicKey public_key; + unsigned char *encpk; + SilcUInt32 encpk_len; + + /* Load the key file, try for both IP filename and hostname filename */ + if (!silc_pkcs_load_public_key(ipf, &public_key, + SILC_PKCS_FILE_PEM) && + !silc_pkcs_load_public_key(ipf, &public_key, + SILC_PKCS_FILE_BIN) && + (!hostf || (!silc_pkcs_load_public_key(hostf, &public_key, + SILC_PKCS_FILE_PEM) && + !silc_pkcs_load_public_key(hostf, &public_key, + SILC_PKCS_FILE_BIN)))) { + silcpurple_verify_ask(name ? name : entity, + fingerprint, babbleprint, verify); + return; + } + + /* Encode the key data */ + encpk = silc_pkcs_public_key_encode(public_key, &encpk_len); + if (!encpk) { + silcpurple_verify_ask(name ? name : entity, + fingerprint, babbleprint, verify); + return; + } + + /* Compare the keys */ + if (memcmp(encpk, pk, encpk_len)) { + /* Ask user to verify the key and save it */ + verify->changed = TRUE; + silcpurple_verify_ask(name ? name : entity, + fingerprint, babbleprint, verify); + return; + } + + /* Local copy matched */ + if (completion) + completion(TRUE, context); + silc_free(verify->filename); + silc_free(verify->entity); + silc_free(verify->entity_name); + silc_free(verify->pk); + silc_free(verify->fingerprint); + silc_free(verify->babbleprint); + silc_free(verify); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/silc10/silc.c Mon Jun 18 01:48:35 2007 +0000 @@ -0,0 +1,1914 @@ +/* + + silcpurple.c + + Author: Pekka Riikonen <priikone@silcnet.org> + + Copyright (C) 2004 - 2005 Pekka Riikonen + + 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; version 2 of the License. + + 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. + +*/ + +#include "silcincludes.h" +#include "silcclient.h" +#include "silcpurple.h" +#include "version.h" +#include "wb.h" + +extern SilcClientOperations ops; +static PurplePlugin *silc_plugin = NULL; + +static const char * +silcpurple_list_icon(PurpleAccount *a, PurpleBuddy *b) +{ + return (const char *)"silc"; +} + +static GList * +silcpurple_away_states(PurpleAccount *account) +{ + PurpleStatusType *type; + GList *types = NULL; + + type = purple_status_type_new_full(PURPLE_STATUS_AVAILABLE, SILCPURPLE_STATUS_ID_AVAILABLE, NULL, FALSE, TRUE, FALSE); + types = g_list_append(types, type); + type = purple_status_type_new_full(PURPLE_STATUS_AVAILABLE, SILCPURPLE_STATUS_ID_HYPER, _("Hyper Active"), FALSE, TRUE, FALSE); + types = g_list_append(types, type); + type = purple_status_type_new_full(PURPLE_STATUS_AWAY, SILCPURPLE_STATUS_ID_AWAY, NULL, FALSE, TRUE, FALSE); + types = g_list_append(types, type); + type = purple_status_type_new_full(PURPLE_STATUS_UNAVAILABLE, SILCPURPLE_STATUS_ID_BUSY, _("Busy"), FALSE, TRUE, FALSE); + types = g_list_append(types, type); + type = purple_status_type_new_full(PURPLE_STATUS_AWAY, SILCPURPLE_STATUS_ID_INDISPOSED, _("Indisposed"), FALSE, TRUE, FALSE); + types = g_list_append(types, type); + type = purple_status_type_new_full(PURPLE_STATUS_AWAY, SILCPURPLE_STATUS_ID_PAGE, _("Wake Me Up"), FALSE, TRUE, FALSE); + types = g_list_append(types, type); + type = purple_status_type_new_full(PURPLE_STATUS_OFFLINE, SILCPURPLE_STATUS_ID_OFFLINE, NULL, FALSE, TRUE, FALSE); + types = g_list_append(types, type); + + return types; +} + +static void +silcpurple_set_status(PurpleAccount *account, PurpleStatus *status) +{ + PurpleConnection *gc = purple_account_get_connection(account); + SilcPurple sg = NULL; + SilcUInt32 mode; + SilcBuffer idp; + unsigned char mb[4]; + const char *state; + + if (gc != NULL) + sg = gc->proto_data; + + if (status == NULL) + return; + + state = purple_status_get_id(status); + + if (state == NULL) + return; + + if ((sg == NULL) || (sg->conn == NULL)) + return; + + mode = sg->conn->local_entry->mode; + mode &= ~(SILC_UMODE_GONE | + SILC_UMODE_HYPER | + SILC_UMODE_BUSY | + SILC_UMODE_INDISPOSED | + SILC_UMODE_PAGE); + + if (!strcmp(state, "hyper")) + mode |= SILC_UMODE_HYPER; + else if (!strcmp(state, "away")) + mode |= SILC_UMODE_GONE; + else if (!strcmp(state, "busy")) + mode |= SILC_UMODE_BUSY; + else if (!strcmp(state, "indisposed")) + mode |= SILC_UMODE_INDISPOSED; + else if (!strcmp(state, "page")) + mode |= SILC_UMODE_PAGE; + + /* Send UMODE */ + idp = silc_id_payload_encode(sg->conn->local_id, SILC_ID_CLIENT); + SILC_PUT32_MSB(mode, mb); + silc_client_command_send(sg->client, sg->conn, SILC_COMMAND_UMODE, + ++sg->conn->cmd_ident, 2, + 1, idp->data, idp->len, + 2, mb, sizeof(mb)); + silc_buffer_free(idp); +} + + +/*************************** Connection Routines *****************************/ + +static void +silcpurple_keepalive(PurpleConnection *gc) +{ + SilcPurple sg = gc->proto_data; + silc_client_send_packet(sg->client, sg->conn, SILC_PACKET_HEARTBEAT, + NULL, 0); +} + +static gboolean +silcpurple_scheduler(gpointer *context) +{ + SilcPurple sg = (SilcPurple)context; + silc_client_run_one(sg->client); + return TRUE; +} + +static void +silcpurple_nickname_parse(const char *nickname, + char **ret_nickname) +{ + silc_parse_userfqdn(nickname, ret_nickname, NULL); +} + +static void +silcpurple_login_connected(gpointer data, gint source, const gchar *error_message) +{ + PurpleConnection *gc = data; + SilcPurple sg; + SilcClient client; + SilcClientConnection conn; + PurpleAccount *account; + SilcClientConnectionParams params; + SilcUInt32 mask; + const char *dfile, *tmp; +#ifdef SILC_ATTRIBUTE_USER_ICON + PurpleStoredImage *img; +#endif +#ifdef HAVE_SYS_UTSNAME_H + struct utsname u; +#endif + + + g_return_if_fail(gc != NULL); + + sg = gc->proto_data; + + if (source < 0) { + purple_connection_error(gc, _("Connection failed")); + return; + } + + client = sg->client; + account = sg->account; + + /* Get session detachment data, if available */ + memset(¶ms, 0, sizeof(params)); + dfile = silcpurple_session_file(purple_account_get_username(sg->account)); + params.detach_data = (unsigned char *)silc_file_readfile(dfile, ¶ms.detach_data_len); + if (params.detach_data) + params.detach_data[params.detach_data_len] = 0; + + /* Add connection to SILC client library */ + conn = silc_client_add_connection( + sg->client, ¶ms, + (char *)purple_account_get_string(account, "server", + "silc.silcnet.org"), + purple_account_get_int(account, "port", 706), sg); + if (!conn) { + purple_connection_error(gc, _("Cannot initialize SILC Client connection")); + gc->proto_data = NULL; + return; + } + sg->conn = conn; + + /* Progress */ + if (params.detach_data) { + purple_connection_update_progress(gc, _("Resuming session"), 2, 5); + sg->resuming = TRUE; + } else { + purple_connection_update_progress(gc, _("Performing key exchange"), 2, 5); + } + + /* Perform SILC Key Exchange. The "silc_connected" will be called + eventually. */ + silc_client_start_key_exchange(sg->client, sg->conn, source); + + /* Set default attributes */ + mask = SILC_ATTRIBUTE_MOOD_NORMAL; + silc_client_attribute_add(client, conn, + SILC_ATTRIBUTE_STATUS_MOOD, + SILC_32_TO_PTR(mask), + sizeof(SilcUInt32)); + mask = SILC_ATTRIBUTE_CONTACT_CHAT; + silc_client_attribute_add(client, conn, + SILC_ATTRIBUTE_PREFERRED_CONTACT, + SILC_32_TO_PTR(mask), + sizeof(SilcUInt32)); +#ifdef HAVE_SYS_UTSNAME_H + if (!uname(&u)) { + SilcAttributeObjDevice dev; + memset(&dev, 0, sizeof(dev)); + dev.type = SILC_ATTRIBUTE_DEVICE_COMPUTER; + dev.version = u.release; + dev.model = u.sysname; + silc_client_attribute_add(client, conn, + SILC_ATTRIBUTE_DEVICE_INFO, + (void *)&dev, sizeof(dev)); + } +#endif +#ifdef _WIN32 + tmp = _tzname[0]; +#else + tmp = tzname[0]; +#endif + silc_client_attribute_add(client, conn, + SILC_ATTRIBUTE_TIMEZONE, + (void *)tmp, strlen(tmp)); + +#ifdef SILC_ATTRIBUTE_USER_ICON + /* Set our buddy icon */ + img = purple_buddy_icons_find_account_icon(account); + silcpurple_buddy_set_icon(gc, img); + purple_imgstore_unref(img); +#endif + + silc_free(params.detach_data); +} + +static void +silcpurple_login(PurpleAccount *account) +{ + SilcPurple sg; + SilcClient client; + SilcClientParams params; + PurpleConnection *gc; + char pkd[256], prd[256]; + const char *cipher, *hmac; + char *realname; + int i; + + gc = account->gc; + if (!gc) + return; + gc->proto_data = NULL; + + memset(¶ms, 0, sizeof(params)); + strcat(params.nickname_format, "%n@%h%a"); + params.nickname_parse = silcpurple_nickname_parse; + params.ignore_requested_attributes = FALSE; + + /* Allocate SILC client */ + client = silc_client_alloc(&ops, ¶ms, gc, NULL); + if (!client) { + purple_connection_error(gc, _("Out of memory")); + return; + } + + /* Get username, real name and local hostname for SILC library */ + if (purple_account_get_username(account)) { + const char *u = purple_account_get_username(account); + char **up = g_strsplit(u, "@", 2); + client->username = strdup(up[0]); + g_strfreev(up); + } else { + client->username = silc_get_username(); + purple_account_set_username(account, client->username); + } + realname = silc_get_real_name(); + if (purple_account_get_user_info(account)) { + client->realname = strdup(purple_account_get_user_info(account)); + free(realname); + } else if ((silc_get_real_name() != NULL) && (*realname != '\0')) { + client->realname = realname; + purple_account_set_user_info(account, client->realname); + } else { + free(realname); + client->realname = strdup(_("John Noname")); + } + client->hostname = silc_net_localhost(); + + purple_connection_set_display_name(gc, client->username); + + /* Register requested cipher and HMAC */ + cipher = purple_account_get_string(account, "cipher", SILC_DEFAULT_CIPHER); + for (i = 0; silc_default_ciphers[i].name; i++) + if (!strcmp(silc_default_ciphers[i].name, cipher)) { + silc_cipher_register(&(silc_default_ciphers[i])); + break; + } + hmac = purple_account_get_string(account, "hmac", SILC_DEFAULT_HMAC); + for (i = 0; silc_default_hmacs[i].name; i++) + if (!strcmp(silc_default_hmacs[i].name, hmac)) { + silc_hmac_register(&(silc_default_hmacs[i])); + break; + } + + /* Init SILC client */ + if (!silc_client_init(client)) { + gc->wants_to_die = TRUE; + purple_connection_error(gc, _("Cannot initialize SILC protocol")); + return; + } + + /* Check the ~/.silc dir and create it, and new key pair if necessary. */ + if (!silcpurple_check_silc_dir(gc)) { + gc->wants_to_die = TRUE; + purple_connection_error(gc, _("Cannot find/access ~/.silc directory")); + return; + } + + /* Progress */ + purple_connection_update_progress(gc, _("Connecting to SILC Server"), 1, 5); + + /* Load SILC key pair */ + g_snprintf(pkd, sizeof(pkd), "%s" G_DIR_SEPARATOR_S "public_key.pub", silcpurple_silcdir()); + g_snprintf(prd, sizeof(prd), "%s" G_DIR_SEPARATOR_S "private_key.prv", silcpurple_silcdir()); + if (!silc_load_key_pair((char *)purple_account_get_string(account, "public-key", pkd), + (char *)purple_account_get_string(account, "private-key", prd), + (gc->password == NULL) ? "" : gc->password, &client->pkcs, + &client->public_key, &client->private_key)) { + g_snprintf(pkd, sizeof(pkd), _("Could not load SILC key pair: %s"), strerror(errno)); + purple_connection_error(gc, pkd); + return; + } + + sg = silc_calloc(1, sizeof(*sg)); + if (!sg) + return; + memset(sg, 0, sizeof(*sg)); + sg->client = client; + sg->gc = gc; + sg->account = account; + gc->proto_data = sg; + + /* Connect to the SILC server */ + if (purple_proxy_connect(gc, account, + purple_account_get_string(account, "server", + "silc.silcnet.org"), + purple_account_get_int(account, "port", 706), + silcpurple_login_connected, gc) == NULL) + { + purple_connection_error(gc, _("Unable to create connection")); + return; + } + + /* Schedule SILC using Glib's event loop */ + sg->scheduler = purple_timeout_add(300, (GSourceFunc)silcpurple_scheduler, sg); +} + +static int +silcpurple_close_final(gpointer *context) +{ + SilcPurple sg = (SilcPurple)context; + silc_client_stop(sg->client); + silc_client_free(sg->client); +#ifdef HAVE_SILCMIME_H + if (sg->mimeass) + silc_mime_assembler_free(sg->mimeass); +#endif + silc_free(sg); + return 0; +} + +static void +silcpurple_close(PurpleConnection *gc) +{ + SilcPurple sg = gc->proto_data; + + g_return_if_fail(sg != NULL); + + /* Send QUIT */ + silc_client_command_call(sg->client, sg->conn, NULL, + "QUIT", "Download this: " PURPLE_WEBSITE, NULL); + + if (sg->conn) + silc_client_close_connection(sg->client, sg->conn); + + purple_timeout_remove(sg->scheduler); + purple_timeout_add(1, (GSourceFunc)silcpurple_close_final, sg); +} + + +/****************************** Protocol Actions *****************************/ + +static void +silcpurple_attrs_cancel(PurpleConnection *gc, PurpleRequestFields *fields) +{ + /* Nothing */ +} + +static void +silcpurple_attrs_cb(PurpleConnection *gc, PurpleRequestFields *fields) +{ + SilcPurple sg = gc->proto_data; + SilcClient client = sg->client; + SilcClientConnection conn = sg->conn; + PurpleRequestField *f; + char *tmp; + SilcUInt32 tmp_len, mask; + SilcAttributeObjService service; + SilcAttributeObjDevice dev; + SilcVCardStruct vcard; + const char *val; + + sg = gc->proto_data; + if (!sg) + return; + + memset(&service, 0, sizeof(service)); + memset(&dev, 0, sizeof(dev)); + memset(&vcard, 0, sizeof(vcard)); + + silc_client_attribute_del(client, conn, + SILC_ATTRIBUTE_USER_INFO, NULL); + silc_client_attribute_del(client, conn, + SILC_ATTRIBUTE_SERVICE, NULL); + silc_client_attribute_del(client, conn, + SILC_ATTRIBUTE_STATUS_MOOD, NULL); + silc_client_attribute_del(client, conn, + SILC_ATTRIBUTE_STATUS_FREETEXT, NULL); + silc_client_attribute_del(client, conn, + SILC_ATTRIBUTE_STATUS_MESSAGE, NULL); + silc_client_attribute_del(client, conn, + SILC_ATTRIBUTE_PREFERRED_LANGUAGE, NULL); + silc_client_attribute_del(client, conn, + SILC_ATTRIBUTE_PREFERRED_CONTACT, NULL); + silc_client_attribute_del(client, conn, + SILC_ATTRIBUTE_TIMEZONE, NULL); + silc_client_attribute_del(client, conn, + SILC_ATTRIBUTE_GEOLOCATION, NULL); + silc_client_attribute_del(client, conn, + SILC_ATTRIBUTE_DEVICE_INFO, NULL); + + /* Set mood */ + mask = 0; + f = purple_request_fields_get_field(fields, "mood_normal"); + if (f && purple_request_field_bool_get_value(f)) + mask |= SILC_ATTRIBUTE_MOOD_NORMAL; + f = purple_request_fields_get_field(fields, "mood_happy"); + if (f && purple_request_field_bool_get_value(f)) + mask |= SILC_ATTRIBUTE_MOOD_HAPPY; + f = purple_request_fields_get_field(fields, "mood_sad"); + if (f && purple_request_field_bool_get_value(f)) + mask |= SILC_ATTRIBUTE_MOOD_SAD; + f = purple_request_fields_get_field(fields, "mood_angry"); + if (f && purple_request_field_bool_get_value(f)) + mask |= SILC_ATTRIBUTE_MOOD_ANGRY; + f = purple_request_fields_get_field(fields, "mood_jealous"); + if (f && purple_request_field_bool_get_value(f)) + mask |= SILC_ATTRIBUTE_MOOD_JEALOUS; + f = purple_request_fields_get_field(fields, "mood_ashamed"); + if (f && purple_request_field_bool_get_value(f)) + mask |= SILC_ATTRIBUTE_MOOD_ASHAMED; + f = purple_request_fields_get_field(fields, "mood_invincible"); + if (f && purple_request_field_bool_get_value(f)) + mask |= SILC_ATTRIBUTE_MOOD_INVINCIBLE; + f = purple_request_fields_get_field(fields, "mood_inlove"); + if (f && purple_request_field_bool_get_value(f)) + mask |= SILC_ATTRIBUTE_MOOD_INLOVE; + f = purple_request_fields_get_field(fields, "mood_sleepy"); + if (f && purple_request_field_bool_get_value(f)) + mask |= SILC_ATTRIBUTE_MOOD_SLEEPY; + f = purple_request_fields_get_field(fields, "mood_bored"); + if (f && purple_request_field_bool_get_value(f)) + mask |= SILC_ATTRIBUTE_MOOD_BORED; + f = purple_request_fields_get_field(fields, "mood_excited"); + if (f && purple_request_field_bool_get_value(f)) + mask |= SILC_ATTRIBUTE_MOOD_EXCITED; + f = purple_request_fields_get_field(fields, "mood_anxious"); + if (f && purple_request_field_bool_get_value(f)) + mask |= SILC_ATTRIBUTE_MOOD_ANXIOUS; + silc_client_attribute_add(client, conn, + SILC_ATTRIBUTE_STATUS_MOOD, + SILC_32_TO_PTR(mask), + sizeof(SilcUInt32)); + + /* Set preferred contact */ + mask = 0; + f = purple_request_fields_get_field(fields, "contact_chat"); + if (f && purple_request_field_bool_get_value(f)) + mask |= SILC_ATTRIBUTE_CONTACT_CHAT; + f = purple_request_fields_get_field(fields, "contact_email"); + if (f && purple_request_field_bool_get_value(f)) + mask |= SILC_ATTRIBUTE_CONTACT_EMAIL; + f = purple_request_fields_get_field(fields, "contact_call"); + if (f && purple_request_field_bool_get_value(f)) + mask |= SILC_ATTRIBUTE_CONTACT_CALL; + f = purple_request_fields_get_field(fields, "contact_sms"); + if (f && purple_request_field_bool_get_value(f)) + mask |= SILC_ATTRIBUTE_CONTACT_SMS; + f = purple_request_fields_get_field(fields, "contact_mms"); + if (f && purple_request_field_bool_get_value(f)) + mask |= SILC_ATTRIBUTE_CONTACT_MMS; + f = purple_request_fields_get_field(fields, "contact_video"); + if (f && purple_request_field_bool_get_value(f)) + mask |= SILC_ATTRIBUTE_CONTACT_VIDEO; + if (mask) + silc_client_attribute_add(client, conn, + SILC_ATTRIBUTE_PREFERRED_CONTACT, + SILC_32_TO_PTR(mask), + sizeof(SilcUInt32)); + + /* Set status text */ + val = NULL; + f = purple_request_fields_get_field(fields, "status_text"); + if (f) + val = purple_request_field_string_get_value(f); + if (val && *val) + silc_client_attribute_add(client, conn, + SILC_ATTRIBUTE_STATUS_FREETEXT, + (void *)val, strlen(val)); + + /* Set vcard */ + val = NULL; + f = purple_request_fields_get_field(fields, "vcard"); + if (f) + val = purple_request_field_string_get_value(f); + if (val && *val) { + purple_account_set_string(sg->account, "vcard", val); + tmp = silc_file_readfile(val, &tmp_len); + if (tmp) { + tmp[tmp_len] = 0; + if (silc_vcard_decode((unsigned char *)tmp, tmp_len, &vcard)) + silc_client_attribute_add(client, conn, + SILC_ATTRIBUTE_USER_INFO, + (void *)&vcard, + sizeof(vcard)); + } + silc_vcard_free(&vcard); + silc_free(tmp); + } else { + purple_account_set_string(sg->account, "vcard", ""); + } + +#ifdef HAVE_SYS_UTSNAME_H + /* Set device info */ + f = purple_request_fields_get_field(fields, "device"); + if (f && purple_request_field_bool_get_value(f)) { + struct utsname u; + if (!uname(&u)) { + dev.type = SILC_ATTRIBUTE_DEVICE_COMPUTER; + dev.version = u.release; + dev.model = u.sysname; + silc_client_attribute_add(client, conn, + SILC_ATTRIBUTE_DEVICE_INFO, + (void *)&dev, sizeof(dev)); + } + } +#endif + + /* Set timezone */ + val = NULL; + f = purple_request_fields_get_field(fields, "timezone"); + if (f) + val = purple_request_field_string_get_value(f); + if (val && *val) + silc_client_attribute_add(client, conn, + SILC_ATTRIBUTE_TIMEZONE, + (void *)val, strlen(val)); +} + +static void +silcpurple_attrs(PurplePluginAction *action) +{ + PurpleConnection *gc = (PurpleConnection *) action->context; + SilcPurple sg = gc->proto_data; + SilcClient client = sg->client; + SilcClientConnection conn = sg->conn; + PurpleRequestFields *fields; + PurpleRequestFieldGroup *g; + PurpleRequestField *f; + SilcHashTable attrs; + SilcAttributePayload attr; + gboolean mnormal = TRUE, mhappy = FALSE, msad = FALSE, + mangry = FALSE, mjealous = FALSE, mashamed = FALSE, + minvincible = FALSE, minlove = FALSE, msleepy = FALSE, + mbored = FALSE, mexcited = FALSE, manxious = FALSE; + gboolean cemail = FALSE, ccall = FALSE, csms = FALSE, + cmms = FALSE, cchat = TRUE, cvideo = FALSE; + gboolean device = TRUE; + char status[1024]; + + sg = gc->proto_data; + if (!sg) + return; + + memset(status, 0, sizeof(status)); + + attrs = silc_client_attributes_get(client, conn); + if (attrs) { + if (silc_hash_table_find(attrs, + SILC_32_TO_PTR(SILC_ATTRIBUTE_STATUS_MOOD), + NULL, (void *)&attr)) { + SilcUInt32 mood = 0; + silc_attribute_get_object(attr, &mood, sizeof(mood)); + mnormal = !mood; + mhappy = (mood & SILC_ATTRIBUTE_MOOD_HAPPY); + msad = (mood & SILC_ATTRIBUTE_MOOD_SAD); + mangry = (mood & SILC_ATTRIBUTE_MOOD_ANGRY); + mjealous = (mood & SILC_ATTRIBUTE_MOOD_JEALOUS); + mashamed = (mood & SILC_ATTRIBUTE_MOOD_ASHAMED); + minvincible = (mood & SILC_ATTRIBUTE_MOOD_INVINCIBLE); + minlove = (mood & SILC_ATTRIBUTE_MOOD_INLOVE); + msleepy = (mood & SILC_ATTRIBUTE_MOOD_SLEEPY); + mbored = (mood & SILC_ATTRIBUTE_MOOD_BORED); + mexcited = (mood & SILC_ATTRIBUTE_MOOD_EXCITED); + manxious = (mood & SILC_ATTRIBUTE_MOOD_ANXIOUS); + } + + if (silc_hash_table_find(attrs, + SILC_32_TO_PTR(SILC_ATTRIBUTE_PREFERRED_CONTACT), + NULL, (void *)&attr)) { + SilcUInt32 contact = 0; + silc_attribute_get_object(attr, &contact, sizeof(contact)); + cemail = (contact & SILC_ATTRIBUTE_CONTACT_EMAIL); + ccall = (contact & SILC_ATTRIBUTE_CONTACT_CALL); + csms = (contact & SILC_ATTRIBUTE_CONTACT_SMS); + cmms = (contact & SILC_ATTRIBUTE_CONTACT_MMS); + cchat = (contact & SILC_ATTRIBUTE_CONTACT_CHAT); + cvideo = (contact & SILC_ATTRIBUTE_CONTACT_VIDEO); + } + + if (silc_hash_table_find(attrs, + SILC_32_TO_PTR(SILC_ATTRIBUTE_STATUS_FREETEXT), + NULL, (void *)&attr)) + silc_attribute_get_object(attr, &status, sizeof(status)); + + if (!silc_hash_table_find(attrs, + SILC_32_TO_PTR(SILC_ATTRIBUTE_DEVICE_INFO), + NULL, (void *)&attr)) + device = FALSE; + } + + fields = purple_request_fields_new(); + + g = purple_request_field_group_new(NULL); + f = purple_request_field_label_new("l3", _("Your Current Mood")); + purple_request_field_group_add_field(g, f); + f = purple_request_field_bool_new("mood_normal", _("Normal"), mnormal); + purple_request_field_group_add_field(g, f); + f = purple_request_field_bool_new("mood_happy", _("Happy"), mhappy); + purple_request_field_group_add_field(g, f); + f = purple_request_field_bool_new("mood_sad", _("Sad"), msad); + purple_request_field_group_add_field(g, f); + f = purple_request_field_bool_new("mood_angry", _("Angry"), mangry); + purple_request_field_group_add_field(g, f); + f = purple_request_field_bool_new("mood_jealous", _("Jealous"), mjealous); + purple_request_field_group_add_field(g, f); + f = purple_request_field_bool_new("mood_ashamed", _("Ashamed"), mashamed); + purple_request_field_group_add_field(g, f); + f = purple_request_field_bool_new("mood_invincible", _("Invincible"), minvincible); + purple_request_field_group_add_field(g, f); + f = purple_request_field_bool_new("mood_inlove", _("In love"), minlove); + purple_request_field_group_add_field(g, f); + f = purple_request_field_bool_new("mood_sleepy", _("Sleepy"), msleepy); + purple_request_field_group_add_field(g, f); + f = purple_request_field_bool_new("mood_bored", _("Bored"), mbored); + purple_request_field_group_add_field(g, f); + f = purple_request_field_bool_new("mood_excited", _("Excited"), mexcited); + purple_request_field_group_add_field(g, f); + f = purple_request_field_bool_new("mood_anxious", _("Anxious"), manxious); + purple_request_field_group_add_field(g, f); + + f = purple_request_field_label_new("l4", _("\nYour Preferred Contact Methods")); + purple_request_field_group_add_field(g, f); + f = purple_request_field_bool_new("contact_chat", _("Chat"), cchat); + purple_request_field_group_add_field(g, f); + f = purple_request_field_bool_new("contact_email", _("E-mail"), cemail); + purple_request_field_group_add_field(g, f); + f = purple_request_field_bool_new("contact_call", _("Phone"), ccall); + purple_request_field_group_add_field(g, f); + f = purple_request_field_bool_new("contact_sms", _("SMS"), csms); + purple_request_field_group_add_field(g, f); + f = purple_request_field_bool_new("contact_mms", _("MMS"), cmms); + purple_request_field_group_add_field(g, f); + f = purple_request_field_bool_new("contact_video", _("Video conferencing"), cvideo); + purple_request_field_group_add_field(g, f); + purple_request_fields_add_group(fields, g); + + g = purple_request_field_group_new(NULL); + f = purple_request_field_string_new("status_text", _("Your Current Status"), + status[0] ? status : NULL, TRUE); + purple_request_field_group_add_field(g, f); + purple_request_fields_add_group(fields, g); + + g = purple_request_field_group_new(NULL); +#if 0 + f = purple_request_field_label_new("l2", _("Online Services")); + purple_request_field_group_add_field(g, f); + f = purple_request_field_bool_new("services", + _("Let others see what services you are using"), + TRUE); + purple_request_field_group_add_field(g, f); +#endif +#ifdef HAVE_SYS_UTSNAME_H + f = purple_request_field_bool_new("device", + _("Let others see what computer you are using"), + device); + purple_request_field_group_add_field(g, f); +#endif + purple_request_fields_add_group(fields, g); + + g = purple_request_field_group_new(NULL); + f = purple_request_field_string_new("vcard", _("Your VCard File"), + purple_account_get_string(sg->account, "vcard", ""), + FALSE); + purple_request_field_group_add_field(g, f); +#ifdef _WIN32 + f = purple_request_field_string_new("timezone", _("Timezone"), _tzname[0], FALSE); +#else + f = purple_request_field_string_new("timezone", _("Timezone"), tzname[0], FALSE); +#endif + purple_request_field_group_add_field(g, f); + purple_request_fields_add_group(fields, g); + + purple_request_fields(gc, _("User Online Status Attributes"), + _("User Online Status Attributes"), + _("You can let other users see your online status information " + "and your personal information. Please fill the information " + "you would like other users to see about yourself."), + fields, + _("OK"), G_CALLBACK(silcpurple_attrs_cb), + _("Cancel"), G_CALLBACK(silcpurple_attrs_cancel), + gc->account, NULL, NULL, gc); +} + +static void +silcpurple_detach(PurplePluginAction *action) +{ + PurpleConnection *gc = (PurpleConnection *) action->context; + SilcPurple sg; + + if (!gc) + return; + sg = gc->proto_data; + if (!sg) + return; + + /* Call DETACH */ + silc_client_command_call(sg->client, sg->conn, "DETACH"); + sg->detaching = TRUE; +} + +static void +silcpurple_view_motd(PurplePluginAction *action) +{ + PurpleConnection *gc = (PurpleConnection *) action->context; + SilcPurple sg; + char *tmp; + + if (!gc) + return; + sg = gc->proto_data; + if (!sg) + return; + + if (!sg->motd) { + purple_notify_error( + gc, _("Message of the Day"), _("No Message of the Day available"), + _("There is no Message of the Day associated with this connection")); + return; + } + + tmp = g_markup_escape_text(sg->motd, -1); + purple_notify_formatted(gc, NULL, _("Message of the Day"), NULL, + tmp, NULL, NULL); + g_free(tmp); +} + +static void +silcpurple_create_keypair_cancel(PurpleConnection *gc, PurpleRequestFields *fields) +{ + /* Nothing */ +} + +static void +silcpurple_create_keypair_cb(PurpleConnection *gc, PurpleRequestFields *fields) +{ + SilcPurple sg = gc->proto_data; + PurpleRequestField *f; + const char *val, *pkfile = NULL, *prfile = NULL; + const char *pass1 = NULL, *pass2 = NULL, *un = NULL, *hn = NULL; + const char *rn = NULL, *e = NULL, *o = NULL, *c = NULL; + char *identifier; + int keylen = SILCPURPLE_DEF_PKCS_LEN; + SilcPublicKey public_key; + + sg = gc->proto_data; + if (!sg) + return; + + val = NULL; + f = purple_request_fields_get_field(fields, "pass1"); + if (f) + val = purple_request_field_string_get_value(f); + if (val && *val) + pass1 = val; + else + pass1 = ""; + val = NULL; + f = purple_request_fields_get_field(fields, "pass2"); + if (f) + val = purple_request_field_string_get_value(f); + if (val && *val) + pass2 = val; + else + pass2 = ""; + + if (strcmp(pass1, pass2)) { + purple_notify_error( + gc, _("Create New SILC Key Pair"), _("Passphrases do not match"), NULL); + return; + } + + val = NULL; + f = purple_request_fields_get_field(fields, "key"); + if (f) + val = purple_request_field_string_get_value(f); + if (val && *val) + keylen = atoi(val); + f = purple_request_fields_get_field(fields, "pkfile"); + if (f) + pkfile = purple_request_field_string_get_value(f); + f = purple_request_fields_get_field(fields, "prfile"); + if (f) + prfile = purple_request_field_string_get_value(f); + + f = purple_request_fields_get_field(fields, "un"); + if (f) + un = purple_request_field_string_get_value(f); + f = purple_request_fields_get_field(fields, "hn"); + if (f) + hn = purple_request_field_string_get_value(f); + f = purple_request_fields_get_field(fields, "rn"); + if (f) + rn = purple_request_field_string_get_value(f); + f = purple_request_fields_get_field(fields, "e"); + if (f) + e = purple_request_field_string_get_value(f); + f = purple_request_fields_get_field(fields, "o"); + if (f) + o = purple_request_field_string_get_value(f); + f = purple_request_fields_get_field(fields, "c"); + if (f) + c = purple_request_field_string_get_value(f); + + identifier = silc_pkcs_encode_identifier((char *)un, (char *)hn, + (char *)rn, (char *)e, (char *)o, (char *)c); + + /* Create the key pair */ + if (!silc_create_key_pair(SILCPURPLE_DEF_PKCS, keylen, pkfile, prfile, + identifier, pass1, NULL, &public_key, NULL, + FALSE)) { + purple_notify_error( + gc, _("Create New SILC Key Pair"), _("Key Pair Generation failed"), NULL); + return; + } + + silcpurple_show_public_key(sg, NULL, public_key, NULL, NULL); + + silc_pkcs_public_key_free(public_key); + silc_free(identifier); +} + +static void +silcpurple_create_keypair(PurplePluginAction *action) +{ + PurpleConnection *gc = (PurpleConnection *) action->context; + SilcPurple sg = gc->proto_data; + PurpleRequestFields *fields; + PurpleRequestFieldGroup *g; + PurpleRequestField *f; + const char *username, *realname; + char *hostname, **u; + char tmp[256], pkd[256], pkd2[256], prd[256], prd2[256]; + + username = purple_account_get_username(sg->account); + u = g_strsplit(username, "@", 2); + username = u[0]; + realname = purple_account_get_user_info(sg->account); + hostname = silc_net_localhost(); + g_snprintf(tmp, sizeof(tmp), "%s@%s", username, hostname); + + g_snprintf(pkd2, sizeof(pkd2), "%s" G_DIR_SEPARATOR_S"public_key.pub", silcpurple_silcdir()); + g_snprintf(prd2, sizeof(prd2), "%s" G_DIR_SEPARATOR_S"private_key.prv", silcpurple_silcdir()); + g_snprintf(pkd, sizeof(pkd) - 1, "%s", + purple_account_get_string(gc->account, "public-key", pkd2)); + g_snprintf(prd, sizeof(prd) - 1, "%s", + purple_account_get_string(gc->account, "private-key", prd2)); + + fields = purple_request_fields_new(); + + g = purple_request_field_group_new(NULL); + f = purple_request_field_string_new("key", _("Key length"), "2048", FALSE); + purple_request_field_group_add_field(g, f); + f = purple_request_field_string_new("pkfile", _("Public key file"), pkd, FALSE); + purple_request_field_group_add_field(g, f); + f = purple_request_field_string_new("prfile", _("Private key file"), prd, FALSE); + purple_request_field_group_add_field(g, f); + purple_request_fields_add_group(fields, g); + + g = purple_request_field_group_new(NULL); + f = purple_request_field_string_new("un", _("Username"), username ? username : "", FALSE); + purple_request_field_group_add_field(g, f); + f = purple_request_field_string_new("hn", _("Hostname"), hostname ? hostname : "", FALSE); + purple_request_field_group_add_field(g, f); + f = purple_request_field_string_new("rn", _("Real name"), realname ? realname : "", FALSE); + purple_request_field_group_add_field(g, f); + f = purple_request_field_string_new("e", _("E-mail"), tmp, FALSE); + purple_request_field_group_add_field(g, f); + f = purple_request_field_string_new("o", _("Organization"), "", FALSE); + purple_request_field_group_add_field(g, f); + f = purple_request_field_string_new("c", _("Country"), "", FALSE); + purple_request_field_group_add_field(g, f); + purple_request_fields_add_group(fields, g); + + g = purple_request_field_group_new(NULL); + f = purple_request_field_string_new("pass1", _("Passphrase"), "", FALSE); + purple_request_field_string_set_masked(f, TRUE); + purple_request_field_group_add_field(g, f); + f = purple_request_field_string_new("pass2", _("Passphrase (retype)"), "", FALSE); + purple_request_field_string_set_masked(f, TRUE); + purple_request_field_group_add_field(g, f); + purple_request_fields_add_group(fields, g); + + purple_request_fields(gc, _("Create New SILC Key Pair"), + _("Create New SILC Key Pair"), NULL, fields, + _("Generate Key Pair"), G_CALLBACK(silcpurple_create_keypair_cb), + _("Cancel"), G_CALLBACK(silcpurple_create_keypair_cancel), + gc->account, NULL, NULL, gc); + + g_strfreev(u); + silc_free(hostname); +} + +static void +silcpurple_change_pass(PurplePluginAction *action) +{ + PurpleConnection *gc = (PurpleConnection *) action->context; + purple_account_request_change_password(purple_connection_get_account(gc)); +} + +static void +silcpurple_change_passwd(PurpleConnection *gc, const char *old, const char *new) +{ + char prd[256]; + g_snprintf(prd, sizeof(prd), "%s" G_DIR_SEPARATOR_S "private_key.pub", silcpurple_silcdir()); + silc_change_private_key_passphrase(purple_account_get_string(gc->account, + "private-key", + prd), old, new); +} + +static void +silcpurple_show_set_info(PurplePluginAction *action) +{ + PurpleConnection *gc = (PurpleConnection *) action->context; + purple_account_request_change_user_info(purple_connection_get_account(gc)); +} + +static void +silcpurple_set_info(PurpleConnection *gc, const char *text) +{ +} + +static GList * +silcpurple_actions(PurplePlugin *plugin, gpointer context) +{ + GList *list = NULL; + PurplePluginAction *act; + + act = purple_plugin_action_new(_("Online Status"), + silcpurple_attrs); + list = g_list_append(list, act); + + act = purple_plugin_action_new(_("Detach From Server"), + silcpurple_detach); + list = g_list_append(list, act); + + act = purple_plugin_action_new(_("View Message of the Day"), + silcpurple_view_motd); + list = g_list_append(list, act); + + act = purple_plugin_action_new(_("Create SILC Key Pair..."), + silcpurple_create_keypair); + list = g_list_append(list, act); + + act = purple_plugin_action_new(_("Change Password..."), + silcpurple_change_pass); + list = g_list_append(list, act); + + act = purple_plugin_action_new(_("Set User Info..."), + silcpurple_show_set_info); + list = g_list_append(list, act); + + return list; +} + + +/******************************* IM Routines *********************************/ + +typedef struct { + char *nick; + char *message; + SilcUInt32 message_len; + SilcMessageFlags flags; + PurpleMessageFlags gflags; +} *SilcPurpleIM; + +static void +silcpurple_send_im_resolved(SilcClient client, + SilcClientConnection conn, + SilcClientEntry *clients, + SilcUInt32 clients_count, + void *context) +{ + PurpleConnection *gc = client->application; + SilcPurple sg = gc->proto_data; + SilcPurpleIM im = context; + PurpleConversation *convo; + char tmp[256], *nickname = NULL; + SilcClientEntry client_entry; +#ifdef HAVE_SILCMIME_H + SilcDList list; +#endif + + convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, im->nick, + sg->account); + if (!convo) + return; + + if (!clients) + goto err; + + if (clients_count > 1) { + silc_parse_userfqdn(im->nick, &nickname, NULL); + + /* Find the correct one. The im->nick might be a formatted nick + so this will find the correct one. */ + clients = silc_client_get_clients_local(client, conn, + nickname, im->nick, + &clients_count); + if (!clients) + goto err; + client_entry = clients[0]; + silc_free(clients); + } else { + client_entry = clients[0]; + } + +#ifdef HAVE_SILCMIME_H + /* Check for images */ + if (im->gflags & PURPLE_MESSAGE_IMAGES) { + list = silcpurple_image_message(im->message, (SilcUInt32 *)&im->flags); + if (list) { + /* Send one or more MIME message. If more than one, they + are MIME fragments due to over large message */ + SilcBuffer buf; + + silc_dlist_start(list); + while ((buf = silc_dlist_get(list)) != SILC_LIST_END) + silc_client_send_private_message(client, conn, + client_entry, im->flags, + buf->data, buf->len, + TRUE); + silc_mime_partial_free(list); + purple_conv_im_write(PURPLE_CONV_IM(convo), conn->local_entry->nickname, + im->message, 0, time(NULL)); + goto out; + } + } +#endif + + /* Send the message */ + silc_client_send_private_message(client, conn, client_entry, im->flags, + (unsigned char *)im->message, im->message_len, TRUE); + purple_conv_im_write(PURPLE_CONV_IM(convo), conn->local_entry->nickname, + im->message, 0, time(NULL)); + goto out; + + err: + g_snprintf(tmp, sizeof(tmp), + _("User <I>%s</I> is not present in the network"), im->nick); + purple_conversation_write(convo, NULL, tmp, PURPLE_MESSAGE_SYSTEM, time(NULL)); + + out: + g_free(im->nick); + g_free(im->message); + silc_free(im); + silc_free(nickname); +} + +static int +silcpurple_send_im(PurpleConnection *gc, const char *who, const char *message, + PurpleMessageFlags flags) +{ + SilcPurple sg = gc->proto_data; + SilcClient client = sg->client; + SilcClientConnection conn = sg->conn; + SilcClientEntry *clients; + SilcUInt32 clients_count, mflags; + char *nickname, *msg, *tmp; + int ret = 0; + gboolean sign = purple_account_get_bool(sg->account, "sign-verify", FALSE); +#ifdef HAVE_SILCMIME_H + SilcDList list; +#endif + + if (!who || !message) + return 0; + + mflags = SILC_MESSAGE_FLAG_UTF8; + + tmp = msg = purple_unescape_html(message); + + if (!g_ascii_strncasecmp(msg, "/me ", 4)) { + msg += 4; + if (!*msg) { + g_free(tmp); + return 0; + } + mflags |= SILC_MESSAGE_FLAG_ACTION; + } else if (strlen(msg) > 1 && msg[0] == '/') { + if (!silc_client_command_call(client, conn, msg + 1)) + purple_notify_error(gc, _("Call Command"), _("Cannot call command"), + _("Unknown command")); + g_free(tmp); + return 0; + } + + + if (!silc_parse_userfqdn(who, &nickname, NULL)) { + g_free(tmp); + return 0; + } + + if (sign) + mflags |= SILC_MESSAGE_FLAG_SIGNED; + + /* Find client entry */ + clients = silc_client_get_clients_local(client, conn, nickname, who, + &clients_count); + if (!clients) { + /* Resolve unknown user */ + SilcPurpleIM im = silc_calloc(1, sizeof(*im)); + if (!im) { + g_free(tmp); + return 0; + } + im->nick = g_strdup(who); + im->message = g_strdup(message); + im->message_len = strlen(im->message); + im->flags = mflags; + im->gflags = flags; + silc_client_get_clients(client, conn, nickname, NULL, + silcpurple_send_im_resolved, im); + silc_free(nickname); + g_free(tmp); + return 0; + } + +#ifdef HAVE_SILCMIME_H + /* Check for images */ + if (flags & PURPLE_MESSAGE_IMAGES) { + list = silcpurple_image_message(message, &mflags); + if (list) { + /* Send one or more MIME message. If more than one, they + are MIME fragments due to over large message */ + SilcBuffer buf; + + silc_dlist_start(list); + while ((buf = silc_dlist_get(list)) != SILC_LIST_END) + ret = + silc_client_send_private_message(client, conn, + clients[0], mflags, + buf->data, buf->len, + TRUE); + silc_mime_partial_free(list); + g_free(tmp); + silc_free(nickname); + silc_free(clients); + return ret; + } + } +#endif + + /* Send private message directly */ + ret = silc_client_send_private_message(client, conn, clients[0], + mflags, + (unsigned char *)msg, + strlen(msg), TRUE); + + g_free(tmp); + silc_free(nickname); + silc_free(clients); + return ret; +} + + +static GList *silcpurple_blist_node_menu(PurpleBlistNode *node) { + /* split this single menu building function back into the two + original: one for buddies and one for chats */ + + if(PURPLE_BLIST_NODE_IS_CHAT(node)) { + return silcpurple_chat_menu((PurpleChat *) node); + } else if(PURPLE_BLIST_NODE_IS_BUDDY(node)) { + return silcpurple_buddy_menu((PurpleBuddy *) node); + } else { + g_return_val_if_reached(NULL); + } +} + +/********************************* Commands **********************************/ + +static PurpleCmdRet silcpurple_cmd_chat_part(PurpleConversation *conv, + const char *cmd, char **args, char **error, void *data) +{ + PurpleConnection *gc; + PurpleConversation *convo = conv; + int id = 0; + + gc = purple_conversation_get_gc(conv); + + if (gc == NULL) + return PURPLE_CMD_RET_FAILED; + + if(args && args[0]) + convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, args[0], + gc->account); + + if (convo != NULL) + id = purple_conv_chat_get_id(PURPLE_CONV_CHAT(convo)); + + if (id == 0) + return PURPLE_CMD_RET_FAILED; + + silcpurple_chat_leave(gc, id); + + return PURPLE_CMD_RET_OK; + +} + +static PurpleCmdRet silcpurple_cmd_chat_topic(PurpleConversation *conv, + const char *cmd, char **args, char **error, void *data) +{ + PurpleConnection *gc; + int id = 0; + char *buf, *tmp, *tmp2; + const char *topic; + + gc = purple_conversation_get_gc(conv); + id = purple_conv_chat_get_id(PURPLE_CONV_CHAT(conv)); + + if (gc == NULL || id == 0) + return PURPLE_CMD_RET_FAILED; + + if (!args || !args[0]) { + topic = purple_conv_chat_get_topic (PURPLE_CONV_CHAT(conv)); + if (topic) { + tmp = g_markup_escape_text(topic, -1); + tmp2 = purple_markup_linkify(tmp); + buf = g_strdup_printf(_("current topic is: %s"), tmp2); + g_free(tmp); + g_free(tmp2); + } else + buf = g_strdup(_("No topic is set")); + purple_conv_chat_write(PURPLE_CONV_CHAT(conv), gc->account->username, buf, + PURPLE_MESSAGE_SYSTEM|PURPLE_MESSAGE_NO_LOG, time(NULL)); + g_free(buf); + + } + + if (args && args[0] && (strlen(args[0]) > 255)) { + *error = g_strdup(_("Topic too long")); + return PURPLE_CMD_RET_FAILED; + } + + silcpurple_chat_set_topic(gc, id, args ? args[0] : NULL); + + return PURPLE_CMD_RET_OK; +} + +static PurpleCmdRet silcpurple_cmd_chat_join(PurpleConversation *conv, + const char *cmd, char **args, char **error, void *data) +{ + GHashTable *comp; + + if(!args || !args[0]) + return PURPLE_CMD_RET_FAILED; + + comp = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL); + + g_hash_table_replace(comp, "channel", args[0]); + if(args[1]) + g_hash_table_replace(comp, "passphrase", args[1]); + + silcpurple_chat_join(purple_conversation_get_gc(conv), comp); + + g_hash_table_destroy(comp); + return PURPLE_CMD_RET_OK; +} + +static PurpleCmdRet silcpurple_cmd_chat_list(PurpleConversation *conv, + const char *cmd, char **args, char **error, void *data) +{ + PurpleConnection *gc; + gc = purple_conversation_get_gc(conv); + purple_roomlist_show_with_account(purple_connection_get_account(gc)); + return PURPLE_CMD_RET_OK; +} + +static PurpleCmdRet silcpurple_cmd_whois(PurpleConversation *conv, + const char *cmd, char **args, char **error, void *data) +{ + PurpleConnection *gc; + + gc = purple_conversation_get_gc(conv); + + if (gc == NULL) + return PURPLE_CMD_RET_FAILED; + + silcpurple_get_info(gc, args[0]); + + return PURPLE_CMD_RET_OK; +} + +static PurpleCmdRet silcpurple_cmd_msg(PurpleConversation *conv, + const char *cmd, char **args, char **error, void *data) +{ + int ret; + PurpleConnection *gc; + + gc = purple_conversation_get_gc(conv); + + if (gc == NULL) + return PURPLE_CMD_RET_FAILED; + + ret = silcpurple_send_im(gc, args[0], args[1], PURPLE_MESSAGE_SEND); + + if (ret) + return PURPLE_CMD_RET_OK; + else + return PURPLE_CMD_RET_FAILED; +} + +static PurpleCmdRet silcpurple_cmd_query(PurpleConversation *conv, + const char *cmd, char **args, char **error, void *data) +{ + int ret = 1; + PurpleConversation *convo; + PurpleConnection *gc; + PurpleAccount *account; + + if (!args || !args[0]) { + *error = g_strdup(_("You must specify a nick")); + return PURPLE_CMD_RET_FAILED; + } + + gc = purple_conversation_get_gc(conv); + + if (gc == NULL) + return PURPLE_CMD_RET_FAILED; + + account = purple_connection_get_account(gc); + + convo = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, args[0]); + + if (args[1]) { + ret = silcpurple_send_im(gc, args[0], args[1], PURPLE_MESSAGE_SEND); + purple_conv_im_write(PURPLE_CONV_IM(convo), purple_connection_get_display_name(gc), + args[1], PURPLE_MESSAGE_SEND, time(NULL)); + } + + if (ret) + return PURPLE_CMD_RET_OK; + else + return PURPLE_CMD_RET_FAILED; +} + +static PurpleCmdRet silcpurple_cmd_motd(PurpleConversation *conv, + const char *cmd, char **args, char **error, void *data) +{ + PurpleConnection *gc; + SilcPurple sg; + char *tmp; + + gc = purple_conversation_get_gc(conv); + + if (gc == NULL) + return PURPLE_CMD_RET_FAILED; + + sg = gc->proto_data; + + if (sg == NULL) + return PURPLE_CMD_RET_FAILED; + + if (!sg->motd) { + *error = g_strdup(_("There is no Message of the Day associated with this connection")); + return PURPLE_CMD_RET_FAILED; + } + + tmp = g_markup_escape_text(sg->motd, -1); + purple_notify_formatted(gc, NULL, _("Message of the Day"), NULL, + tmp, NULL, NULL); + g_free(tmp); + + return PURPLE_CMD_RET_OK; +} + +static PurpleCmdRet silcpurple_cmd_detach(PurpleConversation *conv, + const char *cmd, char **args, char **error, void *data) +{ + PurpleConnection *gc; + SilcPurple sg; + + gc = purple_conversation_get_gc(conv); + + if (gc == NULL) + return PURPLE_CMD_RET_FAILED; + + sg = gc->proto_data; + + if (sg == NULL) + return PURPLE_CMD_RET_FAILED; + + silc_client_command_call(sg->client, sg->conn, "DETACH"); + sg->detaching = TRUE; + + return PURPLE_CMD_RET_OK; +} + +static PurpleCmdRet silcpurple_cmd_cmode(PurpleConversation *conv, + const char *cmd, char **args, char **error, void *data) +{ + PurpleConnection *gc; + SilcPurple sg; + SilcChannelEntry channel; + char *silccmd, *silcargs, *msg, tmp[256]; + const char *chname; + + gc = purple_conversation_get_gc(conv); + + if (gc == NULL || !args || gc->proto_data == NULL) + return PURPLE_CMD_RET_FAILED; + + sg = gc->proto_data; + + if (args[0]) + chname = args[0]; + else + chname = purple_conversation_get_name(conv); + + if (!args[1]) { + channel = silc_client_get_channel(sg->client, sg->conn, + (char *)chname); + if (!channel) { + *error = g_strdup_printf(_("channel %s not found"), chname); + return PURPLE_CMD_RET_FAILED; + } + if (channel->mode) { + silcpurple_get_chmode_string(channel->mode, tmp, sizeof(tmp)); + msg = g_strdup_printf(_("channel modes for %s: %s"), chname, tmp); + } else { + msg = g_strdup_printf(_("no channel modes are set on %s"), chname); + } + purple_conv_chat_write(PURPLE_CONV_CHAT(conv), "", + msg, PURPLE_MESSAGE_SYSTEM|PURPLE_MESSAGE_NO_LOG, time(NULL)); + g_free(msg); + return PURPLE_CMD_RET_OK; + } + + silcargs = g_strjoinv(" ", args); + silccmd = g_strconcat(cmd, " ", args ? silcargs : NULL, NULL); + g_free(silcargs); + if (!silc_client_command_call(sg->client, sg->conn, silccmd)) { + g_free(silccmd); + *error = g_strdup_printf(_("Failed to set cmodes for %s"), args[0]); + return PURPLE_CMD_RET_FAILED; + } + g_free(silccmd); + + return PURPLE_CMD_RET_OK; +} + +static PurpleCmdRet silcpurple_cmd_generic(PurpleConversation *conv, + const char *cmd, char **args, char **error, void *data) +{ + PurpleConnection *gc; + SilcPurple sg; + char *silccmd, *silcargs; + + gc = purple_conversation_get_gc(conv); + + if (gc == NULL) + return PURPLE_CMD_RET_FAILED; + + sg = gc->proto_data; + + if (sg == NULL) + return PURPLE_CMD_RET_FAILED; + + silcargs = g_strjoinv(" ", args); + silccmd = g_strconcat(cmd, " ", args ? silcargs : NULL, NULL); + g_free(silcargs); + if (!silc_client_command_call(sg->client, sg->conn, silccmd)) { + g_free(silccmd); + *error = g_strdup_printf(_("Unknown command: %s, (may be a client bug)"), cmd); + return PURPLE_CMD_RET_FAILED; + } + g_free(silccmd); + + return PURPLE_CMD_RET_OK; +} + +static PurpleCmdRet silcpurple_cmd_quit(PurpleConversation *conv, + const char *cmd, char **args, char **error, void *data) +{ + PurpleConnection *gc; + SilcPurple sg; + + gc = purple_conversation_get_gc(conv); + + if (gc == NULL) + return PURPLE_CMD_RET_FAILED; + + sg = gc->proto_data; + + if (sg == NULL) + return PURPLE_CMD_RET_FAILED; + + silc_client_command_call(sg->client, sg->conn, NULL, + "QUIT", (args && args[0]) ? args[0] : "Download this: " PURPLE_WEBSITE, NULL); + + return PURPLE_CMD_RET_OK; +} + +static PurpleCmdRet silcpurple_cmd_call(PurpleConversation *conv, + const char *cmd, char **args, char **error, void *data) +{ + PurpleConnection *gc; + SilcPurple sg; + + gc = purple_conversation_get_gc(conv); + + if (gc == NULL) + return PURPLE_CMD_RET_FAILED; + + sg = gc->proto_data; + + if (sg == NULL) + return PURPLE_CMD_RET_FAILED; + + if (!silc_client_command_call(sg->client, sg->conn, args[0])) { + *error = g_strdup_printf(_("Unknown command: %s"), args[0]); + return PURPLE_CMD_RET_FAILED; + } + + return PURPLE_CMD_RET_OK; +} + + +/************************** Plugin Initialization ****************************/ + +static void +silcpurple_register_commands(void) +{ + purple_cmd_register("part", "w", PURPLE_CMD_P_PRPL, + PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_CHAT | + PURPLE_CMD_FLAG_PRPL_ONLY | PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS, + "prpl-silc", silcpurple_cmd_chat_part, _("part [channel]: Leave the chat"), NULL); + purple_cmd_register("leave", "w", PURPLE_CMD_P_PRPL, + PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_CHAT | + PURPLE_CMD_FLAG_PRPL_ONLY | PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS, + "prpl-silc", silcpurple_cmd_chat_part, _("leave [channel]: Leave the chat"), NULL); + purple_cmd_register("topic", "s", PURPLE_CMD_P_PRPL, + PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY | + PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-silc", + silcpurple_cmd_chat_topic, _("topic [<new topic>]: View or change the topic"), NULL); + purple_cmd_register("join", "ws", PURPLE_CMD_P_PRPL, + PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_CHAT | + PURPLE_CMD_FLAG_PRPL_ONLY | PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS, + "prpl-silc", silcpurple_cmd_chat_join, + _("join <channel> [<password>]: Join a chat on this network"), NULL); + purple_cmd_register("list", "", PURPLE_CMD_P_PRPL, + PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY | + PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-silc", + silcpurple_cmd_chat_list, _("list: List channels on this network"), NULL); + purple_cmd_register("whois", "w", PURPLE_CMD_P_PRPL, + PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY, + "prpl-silc", + silcpurple_cmd_whois, _("whois <nick>: View nick's information"), NULL); + purple_cmd_register("msg", "ws", PURPLE_CMD_P_PRPL, + PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY, + "prpl-silc", silcpurple_cmd_msg, + _("msg <nick> <message>: Send a private message to a user"), NULL); + purple_cmd_register("query", "ws", PURPLE_CMD_P_PRPL, + PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY | + PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-silc", silcpurple_cmd_query, + _("query <nick> [<message>]: Send a private message to a user"), NULL); + purple_cmd_register("motd", "", PURPLE_CMD_P_PRPL, + PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY | + PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-silc", silcpurple_cmd_motd, + _("motd: View the server's Message Of The Day"), NULL); + purple_cmd_register("detach", "", PURPLE_CMD_P_PRPL, + PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY, + "prpl-silc", silcpurple_cmd_detach, + _("detach: Detach this session"), NULL); + purple_cmd_register("quit", "s", PURPLE_CMD_P_PRPL, + PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY | + PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-silc", silcpurple_cmd_quit, + _("quit [message]: Disconnect from the server, with an optional message"), NULL); + purple_cmd_register("call", "s", PURPLE_CMD_P_PRPL, + PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY, + "prpl-silc", silcpurple_cmd_call, + _("call <command>: Call any silc client command"), NULL); + /* These below just get passed through for the silc client library to deal + * with */ + purple_cmd_register("kill", "ws", PURPLE_CMD_P_PRPL, + PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY | + PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-silc", silcpurple_cmd_generic, + _("kill <nick> [-pubkey|<reason>]: Kill nick"), NULL); + purple_cmd_register("nick", "w", PURPLE_CMD_P_PRPL, + PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY, + "prpl-silc", silcpurple_cmd_generic, + _("nick <newnick>: Change your nickname"), NULL); + purple_cmd_register("whowas", "ww", PURPLE_CMD_P_PRPL, + PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY | + PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-silc", silcpurple_cmd_generic, + _("whowas <nick>: View nick's information"), NULL); + purple_cmd_register("cmode", "wws", PURPLE_CMD_P_PRPL, + PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY | + PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-silc", silcpurple_cmd_cmode, + _("cmode <channel> [+|-<modes>] [arguments]: Change or display channel modes"), NULL); + purple_cmd_register("cumode", "wws", PURPLE_CMD_P_PRPL, + PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY | + PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-silc", silcpurple_cmd_generic, + _("cumode <channel> +|-<modes> <nick>: Change nick's modes on channel"), NULL); + purple_cmd_register("umode", "w", PURPLE_CMD_P_PRPL, + PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY, + "prpl-silc", silcpurple_cmd_generic, + _("umode <usermodes>: Set your modes in the network"), NULL); + purple_cmd_register("oper", "s", PURPLE_CMD_P_PRPL, + PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY, + "prpl-silc", silcpurple_cmd_generic, + _("oper <nick> [-pubkey]: Get server operator privileges"), NULL); + purple_cmd_register("invite", "ws", PURPLE_CMD_P_PRPL, + PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY | + PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-silc", silcpurple_cmd_generic, + _("invite <channel> [-|+]<nick>: invite nick or add/remove from channel invite list"), NULL); + purple_cmd_register("kick", "wws", PURPLE_CMD_P_PRPL, + PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY | + PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-silc", silcpurple_cmd_generic, + _("kick <channel> <nick> [comment]: Kick client from channel"), NULL); + purple_cmd_register("info", "w", PURPLE_CMD_P_PRPL, + PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY | + PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-silc", silcpurple_cmd_generic, + _("info [server]: View server administrative details"), NULL); + purple_cmd_register("ban", "ww", PURPLE_CMD_P_PRPL, + PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY | + PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-silc", silcpurple_cmd_generic, + _("ban [<channel> +|-<nick>]: Ban client from channel"), NULL); + purple_cmd_register("getkey", "w", PURPLE_CMD_P_PRPL, + PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY, + "prpl-silc", silcpurple_cmd_generic, + _("getkey <nick|server>: Retrieve client's or server's public key"), NULL); + purple_cmd_register("stats", "", PURPLE_CMD_P_PRPL, + PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY, + "prpl-silc", silcpurple_cmd_generic, + _("stats: View server and network statistics"), NULL); + purple_cmd_register("ping", "", PURPLE_CMD_P_PRPL, + PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY, + "prpl-silc", silcpurple_cmd_generic, + _("ping: Send PING to the connected server"), NULL); +#if 0 /* Purple doesn't handle these yet */ + purple_cmd_register("users", "w", PURPLE_CMD_P_PRPL, + PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY, + "prpl-silc", silcpurple_cmd_users, + _("users <channel>: List users in channel")); + purple_cmd_register("names", "ww", PURPLE_CMD_P_PRPL, + PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY | + PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-silc", silcpurple_cmd_names, + _("names [-count|-ops|-halfops|-voices|-normal] <channel(s)>: List specific users in channel(s)")); +#endif +} + +static PurpleWhiteboardPrplOps silcpurple_wb_ops = +{ + silcpurple_wb_start, + silcpurple_wb_end, + silcpurple_wb_get_dimensions, + silcpurple_wb_set_dimensions, + silcpurple_wb_get_brush, + silcpurple_wb_set_brush, + silcpurple_wb_send, + silcpurple_wb_clear, + + /* padding */ + NULL, + NULL, + NULL, + NULL +}; + +static PurplePluginProtocolInfo prpl_info = +{ +#ifdef HAVE_SILCMIME_H + OPT_PROTO_CHAT_TOPIC | OPT_PROTO_UNIQUE_CHATNAME | + OPT_PROTO_PASSWORD_OPTIONAL | OPT_PROTO_IM_IMAGE, +#else + OPT_PROTO_CHAT_TOPIC | OPT_PROTO_UNIQUE_CHATNAME | + OPT_PROTO_PASSWORD_OPTIONAL, +#endif + NULL, /* user_splits */ + NULL, /* protocol_options */ +#ifdef SILC_ATTRIBUTE_USER_ICON + {"jpeg,gif,png,bmp", 0, 0, 96, 96, 0, PURPLE_ICON_SCALE_DISPLAY}, /* icon_spec */ +#else + NO_BUDDY_ICONS, +#endif + silcpurple_list_icon, /* list_icon */ + NULL, /* list_emblems */ + silcpurple_status_text, /* status_text */ + silcpurple_tooltip_text, /* tooltip_text */ + silcpurple_away_states, /* away_states */ + silcpurple_blist_node_menu, /* blist_node_menu */ + silcpurple_chat_info, /* chat_info */ + silcpurple_chat_info_defaults,/* chat_info_defaults */ + silcpurple_login, /* login */ + silcpurple_close, /* close */ + silcpurple_send_im, /* send_im */ + silcpurple_set_info, /* set_info */ + NULL, /* send_typing */ + silcpurple_get_info, /* get_info */ + silcpurple_set_status, /* set_status */ + silcpurple_idle_set, /* set_idle */ + silcpurple_change_passwd, /* change_passwd */ + silcpurple_add_buddy, /* add_buddy */ + NULL, /* add_buddies */ + silcpurple_remove_buddy, /* remove_buddy */ + NULL, /* remove_buddies */ + NULL, /* add_permit */ + NULL, /* add_deny */ + NULL, /* rem_permit */ + NULL, /* rem_deny */ + NULL, /* set_permit_deny */ + silcpurple_chat_join, /* join_chat */ + NULL, /* reject_chat */ + silcpurple_get_chat_name, /* get_chat_name */ + silcpurple_chat_invite, /* chat_invite */ + silcpurple_chat_leave, /* chat_leave */ + NULL, /* chat_whisper */ + silcpurple_chat_send, /* chat_send */ + silcpurple_keepalive, /* keepalive */ + NULL, /* register_user */ + NULL, /* get_cb_info */ + NULL, /* get_cb_away */ + NULL, /* alias_buddy */ + NULL, /* group_buddy */ + NULL, /* rename_group */ + NULL, /* buddy_free */ + NULL, /* convo_closed */ + NULL, /* normalize */ +#ifdef SILC_ATTRIBUTE_USER_ICON + silcpurple_buddy_set_icon, /* set_buddy_icon */ +#else + NULL, +#endif + NULL, /* remove_group */ + NULL, /* get_cb_real_name */ + silcpurple_chat_set_topic, /* set_chat_topic */ + NULL, /* find_blist_chat */ + silcpurple_roomlist_get_list, /* roomlist_get_list */ + silcpurple_roomlist_cancel, /* roomlist_cancel */ + NULL, /* roomlist_expand_category */ + NULL, /* can_receive_file */ + silcpurple_ftp_send_file, /* send_file */ + silcpurple_ftp_new_xfer, /* new_xfer */ + NULL, /* offline_message */ + &silcpurple_wb_ops, /* whiteboard_prpl_ops */ + NULL, /* send_raw */ + NULL, /* roomlist_room_serialize */ + + /* padding */ + NULL, + NULL, + NULL, + NULL +}; + +static PurplePluginInfo info = +{ + PURPLE_PLUGIN_MAGIC, + PURPLE_MAJOR_VERSION, + PURPLE_MINOR_VERSION, + PURPLE_PLUGIN_PROTOCOL, /**< type */ + NULL, /**< ui_requirement */ + 0, /**< flags */ + NULL, /**< dependencies */ + PURPLE_PRIORITY_DEFAULT, /**< priority */ + + "prpl-silc", /**< id */ + "SILC", /**< name */ + "1.0", /**< version */ + /** summary */ + N_("SILC Protocol Plugin"), + /** description */ + N_("Secure Internet Live Conferencing (SILC) Protocol"), + "Pekka Riikonen", /**< author */ + "http://silcnet.org/", /**< homepage */ + + NULL, /**< load */ + NULL, /**< unload */ + NULL, /**< destroy */ + + NULL, /**< ui_info */ + &prpl_info, /**< extra_info */ + NULL, /**< prefs_info */ + silcpurple_actions, + + /* padding */ + NULL, + NULL, + NULL, + NULL +}; + +static void +init_plugin(PurplePlugin *plugin) +{ + PurpleAccountOption *option; + PurpleAccountUserSplit *split; + char tmp[256]; + int i; + PurpleKeyValuePair *kvp; + GList *list = NULL; + + silc_plugin = plugin; + + split = purple_account_user_split_new(_("Network"), "silcnet.org", '@'); + prpl_info.user_splits = g_list_append(prpl_info.user_splits, split); + + /* Account options */ + option = purple_account_option_string_new(_("Connect server"), + "server", + "silc.silcnet.org"); + prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); + option = purple_account_option_int_new(_("Port"), "port", 706); + prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); + g_snprintf(tmp, sizeof(tmp), "%s" G_DIR_SEPARATOR_S "public_key.pub", silcpurple_silcdir()); + option = purple_account_option_string_new(_("Public Key file"), + "public-key", tmp); + prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); + g_snprintf(tmp, sizeof(tmp), "%s" G_DIR_SEPARATOR_S "private_key.prv", silcpurple_silcdir()); + option = purple_account_option_string_new(_("Private Key file"), + "private-key", tmp); + prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); + + for (i = 0; silc_default_ciphers[i].name; i++) { + kvp = g_new0(PurpleKeyValuePair, 1); + kvp->key = g_strdup(silc_default_ciphers[i].name); + kvp->value = g_strdup(silc_default_ciphers[i].name); + list = g_list_append(list, kvp); + } + option = purple_account_option_list_new(_("Cipher"), "cipher", list); + prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); + + list = NULL; + for (i = 0; silc_default_hmacs[i].name; i++) { + kvp = g_new0(PurpleKeyValuePair, 1); + kvp->key = g_strdup(silc_default_hmacs[i].name); + kvp->value = g_strdup(silc_default_hmacs[i].name); + list = g_list_append(list, kvp); + } + option = purple_account_option_list_new(_("HMAC"), "hmac", list); + prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); + + option = purple_account_option_bool_new(_("Public key authentication"), + "pubkey-auth", FALSE); + prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); + option = purple_account_option_bool_new(_("Block IMs without Key Exchange"), + "block-ims", FALSE); + prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); + option = purple_account_option_bool_new(_("Block messages to whiteboard"), + "block-wb", FALSE); + prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); + option = purple_account_option_bool_new(_("Automatically open whiteboard"), + "open-wb", FALSE); + prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); + option = purple_account_option_bool_new(_("Digitally sign and verify all messages"), + "sign-verify", FALSE); + prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); + + purple_prefs_remove("/plugins/prpl/silc"); + + silcpurple_register_commands(); + +#ifdef _WIN32 + silc_net_win32_init(); +#endif +} + +PURPLE_INIT_PLUGIN(silc, init_plugin, info);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/silc10/silcpurple.h Mon Jun 18 01:48:35 2007 +0000 @@ -0,0 +1,173 @@ +/* + + silcpurple.h + + Author: Pekka Riikonen <priikone@silcnet.org> + + Copyright (C) 2004 Pekka Riikonen + + 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; version 2 of the License. + + 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. + +*/ + +#ifndef SILCPURPLE_H +#define SILCPURPLE_H + +/* Purple includes */ +#include "internal.h" +#include "account.h" +#include "accountopt.h" +#include "cmds.h" +#include "conversation.h" +#include "debug.h" +#include "ft.h" +#include "notify.h" +#include "prpl.h" +#include "request.h" +#include "roomlist.h" +#include "server.h" +#include "util.h" + +/* Default public and private key file names */ +#define SILCPURPLE_PUBLIC_KEY_NAME "public_key.pub" +#define SILCPURPLE_PRIVATE_KEY_NAME "private_key.prv" + +/* Default settings for creating key pair */ +#define SILCPURPLE_DEF_PKCS "rsa" +#define SILCPURPLE_DEF_PKCS_LEN 2048 + +#define SILCPURPLE_PRVGRP 0x001fffff + +/* Status IDs */ +#define SILCPURPLE_STATUS_ID_OFFLINE "offline" +#define SILCPURPLE_STATUS_ID_AVAILABLE "available" +#define SILCPURPLE_STATUS_ID_HYPER "hyper" +#define SILCPURPLE_STATUS_ID_AWAY "away" +#define SILCPURPLE_STATUS_ID_BUSY "busy" +#define SILCPURPLE_STATUS_ID_INDISPOSED "indisposed" +#define SILCPURPLE_STATUS_ID_PAGE "page" + +typedef struct { + unsigned long id; + const char *channel; + unsigned long chid; + const char *parentch; + SilcChannelPrivateKey key; +} *SilcPurplePrvgrp; + +/* The SILC Purple plugin context */ +typedef struct SilcPurpleStruct { + SilcClient client; + SilcClientConnection conn; + + guint scheduler; + PurpleConnection *gc; + PurpleAccount *account; + unsigned long channel_ids; + GList *grps; + + char *motd; + PurpleRoomlist *roomlist; +#ifdef HAVE_SILCMIME_H + SilcMimeAssembler mimeass; +#endif + unsigned int detaching : 1; + unsigned int resuming : 1; + unsigned int roomlist_canceled : 1; + unsigned int chpk : 1; +} *SilcPurple; + + +gboolean silcpurple_check_silc_dir(PurpleConnection *gc); +void silcpurple_chat_join_done(SilcClient client, + SilcClientConnection conn, + SilcClientEntry *clients, + SilcUInt32 clients_count, + void *context); +const char *silcpurple_silcdir(void); +const char *silcpurple_session_file(const char *account); +void silcpurple_verify_public_key(SilcClient client, SilcClientConnection conn, + const char *name, SilcSocketType conn_type, + unsigned char *pk, SilcUInt32 pk_len, + SilcSKEPKType pk_type, + SilcVerifyPublicKey completion, void *context); +GList *silcpurple_buddy_menu(PurpleBuddy *buddy); +void silcpurple_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group); +void silcpurple_send_buddylist(PurpleConnection *gc); +void silcpurple_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group); +void silcpurple_buddy_keyagr_request(SilcClient client, + SilcClientConnection conn, + SilcClientEntry client_entry, + const char *hostname, SilcUInt16 port); +void silcpurple_idle_set(PurpleConnection *gc, int idle); +void silcpurple_tooltip_text(PurpleBuddy *b, PurpleNotifyUserInfo *user_info, gboolean full); +char *silcpurple_status_text(PurpleBuddy *b); +gboolean silcpurple_ip_is_private(const char *ip); +void silcpurple_ftp_send_file(PurpleConnection *gc, const char *name, const char *file); +PurpleXfer *silcpurple_ftp_new_xfer(PurpleConnection *gc, const char *name); +void silcpurple_ftp_request(SilcClient client, SilcClientConnection conn, + SilcClientEntry client_entry, SilcUInt32 session_id, + const char *hostname, SilcUInt16 port); +void silcpurple_show_public_key(SilcPurple sg, + const char *name, SilcPublicKey public_key, + GCallback callback, void *context); +void silcpurple_get_info(PurpleConnection *gc, const char *who); +SilcAttributePayload +silcpurple_get_attr(SilcDList attrs, SilcAttribute attribute); +void silcpurple_get_umode_string(SilcUInt32 mode, char *buf, + SilcUInt32 buf_size); +void silcpurple_get_chmode_string(SilcUInt32 mode, char *buf, + SilcUInt32 buf_size); +void silcpurple_get_chumode_string(SilcUInt32 mode, char *buf, + SilcUInt32 buf_size); +GList *silcpurple_chat_info(PurpleConnection *gc); +GHashTable *silcpurple_chat_info_defaults(PurpleConnection *gc, const char *chat_name); +GList *silcpurple_chat_menu(PurpleChat *); +void silcpurple_chat_join(PurpleConnection *gc, GHashTable *data); +char *silcpurple_get_chat_name(GHashTable *data); +void silcpurple_chat_invite(PurpleConnection *gc, int id, const char *msg, + const char *name); +void silcpurple_chat_leave(PurpleConnection *gc, int id); +int silcpurple_chat_send(PurpleConnection *gc, int id, const char *msg, PurpleMessageFlags flags); +void silcpurple_chat_set_topic(PurpleConnection *gc, int id, const char *topic); +PurpleRoomlist *silcpurple_roomlist_get_list(PurpleConnection *gc); +void silcpurple_roomlist_cancel(PurpleRoomlist *list); +void silcpurple_chat_chauth_show(SilcPurple sg, SilcChannelEntry channel, + SilcBuffer channel_pubkeys); +void silcpurple_parse_attrs(SilcDList attrs, char **moodstr, char **statusstr, + char **contactstr, char **langstr, char **devicestr, + char **tzstr, char **geostr); +#ifdef SILC_ATTRIBUTE_USER_ICON +void silcpurple_buddy_set_icon(PurpleConnection *gc, PurpleStoredImage *img); +#endif +#ifdef HAVE_SILCMIME_H +char *silcpurple_file2mime(const char *filename); +SilcDList silcpurple_image_message(const char *msg, SilcUInt32 *mflags); +#endif + +#ifdef _WIN32 +typedef int uid_t; + +struct passwd { + char *pw_name; /* user name */ + char *pw_passwd; /* user password */ + int pw_uid; /* user id */ + int pw_gid; /* group id */ + char *pw_gecos; /* real name */ + char *pw_dir; /* home directory */ + char *pw_shell; /* shell program */ +}; + +struct passwd *getpwuid(int uid); +int getuid(void); +int geteuid(void); +#endif + +#endif /* SILCPURPLE_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/silc10/util.c Mon Jun 18 01:48:35 2007 +0000 @@ -0,0 +1,771 @@ +/* + + silcpurple_util.c + + Author: Pekka Riikonen <priikone@silcnet.org> + + Copyright (C) 2004 - 2005 Pekka Riikonen + + 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; version 2 of the License. + + 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. + +*/ + +#include "silcincludes.h" +#include "silcclient.h" +#include "silcpurple.h" +#include "imgstore.h" + +/**************************** Utility Routines *******************************/ + +static char str[256], str2[256]; + +const char *silcpurple_silcdir(void) +{ + const char *hd = purple_home_dir(); + memset(str, 0, sizeof(str)); + g_snprintf(str, sizeof(str) - 1, "%s" G_DIR_SEPARATOR_S ".silc", hd ? hd : "/tmp"); + return (const char *)str; +} + +const char *silcpurple_session_file(const char *account) +{ + memset(str2, 0, sizeof(str2)); + g_snprintf(str2, sizeof(str2) - 1, "%s" G_DIR_SEPARATOR_S "%s_session", + silcpurple_silcdir(), account); + return (const char *)str2; +} + +gboolean silcpurple_ip_is_private(const char *ip) +{ + if (silc_net_is_ip4(ip)) { + if (!strncmp(ip, "10.", 3)) { + return TRUE; + } else if (!strncmp(ip, "172.", 4) && strlen(ip) > 6) { + char tmp[3]; + int s; + memset(tmp, 0, sizeof(tmp)); + strncpy(tmp, ip + 4, 2); + s = atoi(tmp); + if (s >= 16 && s <= 31) + return TRUE; + } else if (!strncmp(ip, "192.168.", 8)) { + return TRUE; + } + } + + return FALSE; +} + +/* This checks stats for various SILC files and directories. First it + checks if ~/.silc directory exist and is owned by the correct user. If + it doesn't exist, it will create the directory. After that it checks if + user's Public and Private key files exists and creates them if needed. */ + +gboolean silcpurple_check_silc_dir(PurpleConnection *gc) +{ + char filename[256], file_public_key[256], file_private_key[256]; + char servfilename[256], clientfilename[256], friendsfilename[256]; + char pkd[256], prd[256]; + struct stat st; + struct passwd *pw; + int fd; + + pw = getpwuid(getuid()); + if (!pw) { + purple_debug_error("silc", "silc: %s\n", strerror(errno)); + return FALSE; + } + + g_snprintf(filename, sizeof(filename) - 1, "%s", silcpurple_silcdir()); + g_snprintf(servfilename, sizeof(servfilename) - 1, "%s" G_DIR_SEPARATOR_S "serverkeys", + silcpurple_silcdir()); + g_snprintf(clientfilename, sizeof(clientfilename) - 1, "%s" G_DIR_SEPARATOR_S "clientkeys", + silcpurple_silcdir()); + g_snprintf(friendsfilename, sizeof(friendsfilename) - 1, "%s" G_DIR_SEPARATOR_S "friends", + silcpurple_silcdir()); + + /* + * Check ~/.silc directory + */ + if ((g_stat(filename, &st)) == -1) { + /* If dir doesn't exist */ + if (errno == ENOENT) { + if (pw->pw_uid == geteuid()) { + if ((g_mkdir(filename, 0755)) == -1) { + purple_debug_error("silc", "Couldn't create '%s' directory\n", filename); + return FALSE; + } + } else { + purple_debug_error("silc", "Couldn't create '%s' directory due to a wrong uid!\n", + filename); + return FALSE; + } + } else { + purple_debug_error("silc", "Couldn't stat '%s' directory, error: %s\n", filename, strerror(errno)); + return FALSE; + } + } else { +#ifndef _WIN32 + /* Check the owner of the dir */ + if (st.st_uid != 0 && st.st_uid != pw->pw_uid) { + purple_debug_error("silc", "You don't seem to own '%s' directory\n", + filename); + return FALSE; + } +#endif + } + + /* + * Check ~./silc/serverkeys directory + */ + if ((g_stat(servfilename, &st)) == -1) { + /* If dir doesn't exist */ + if (errno == ENOENT) { + if (pw->pw_uid == geteuid()) { + if ((g_mkdir(servfilename, 0755)) == -1) { + purple_debug_error("silc", "Couldn't create '%s' directory\n", servfilename); + return FALSE; + } + } else { + purple_debug_error("silc", "Couldn't create '%s' directory due to a wrong uid!\n", + servfilename); + return FALSE; + } + } else { + purple_debug_error("silc", "Couldn't stat '%s' directory, error: %s\n", + servfilename, strerror(errno)); + return FALSE; + } + } + + /* + * Check ~./silc/clientkeys directory + */ + if ((g_stat(clientfilename, &st)) == -1) { + /* If dir doesn't exist */ + if (errno == ENOENT) { + if (pw->pw_uid == geteuid()) { + if ((g_mkdir(clientfilename, 0755)) == -1) { + purple_debug_error("silc", "Couldn't create '%s' directory\n", clientfilename); + return FALSE; + } + } else { + purple_debug_error("silc", "Couldn't create '%s' directory due to a wrong uid!\n", + clientfilename); + return FALSE; + } + } else { + purple_debug_error("silc", "Couldn't stat '%s' directory, error: %s\n", + clientfilename, strerror(errno)); + return FALSE; + } + } + + /* + * Check ~./silc/friends directory + */ + if ((g_stat(friendsfilename, &st)) == -1) { + /* If dir doesn't exist */ + if (errno == ENOENT) { + if (pw->pw_uid == geteuid()) { + if ((g_mkdir(friendsfilename, 0755)) == -1) { + purple_debug_error("silc", "Couldn't create '%s' directory\n", friendsfilename); + return FALSE; + } + } else { + purple_debug_error("silc", "Couldn't create '%s' directory due to a wrong uid!\n", + friendsfilename); + return FALSE; + } + } else { + purple_debug_error("silc", "Couldn't stat '%s' directory, error: %s\n", + friendsfilename, strerror(errno)); + return FALSE; + } + } + + /* + * Check Public and Private keys + */ + g_snprintf(pkd, sizeof(pkd), "%s" G_DIR_SEPARATOR_S "public_key.pub", silcpurple_silcdir()); + g_snprintf(prd, sizeof(prd), "%s" G_DIR_SEPARATOR_S "private_key.prv", silcpurple_silcdir()); + g_snprintf(file_public_key, sizeof(file_public_key) - 1, "%s", + purple_account_get_string(gc->account, "public-key", pkd)); + g_snprintf(file_private_key, sizeof(file_public_key) - 1, "%s", + purple_account_get_string(gc->account, "private-key", prd)); + + if ((g_stat(file_public_key, &st)) == -1) { + /* If file doesn't exist */ + if (errno == ENOENT) { + purple_connection_update_progress(gc, _("Creating SILC key pair..."), 1, 5); + if (!silc_create_key_pair(SILCPURPLE_DEF_PKCS, + SILCPURPLE_DEF_PKCS_LEN, + file_public_key, file_private_key, NULL, + (gc->password == NULL) ? "" : gc->password, + NULL, NULL, NULL, FALSE)) { + purple_debug_error("silc", "Couldn't create key pair\n"); + return FALSE; + } + + if ((g_stat(file_public_key, &st)) == -1) { + purple_debug_error("silc", "Couldn't stat '%s' public key, error: %s\n", + file_public_key, strerror(errno)); + return FALSE; + } + } else { + purple_debug_error("silc", "Couldn't stat '%s' public key, error: %s\n", + file_public_key, strerror(errno)); + return FALSE; + } + } + +#ifndef _WIN32 + /* Check the owner of the public key */ + if (st.st_uid != 0 && st.st_uid != pw->pw_uid) { + purple_debug_error("silc", "You don't seem to own your public key!?\n"); + return FALSE; + } +#endif + + if ((fd = g_open(file_private_key, O_RDONLY, 0)) != -1) { + if ((fstat(fd, &st)) == -1) { + purple_debug_error("silc", "Couldn't stat '%s' private key, error: %s\n", + file_private_key, strerror(errno)); + close(fd); + return FALSE; + } + } else if ((g_stat(file_private_key, &st)) == -1) { + /* If file doesn't exist */ + if (errno == ENOENT) { + purple_connection_update_progress(gc, _("Creating SILC key pair..."), 1, 5); + if (!silc_create_key_pair(SILCPURPLE_DEF_PKCS, + SILCPURPLE_DEF_PKCS_LEN, + file_public_key, file_private_key, NULL, + (gc->password == NULL) ? "" : gc->password, + NULL, NULL, NULL, FALSE)) { + purple_debug_error("silc", "Couldn't create key pair\n"); + return FALSE; + } + + if ((fd = g_open(file_private_key, O_RDONLY, 0)) != -1) { + if ((fstat(fd, &st)) == -1) { + purple_debug_error("silc", "Couldn't stat '%s' private key, error: %s\n", + file_private_key, strerror(errno)); + close(fd); + return FALSE; + } + } + /* This shouldn't really happen because silc_create_key_pair() + * will set the permissions */ + else if ((g_stat(file_private_key, &st)) == -1) { + purple_debug_error("silc", "Couldn't stat '%s' private key, error: %s\n", + file_private_key, strerror(errno)); + return FALSE; + } + } else { + purple_debug_error("silc", "Couldn't stat '%s' private key, error: %s\n", + file_private_key, strerror(errno)); + return FALSE; + } + } + +#ifndef _WIN32 + /* Check the owner of the private key */ + if (st.st_uid != 0 && st.st_uid != pw->pw_uid) { + purple_debug_error("silc", "You don't seem to own your private key!?\n"); + if (fd != -1) + close(fd); + return FALSE; + } + + /* Check the permissions for the private key */ + if ((st.st_mode & 0777) != 0600) { + purple_debug_warning("silc", "Wrong permissions in your private key file `%s'!\n" + "Trying to change them ...\n", file_private_key); + if ((fd == -1) || (fchmod(fd, S_IRUSR | S_IWUSR)) == -1) { + purple_debug_error("silc", + "Failed to change permissions for private key file!\n" + "Permissions for your private key file must be 0600.\n"); + if (fd != -1) + close(fd); + return FALSE; + } + purple_debug_warning("silc", "Done.\n\n"); + } +#endif + + if (fd != -1) + close(fd); + + return TRUE; +} + +#ifdef _WIN32 +struct passwd *getpwuid(uid_t uid) { + struct passwd *pwd = calloc(1, sizeof(struct passwd)); + return pwd; +} + +uid_t getuid() { + return 0; +} + +uid_t geteuid() { + return 0; +} +#endif + +void silcpurple_show_public_key(SilcPurple sg, + const char *name, SilcPublicKey public_key, + GCallback callback, void *context) +{ + SilcPublicKeyIdentifier ident; + SilcPKCS pkcs; + char *fingerprint, *babbleprint; + unsigned char *pk; + SilcUInt32 pk_len, key_len = 0; + GString *s; + char *buf; + + ident = silc_pkcs_decode_identifier(public_key->identifier); + if (!ident) + return; + + pk = silc_pkcs_public_key_encode(public_key, &pk_len); + fingerprint = silc_hash_fingerprint(NULL, pk, pk_len); + babbleprint = silc_hash_babbleprint(NULL, pk, pk_len); + + if (silc_pkcs_alloc((unsigned char *)public_key->name, &pkcs)) { + key_len = silc_pkcs_public_key_set(pkcs, public_key); + silc_pkcs_free(pkcs); + } + + s = g_string_new(""); + if (ident->realname) + /* Hint for translators: Please check the tabulator width here and in + the next strings (short strings: 2 tabs, longer strings 1 tab, + sum: 3 tabs or 24 characters) */ + g_string_append_printf(s, _("Real Name: \t%s\n"), ident->realname); + if (ident->username) + g_string_append_printf(s, _("User Name: \t%s\n"), ident->username); + if (ident->email) + g_string_append_printf(s, _("E-Mail: \t\t%s\n"), ident->email); + if (ident->host) + g_string_append_printf(s, _("Host Name: \t%s\n"), ident->host); + if (ident->org) + g_string_append_printf(s, _("Organization: \t%s\n"), ident->org); + if (ident->country) + g_string_append_printf(s, _("Country: \t%s\n"), ident->country); + g_string_append_printf(s, _("Algorithm: \t%s\n"), public_key->name); + g_string_append_printf(s, _("Key Length: \t%d bits\n"), (int)key_len); + g_string_append_printf(s, "\n"); + g_string_append_printf(s, _("Public Key Fingerprint:\n%s\n\n"), fingerprint); + g_string_append_printf(s, _("Public Key Babbleprint:\n%s"), babbleprint); + + buf = g_string_free(s, FALSE); + + purple_request_action(sg->gc, _("Public Key Information"), + _("Public Key Information"), + buf, 0, purple_connection_get_account(sg->gc), + NULL, NULL, context, 1, _("Close"), callback); + + g_free(buf); + silc_free(fingerprint); + silc_free(babbleprint); + silc_free(pk); + silc_pkcs_free_identifier(ident); +} + +SilcAttributePayload +silcpurple_get_attr(SilcDList attrs, SilcAttribute attribute) +{ + SilcAttributePayload attr = NULL; + + if (!attrs) + return NULL; + + silc_dlist_start(attrs); + while ((attr = silc_dlist_get(attrs)) != SILC_LIST_END) + if (attribute == silc_attribute_get_attribute(attr)) + break; + + return attr; +} + +void silcpurple_get_umode_string(SilcUInt32 mode, char *buf, + SilcUInt32 buf_size) +{ + memset(buf, 0, buf_size); + if ((mode & SILC_UMODE_SERVER_OPERATOR) || + (mode & SILC_UMODE_ROUTER_OPERATOR)) { + strcat(buf, (mode & SILC_UMODE_SERVER_OPERATOR) ? + "[server operator] " : + (mode & SILC_UMODE_ROUTER_OPERATOR) ? + "[SILC operator] " : "[unknown mode] "); + } + if (mode & SILC_UMODE_GONE) + strcat(buf, "[away] "); + if (mode & SILC_UMODE_INDISPOSED) + strcat(buf, "[indisposed] "); + if (mode & SILC_UMODE_BUSY) + strcat(buf, "[busy] "); + if (mode & SILC_UMODE_PAGE) + strcat(buf, "[wake me up] "); + if (mode & SILC_UMODE_HYPER) + strcat(buf, "[hyperactive] "); + if (mode & SILC_UMODE_ROBOT) + strcat(buf, "[robot] "); + if (mode & SILC_UMODE_ANONYMOUS) + strcat(buf, "[anonymous] "); + if (mode & SILC_UMODE_BLOCK_PRIVMSG) + strcat(buf, "[blocks private messages] "); + if (mode & SILC_UMODE_DETACHED) + strcat(buf, "[detached] "); + if (mode & SILC_UMODE_REJECT_WATCHING) + strcat(buf, "[rejects watching] "); + if (mode & SILC_UMODE_BLOCK_INVITE) + strcat(buf, "[blocks invites] "); +} + +void silcpurple_get_chmode_string(SilcUInt32 mode, char *buf, + SilcUInt32 buf_size) +{ + memset(buf, 0, buf_size); + if (mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) + strcat(buf, "[permanent] "); + if (mode & SILC_CHANNEL_MODE_PRIVATE) + strcat(buf, "[private] "); + if (mode & SILC_CHANNEL_MODE_SECRET) + strcat(buf, "[secret] "); + if (mode & SILC_CHANNEL_MODE_PRIVKEY) + strcat(buf, "[private key] "); + if (mode & SILC_CHANNEL_MODE_INVITE) + strcat(buf, "[invite only] "); + if (mode & SILC_CHANNEL_MODE_TOPIC) + strcat(buf, "[topic restricted] "); + if (mode & SILC_CHANNEL_MODE_ULIMIT) + strcat(buf, "[user count limit] "); + if (mode & SILC_CHANNEL_MODE_PASSPHRASE) + strcat(buf, "[passphrase auth] "); + if (mode & SILC_CHANNEL_MODE_CHANNEL_AUTH) + strcat(buf, "[public key auth] "); + if (mode & SILC_CHANNEL_MODE_SILENCE_USERS) + strcat(buf, "[users silenced] "); + if (mode & SILC_CHANNEL_MODE_SILENCE_OPERS) + strcat(buf, "[operators silenced] "); +} + +void silcpurple_get_chumode_string(SilcUInt32 mode, char *buf, + SilcUInt32 buf_size) +{ + memset(buf, 0, buf_size); + if (mode & SILC_CHANNEL_UMODE_CHANFO) + strcat(buf, "[founder] "); + if (mode & SILC_CHANNEL_UMODE_CHANOP) + strcat(buf, "[operator] "); + if (mode & SILC_CHANNEL_UMODE_BLOCK_MESSAGES) + strcat(buf, "[blocks messages] "); + if (mode & SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS) + strcat(buf, "[blocks user messages] "); + if (mode & SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS) + strcat(buf, "[blocks robot messages] "); + if (mode & SILC_CHANNEL_UMODE_QUIET) + strcat(buf, "[quieted] "); +} + +void +silcpurple_parse_attrs(SilcDList attrs, char **moodstr, char **statusstr, + char **contactstr, char **langstr, char **devicestr, + char **tzstr, char **geostr) +{ + SilcAttributePayload attr; + SilcAttributeMood mood = 0; + SilcAttributeContact contact; + SilcAttributeObjDevice device; + SilcAttributeObjGeo geo; + + char tmp[1024]; + GString *s; + + *moodstr = NULL; + *statusstr = NULL; + *contactstr = NULL; + *langstr = NULL; + *devicestr = NULL; + *tzstr = NULL; + *geostr = NULL; + + if (!attrs) + return; + + s = g_string_new(""); + attr = silcpurple_get_attr(attrs, SILC_ATTRIBUTE_STATUS_MOOD); + if (attr && silc_attribute_get_object(attr, &mood, sizeof(mood))) { + if (mood & SILC_ATTRIBUTE_MOOD_HAPPY) + g_string_append_printf(s, "[%s] ", _("Happy")); + if (mood & SILC_ATTRIBUTE_MOOD_SAD) + g_string_append_printf(s, "[%s] ", _("Sad")); + if (mood & SILC_ATTRIBUTE_MOOD_ANGRY) + g_string_append_printf(s, "[%s] ", _("Angry")); + if (mood & SILC_ATTRIBUTE_MOOD_JEALOUS) + g_string_append_printf(s, "[%s] ", _("Jealous")); + if (mood & SILC_ATTRIBUTE_MOOD_ASHAMED) + g_string_append_printf(s, "[%s] ", _("Ashamed")); + if (mood & SILC_ATTRIBUTE_MOOD_INVINCIBLE) + g_string_append_printf(s, "[%s] ", _("Invincible")); + if (mood & SILC_ATTRIBUTE_MOOD_INLOVE) + g_string_append_printf(s, "[%s] ", _("In Love")); + if (mood & SILC_ATTRIBUTE_MOOD_SLEEPY) + g_string_append_printf(s, "[%s] ", _("Sleepy")); + if (mood & SILC_ATTRIBUTE_MOOD_BORED) + g_string_append_printf(s, "[%s] ", _("Bored")); + if (mood & SILC_ATTRIBUTE_MOOD_EXCITED) + g_string_append_printf(s, "[%s] ", _("Excited")); + if (mood & SILC_ATTRIBUTE_MOOD_ANXIOUS) + g_string_append_printf(s, "[%s] ", _("Anxious")); + } + if (strlen(s->str)) { + *moodstr = s->str; + g_string_free(s, FALSE); + } else + g_string_free(s, TRUE); + + attr = silcpurple_get_attr(attrs, SILC_ATTRIBUTE_STATUS_FREETEXT); + memset(tmp, 0, sizeof(tmp)); + if (attr && silc_attribute_get_object(attr, tmp, sizeof(tmp))) + *statusstr = g_strdup(tmp); + + s = g_string_new(""); + attr = silcpurple_get_attr(attrs, SILC_ATTRIBUTE_PREFERRED_CONTACT); + if (attr && silc_attribute_get_object(attr, &contact, sizeof(contact))) { + if (contact & SILC_ATTRIBUTE_CONTACT_CHAT) + g_string_append_printf(s, "[%s] ", _("Chat")); + if (contact & SILC_ATTRIBUTE_CONTACT_EMAIL) + g_string_append_printf(s, "[%s] ", _("E-Mail")); + if (contact & SILC_ATTRIBUTE_CONTACT_CALL) + g_string_append_printf(s, "[%s] ", _("Phone")); + if (contact & SILC_ATTRIBUTE_CONTACT_PAGE) + g_string_append_printf(s, "[%s] ", _("Paging")); + if (contact & SILC_ATTRIBUTE_CONTACT_SMS) + g_string_append_printf(s, "[%s] ", _("SMS")); + if (contact & SILC_ATTRIBUTE_CONTACT_MMS) + g_string_append_printf(s, "[%s] ", _("MMS")); + if (contact & SILC_ATTRIBUTE_CONTACT_VIDEO) + g_string_append_printf(s, "[%s] ", _("Video Conferencing")); + } + if (strlen(s->str)) { + *contactstr = s->str; + g_string_free(s, FALSE); + } else + g_string_free(s, TRUE); + + attr = silcpurple_get_attr(attrs, SILC_ATTRIBUTE_PREFERRED_LANGUAGE); + memset(tmp, 0, sizeof(tmp)); + if (attr && silc_attribute_get_object(attr, tmp, sizeof(tmp))) + *langstr = g_strdup(tmp); + + s = g_string_new(""); + attr = silcpurple_get_attr(attrs, SILC_ATTRIBUTE_DEVICE_INFO); + memset(&device, 0, sizeof(device)); + if (attr && silc_attribute_get_object(attr, &device, sizeof(device))) { + if (device.type == SILC_ATTRIBUTE_DEVICE_COMPUTER) + g_string_append_printf(s, "%s: ", _("Computer")); + if (device.type == SILC_ATTRIBUTE_DEVICE_MOBILE_PHONE) + g_string_append_printf(s, "%s: ", _("Mobile Phone")); + if (device.type == SILC_ATTRIBUTE_DEVICE_PDA) + g_string_append_printf(s, "%s: ", _("PDA")); + if (device.type == SILC_ATTRIBUTE_DEVICE_TERMINAL) + g_string_append_printf(s, "%s: ", _("Terminal")); + g_string_append_printf(s, "%s %s %s %s", + device.manufacturer ? device.manufacturer : "", + device.version ? device.version : "", + device.model ? device.model : "", + device.language ? device.language : ""); + } + if (strlen(s->str)) { + *devicestr = s->str; + g_string_free(s, FALSE); + } else + g_string_free(s, TRUE); + + attr = silcpurple_get_attr(attrs, SILC_ATTRIBUTE_TIMEZONE); + memset(tmp, 0, sizeof(tmp)); + if (attr && silc_attribute_get_object(attr, tmp, sizeof(tmp))) + *tzstr = g_strdup(tmp); + + attr = silcpurple_get_attr(attrs, SILC_ATTRIBUTE_GEOLOCATION); + memset(&geo, 0, sizeof(geo)); + if (attr && silc_attribute_get_object(attr, &geo, sizeof(geo))) + *geostr = g_strdup_printf("%s %s %s (%s)", + geo.longitude ? geo.longitude : "", + geo.latitude ? geo.latitude : "", + geo.altitude ? geo.altitude : "", + geo.accuracy ? geo.accuracy : ""); +} + +#ifdef HAVE_SILCMIME_H +/* Returns MIME type of filetype */ + +char *silcpurple_file2mime(const char *filename) +{ + const char *ct; + + ct = strrchr(filename, '.'); + if (!ct) + return NULL; + else if (!g_ascii_strcasecmp(".png", ct)) + return strdup("image/png"); + else if (!g_ascii_strcasecmp(".jpg", ct)) + return strdup("image/jpeg"); + else if (!g_ascii_strcasecmp(".jpeg", ct)) + return strdup("image/jpeg"); + else if (!g_ascii_strcasecmp(".gif", ct)) + return strdup("image/gif"); + else if (!g_ascii_strcasecmp(".tiff", ct)) + return strdup("image/tiff"); + + return NULL; +} + +/* Checks if message has images, and assembles MIME message if it has. + If only one image is present, creates simple MIME image message. If + there are multiple images and/or text with images multipart MIME + message is created. */ + +SilcDList silcpurple_image_message(const char *msg, SilcUInt32 *mflags) +{ + SilcMime mime = NULL, p; + SilcDList list, parts = NULL; + const char *start, *end, *last; + GData *attribs; + char *type; + gboolean images = FALSE; + + last = msg; + while (last && *last && purple_markup_find_tag("img", last, &start, + &end, &attribs)) { + PurpleStoredImage *image = NULL; + const char *id; + + /* Check if there is text before image */ + if (start - last) { + char *text, *tmp; + p = silc_mime_alloc(); + + /* Add content type */ + silc_mime_add_field(p, "Content-Type", + "text/plain; charset=utf-8"); + + tmp = g_strndup(last, start - last); + text = purple_unescape_html(tmp); + g_free(tmp); + /* Add text */ + silc_mime_add_data(p, text, strlen(text)); + g_free(text); + + if (!parts) + parts = silc_dlist_init(); + silc_dlist_add(parts, p); + } + + id = g_datalist_get_data(&attribs, "id"); + if (id && (image = purple_imgstore_find_by_id(atoi(id)))) { + unsigned long imglen = purple_imgstore_get_size(image); + gconstpointer img = purple_imgstore_get_data(image); + + p = silc_mime_alloc(); + + /* Add content type */ + type = silcpurple_file2mime(purple_imgstore_get_filename(image)); + if (!type) { + g_datalist_clear(&attribs); + last = end + 1; + continue; + } + silc_mime_add_field(p, "Content-Type", type); + silc_free(type); + + /* Add content transfer encoding */ + silc_mime_add_field(p, "Content-Transfer-Encoding", "binary"); + + /* Add image data */ + silc_mime_add_data(p, img, imglen); + + if (!parts) + parts = silc_dlist_init(); + silc_dlist_add(parts, p); + images = TRUE; + } + + g_datalist_clear(&attribs); + + /* Continue after tag */ + last = end + 1; + } + + /* Check for text after the image(s) */ + if (images && last && *last) { + char *tmp = purple_unescape_html(last); + p = silc_mime_alloc(); + + /* Add content type */ + silc_mime_add_field(p, "Content-Type", + "text/plain; charset=utf-8"); + + /* Add text */ + silc_mime_add_data(p, tmp, strlen(tmp)); + g_free(tmp); + + if (!parts) + parts = silc_dlist_init(); + silc_dlist_add(parts, p); + } + + /* If there weren't any images, don't return anything. */ + if (!images) { + if (parts) + silc_dlist_uninit(parts); + return NULL; + } + + if (silc_dlist_count(parts) > 1) { + /* Multipart MIME message */ + char b[32]; + mime = silc_mime_alloc(); + silc_mime_add_field(mime, "MIME-Version", "1.0"); + g_snprintf(b, sizeof(b), "b%4X%4X", + (unsigned int)time(NULL), + silc_dlist_count(parts)); + silc_mime_set_multipart(mime, "mixed", b); + silc_dlist_start(parts); + while ((p = silc_dlist_get(parts)) != SILC_LIST_END) + silc_mime_add_multipart(mime, p); + } else { + /* Simple MIME message */ + silc_dlist_start(parts); + mime = silc_dlist_get(parts); + silc_mime_add_field(mime, "MIME-Version", "1.0"); + } + + *mflags &= ~SILC_MESSAGE_FLAG_UTF8; + *mflags |= SILC_MESSAGE_FLAG_DATA; + + /* Encode message. Fragment if it is too large */ + list = silc_mime_encode_partial(mime, 0xfc00); + + silc_dlist_uninit(parts); + + /* Added multiparts gets freed here */ + silc_mime_free(mime); + + return list; +} + +#endif /* HAVE_SILCMIME_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/silc10/wb.c Mon Jun 18 01:48:35 2007 +0000 @@ -0,0 +1,517 @@ +/* + + wb.c + + Author: Pekka Riikonen <priikone@silcnet.org> + + Copyright (C) 2005 Pekka Riikonen + + 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; version 2 of the License. + + 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. + +*/ + +#include "silcincludes.h" +#include "silcclient.h" +#include "silcpurple.h" +#include "wb.h" + +/* + SILC Whiteboard packet: + + 1 byte command + 2 bytes width + 2 bytes height + 4 bytes brush color + 2 bytes brush size + n bytes data + + Data: + + 4 bytes x + 4 bytes y + + Commands: + + 0x01 draw + 0x02 clear + + MIME: + + MIME-Version: 1.0 + Content-Type: application/x-wb + Content-Transfer-Encoding: binary + +*/ + +#define SILCPURPLE_WB_MIME "MIME-Version: 1.0\r\nContent-Type: application/x-wb\r\nContent-Transfer-Encoding: binary\r\n\r\n" +#define SILCPURPLE_WB_HEADER strlen(SILCPURPLE_WB_MIME) + 11 + +#define SILCPURPLE_WB_WIDTH 500 +#define SILCPURPLE_WB_HEIGHT 400 +#define SILCPURPLE_WB_WIDTH_MAX 1024 +#define SILCPURPLE_WB_HEIGHT_MAX 1024 + +/* Commands */ +typedef enum { + SILCPURPLE_WB_DRAW = 0x01, + SILCPURPLE_WB_CLEAR = 0x02, +} SilcPurpleWbCommand; + +/* Brush size */ +typedef enum { + SILCPURPLE_WB_BRUSH_SMALL = 2, + SILCPURPLE_WB_BRUSH_MEDIUM = 5, + SILCPURPLE_WB_BRUSH_LARGE = 10, +} SilcPurpleWbBrushSize; + +/* Brush color (XXX Purple should provide default colors) */ +typedef enum { + SILCPURPLE_WB_COLOR_BLACK = 0, + SILCPURPLE_WB_COLOR_RED = 13369344, + SILCPURPLE_WB_COLOR_GREEN = 52224, + SILCPURPLE_WB_COLOR_BLUE = 204, + SILCPURPLE_WB_COLOR_YELLOW = 15658496, + SILCPURPLE_WB_COLOR_ORANGE = 16737792, + SILCPURPLE_WB_COLOR_CYAN = 52428, + SILCPURPLE_WB_COLOR_VIOLET = 5381277, + SILCPURPLE_WB_COLOR_PURPLE = 13369548, + SILCPURPLE_WB_COLOR_TAN = 12093547, + SILCPURPLE_WB_COLOR_BROWN = 5256485, + SILCPURPLE_WB_COLOR_GREY = 11184810, + SILCPURPLE_WB_COLOR_WHITE = 16777215, +} SilcPurpleWbColor; + +typedef struct { + int type; /* 0 = buddy, 1 = channel */ + union { + SilcClientEntry client; + SilcChannelEntry channel; + } u; + int width; + int height; + int brush_size; + int brush_color; +} *SilcPurpleWb; + +/* Initialize whiteboard */ + +PurpleWhiteboard *silcpurple_wb_init(SilcPurple sg, SilcClientEntry client_entry) +{ + SilcClientConnection conn; + PurpleWhiteboard *wb; + SilcPurpleWb wbs; + + conn = sg->conn; + wb = purple_whiteboard_get_session(sg->account, client_entry->nickname); + if (!wb) + wb = purple_whiteboard_create(sg->account, client_entry->nickname, 0); + if (!wb) + return NULL; + + if (!wb->proto_data) { + wbs = silc_calloc(1, sizeof(*wbs)); + if (!wbs) + return NULL; + wbs->type = 0; + wbs->u.client = client_entry; + wbs->width = SILCPURPLE_WB_WIDTH; + wbs->height = SILCPURPLE_WB_HEIGHT; + wbs->brush_size = SILCPURPLE_WB_BRUSH_SMALL; + wbs->brush_color = SILCPURPLE_WB_COLOR_BLACK; + wb->proto_data = wbs; + + /* Start the whiteboard */ + purple_whiteboard_start(wb); + purple_whiteboard_clear(wb); + } + + return wb; +} + +PurpleWhiteboard *silcpurple_wb_init_ch(SilcPurple sg, SilcChannelEntry channel) +{ + PurpleWhiteboard *wb; + SilcPurpleWb wbs; + + wb = purple_whiteboard_get_session(sg->account, channel->channel_name); + if (!wb) + wb = purple_whiteboard_create(sg->account, channel->channel_name, 0); + if (!wb) + return NULL; + + if (!wb->proto_data) { + wbs = silc_calloc(1, sizeof(*wbs)); + if (!wbs) + return NULL; + wbs->type = 1; + wbs->u.channel = channel; + wbs->width = SILCPURPLE_WB_WIDTH; + wbs->height = SILCPURPLE_WB_HEIGHT; + wbs->brush_size = SILCPURPLE_WB_BRUSH_SMALL; + wbs->brush_color = SILCPURPLE_WB_COLOR_BLACK; + wb->proto_data = wbs; + + /* Start the whiteboard */ + purple_whiteboard_start(wb); + purple_whiteboard_clear(wb); + } + + return wb; +} + +static void +silcpurple_wb_parse(SilcPurpleWb wbs, PurpleWhiteboard *wb, + unsigned char *message, SilcUInt32 message_len) +{ + SilcUInt8 command; + SilcUInt16 width, height, brush_size; + SilcUInt32 brush_color, x, y, dx, dy; + SilcBufferStruct buf; + int ret; + + /* Parse the packet */ + silc_buffer_set(&buf, message, message_len); + ret = silc_buffer_unformat(&buf, + SILC_STR_UI_CHAR(&command), + SILC_STR_UI_SHORT(&width), + SILC_STR_UI_SHORT(&height), + SILC_STR_UI_INT(&brush_color), + SILC_STR_UI_SHORT(&brush_size), + SILC_STR_END); + if (ret < 0) + return; + silc_buffer_pull(&buf, ret); + + /* Update whiteboard if its dimensions changed */ + if (width != wbs->width || height != wbs->height) + silcpurple_wb_set_dimensions(wb, height, width); + + if (command == SILCPURPLE_WB_DRAW) { + /* Parse data and draw it */ + ret = silc_buffer_unformat(&buf, + SILC_STR_UI_INT(&dx), + SILC_STR_UI_INT(&dy), + SILC_STR_END); + if (ret < 0) + return; + silc_buffer_pull(&buf, 8); + x = dx; + y = dy; + while (buf.len > 0) { + ret = silc_buffer_unformat(&buf, + SILC_STR_UI_INT(&dx), + SILC_STR_UI_INT(&dy), + SILC_STR_END); + if (ret < 0) + return; + silc_buffer_pull(&buf, 8); + + purple_whiteboard_draw_line(wb, x, y, x + dx, y + dy, + brush_color, brush_size); + x += dx; + y += dy; + } + } + + if (command == SILCPURPLE_WB_CLEAR) + purple_whiteboard_clear(wb); +} + +typedef struct { + unsigned char *message; + SilcUInt32 message_len; + SilcPurple sg; + SilcClientEntry sender; + SilcChannelEntry channel; +} *SilcPurpleWbRequest; + +static void +silcpurple_wb_request_cb(SilcPurpleWbRequest req, gint id) +{ + PurpleWhiteboard *wb; + + if (id != 1) + goto out; + + if (!req->channel) + wb = silcpurple_wb_init(req->sg, req->sender); + else + wb = silcpurple_wb_init_ch(req->sg, req->channel); + + silcpurple_wb_parse(wb->proto_data, wb, req->message, req->message_len); + + out: + silc_free(req->message); + silc_free(req); +} + +static void +silcpurple_wb_request(SilcClient client, const unsigned char *message, + SilcUInt32 message_len, SilcClientEntry sender, + SilcChannelEntry channel) +{ + char tmp[128]; + SilcPurpleWbRequest req; + PurpleConnection *gc; + SilcPurple sg; + + gc = client->application; + sg = gc->proto_data; + + /* Open whiteboard automatically if requested */ + if (purple_account_get_bool(sg->account, "open-wb", FALSE)) { + PurpleWhiteboard *wb; + + if (!channel) + wb = silcpurple_wb_init(sg, sender); + else + wb = silcpurple_wb_init_ch(sg, channel); + + silcpurple_wb_parse(wb->proto_data, wb, (unsigned char *)message, + message_len); + return; + } + + if (!channel) { + g_snprintf(tmp, sizeof(tmp), + _("%s sent message to whiteboard. Would you like " + "to open the whiteboard?"), sender->nickname); + } else { + g_snprintf(tmp, sizeof(tmp), + _("%s sent message to whiteboard on %s channel. " + "Would you like to open the whiteboard?"), + sender->nickname, channel->channel_name); + } + + req = silc_calloc(1, sizeof(*req)); + if (!req) + return; + req->message = silc_memdup(message, message_len); + req->message_len = message_len; + req->sender = sender; + req->channel = channel; + req->sg = sg; + + purple_request_action(gc, _("Whiteboard"), tmp, NULL, 1, + sg->account, sender->nickname, NULL, req, 2, + _("Yes"), G_CALLBACK(silcpurple_wb_request_cb), + _("No"), G_CALLBACK(silcpurple_wb_request_cb)); +} + +/* Process incoming whiteboard message */ + +void silcpurple_wb_receive(SilcClient client, SilcClientConnection conn, + SilcClientEntry sender, SilcMessagePayload payload, + SilcMessageFlags flags, const unsigned char *message, + SilcUInt32 message_len) +{ + SilcPurple sg; + PurpleConnection *gc; + PurpleWhiteboard *wb; + SilcPurpleWb wbs; + + gc = client->application; + sg = gc->proto_data; + + wb = purple_whiteboard_get_session(sg->account, sender->nickname); + if (!wb) { + /* Ask user if they want to open the whiteboard */ + silcpurple_wb_request(client, message, message_len, + sender, NULL); + return; + } + + wbs = wb->proto_data; + silcpurple_wb_parse(wbs, wb, (unsigned char *)message, message_len); +} + +/* Process incoming whiteboard message on channel */ + +void silcpurple_wb_receive_ch(SilcClient client, SilcClientConnection conn, + SilcClientEntry sender, SilcChannelEntry channel, + SilcMessagePayload payload, + SilcMessageFlags flags, + const unsigned char *message, + SilcUInt32 message_len) +{ + SilcPurple sg; + PurpleConnection *gc; + PurpleWhiteboard *wb; + SilcPurpleWb wbs; + + gc = client->application; + sg = gc->proto_data; + + wb = purple_whiteboard_get_session(sg->account, channel->channel_name); + if (!wb) { + /* Ask user if they want to open the whiteboard */ + silcpurple_wb_request(client, message, message_len, + sender, channel); + return; + } + + wbs = wb->proto_data; + silcpurple_wb_parse(wbs, wb, (unsigned char *)message, message_len); +} + +/* Send whiteboard message */ + +void silcpurple_wb_send(PurpleWhiteboard *wb, GList *draw_list) +{ + SilcPurpleWb wbs = wb->proto_data; + SilcBuffer packet; + GList *list; + int len; + PurpleConnection *gc; + SilcPurple sg; + + g_return_if_fail(draw_list); + gc = purple_account_get_connection(wb->account); + g_return_if_fail(gc); + sg = gc->proto_data; + g_return_if_fail(sg); + + len = SILCPURPLE_WB_HEADER; + for (list = draw_list; list; list = list->next) + len += 4; + + packet = silc_buffer_alloc_size(len); + if (!packet) + return; + + /* Assmeble packet */ + silc_buffer_format(packet, + SILC_STR_UI32_STRING(SILCPURPLE_WB_MIME), + SILC_STR_UI_CHAR(SILCPURPLE_WB_DRAW), + SILC_STR_UI_SHORT(wbs->width), + SILC_STR_UI_SHORT(wbs->height), + SILC_STR_UI_INT(wbs->brush_color), + SILC_STR_UI_SHORT(wbs->brush_size), + SILC_STR_END); + silc_buffer_pull(packet, SILCPURPLE_WB_HEADER); + for (list = draw_list; list; list = list->next) { + silc_buffer_format(packet, + SILC_STR_UI_INT(GPOINTER_TO_INT(list->data)), + SILC_STR_END); + silc_buffer_pull(packet, 4); + } + + /* Send the message */ + if (wbs->type == 0) { + /* Private message */ + silc_client_send_private_message(sg->client, sg->conn, + wbs->u.client, + SILC_MESSAGE_FLAG_DATA, + packet->head, len, TRUE); + } else if (wbs->type == 1) { + /* Channel message. Channel private keys are not supported. */ + silc_client_send_channel_message(sg->client, sg->conn, + wbs->u.channel, NULL, + SILC_MESSAGE_FLAG_DATA, + packet->head, len, TRUE); + } + + silc_buffer_free(packet); +} + +/* Purple Whiteboard operations */ + +void silcpurple_wb_start(PurpleWhiteboard *wb) +{ + /* Nothing here. Everything is in initialization */ +} + +void silcpurple_wb_end(PurpleWhiteboard *wb) +{ + silc_free(wb->proto_data); + wb->proto_data = NULL; +} + +void silcpurple_wb_get_dimensions(const PurpleWhiteboard *wb, int *width, int *height) +{ + SilcPurpleWb wbs = wb->proto_data; + *width = wbs->width; + *height = wbs->height; +} + +void silcpurple_wb_set_dimensions(PurpleWhiteboard *wb, int width, int height) +{ + SilcPurpleWb wbs = wb->proto_data; + wbs->width = width > SILCPURPLE_WB_WIDTH_MAX ? SILCPURPLE_WB_WIDTH_MAX : + width; + wbs->height = height > SILCPURPLE_WB_HEIGHT_MAX ? SILCPURPLE_WB_HEIGHT_MAX : + height; + + /* Update whiteboard */ + purple_whiteboard_set_dimensions(wb, wbs->width, wbs->height); +} + +void silcpurple_wb_get_brush(const PurpleWhiteboard *wb, int *size, int *color) +{ + SilcPurpleWb wbs = wb->proto_data; + *size = wbs->brush_size; + *color = wbs->brush_color; +} + +void silcpurple_wb_set_brush(PurpleWhiteboard *wb, int size, int color) +{ + SilcPurpleWb wbs = wb->proto_data; + wbs->brush_size = size; + wbs->brush_color = color; + + /* Update whiteboard */ + purple_whiteboard_set_brush(wb, size, color); +} + +void silcpurple_wb_clear(PurpleWhiteboard *wb) +{ + SilcPurpleWb wbs = wb->proto_data; + SilcBuffer packet; + int len; + PurpleConnection *gc; + SilcPurple sg; + + gc = purple_account_get_connection(wb->account); + g_return_if_fail(gc); + sg = gc->proto_data; + g_return_if_fail(sg); + + len = SILCPURPLE_WB_HEADER; + packet = silc_buffer_alloc_size(len); + if (!packet) + return; + + /* Assmeble packet */ + silc_buffer_format(packet, + SILC_STR_UI32_STRING(SILCPURPLE_WB_MIME), + SILC_STR_UI_CHAR(SILCPURPLE_WB_CLEAR), + SILC_STR_UI_SHORT(wbs->width), + SILC_STR_UI_SHORT(wbs->height), + SILC_STR_UI_INT(wbs->brush_color), + SILC_STR_UI_SHORT(wbs->brush_size), + SILC_STR_END); + + /* Send the message */ + if (wbs->type == 0) { + /* Private message */ + silc_client_send_private_message(sg->client, sg->conn, + wbs->u.client, + SILC_MESSAGE_FLAG_DATA, + packet->head, len, TRUE); + } else if (wbs->type == 1) { + /* Channel message */ + silc_client_send_channel_message(sg->client, sg->conn, + wbs->u.channel, NULL, + SILC_MESSAGE_FLAG_DATA, + packet->head, len, TRUE); + } + + silc_buffer_free(packet); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/silc10/wb.h Mon Jun 18 01:48:35 2007 +0000 @@ -0,0 +1,49 @@ +/* + + silcpurple.h + + Author: Pekka Riikonen <priikone@silcnet.org> + + Copyright (C) 2005 Pekka Riikonen + + 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; version 2 of the License. + + 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. + +*/ + +#ifndef SILCPURPLE_WB_H +#define SILCPURPLE_WB_H + +#include "silcpurple.h" +#include "whiteboard.h" + +PurpleWhiteboard * +silcpurple_wb_init(SilcPurple sg, SilcClientEntry client_entry); +PurpleWhiteboard * +silcpurple_wb_init_ch(SilcPurple sg, SilcChannelEntry channel); +void silcpurple_wb_receive(SilcClient client, SilcClientConnection conn, + SilcClientEntry sender, SilcMessagePayload payload, + SilcMessageFlags flags, const unsigned char *message, + SilcUInt32 message_len); +void silcpurple_wb_receive_ch(SilcClient client, SilcClientConnection conn, + SilcClientEntry sender, SilcChannelEntry channel, + SilcMessagePayload payload, + SilcMessageFlags flags, + const unsigned char *message, + SilcUInt32 message_len); +void silcpurple_wb_start(PurpleWhiteboard *wb); +void silcpurple_wb_end(PurpleWhiteboard *wb); +void silcpurple_wb_get_dimensions(const PurpleWhiteboard *wb, int *width, int *height); +void silcpurple_wb_set_dimensions(PurpleWhiteboard *wb, int width, int height); +void silcpurple_wb_get_brush(const PurpleWhiteboard *wb, int *size, int *color); +void silcpurple_wb_set_brush(PurpleWhiteboard *wb, int size, int color); +void silcpurple_wb_send(PurpleWhiteboard *wb, GList *draw_list); +void silcpurple_wb_clear(PurpleWhiteboard *wb); + +#endif /* SILCPURPLE_WB_H */
--- a/libpurple/protocols/simple/simple.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/simple/simple.c Mon Jun 18 01:48:35 2007 +0000 @@ -1243,7 +1243,7 @@ foundxpidf = TRUE; if(tmp2) { *tmp2 = ','; - tmp = tmp2; + tmp = tmp2 + 1; while(*tmp == ' ') tmp++; } else tmp = 0;
--- a/libpurple/protocols/toc/PROTOCOL Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/toc/PROTOCOL Mon Jun 18 01:48:35 2007 +0000 @@ -14,10 +14,10 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# Note from Jim Duchek, gaim maintainer -- this may not be the latest -# version of this document, I provide it as a service. Download a copy -# of TiK (http://www.aim.aol.com/tik/) for the latest version of this -# doc. +# Note from Jim Duchek, former libpurple maintainer -- this may not be +# the latest version of this document, I provide it as a service. +# Download a copy of TiK (http://www.aim.aol.com/tik/) for the latest +# version of this doc. # Note from Eric Warmenhoven, random guy -- this appears to be the last # published version of the protocol, and AOL has stopped hosting the TiK
--- a/libpurple/protocols/yahoo/yahoo.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/yahoo/yahoo.c Mon Jun 18 01:48:35 2007 +0000 @@ -2310,7 +2310,7 @@ * are you trying to pull? */ guchar *start; - purple_debug_warning("yahoo", "Error in YMSG stream, got something not a YMSG packet!"); + purple_debug_warning("yahoo", "Error in YMSG stream, got something not a YMSG packet!\n"); start = memchr(yd->rxqueue + 1, 'Y', yd->rxlen - 1); if (start) { @@ -2377,7 +2377,11 @@ } if (source < 0) { - purple_connection_error(gc, _("Unable to connect.")); + gchar *tmp; + tmp = g_strdup_printf(_("Could not establish a connection with the server:\n%s"), + error_message); + purple_connection_error(gc, tmp); + g_free(tmp); return; } @@ -2405,7 +2409,11 @@ } if (source < 0) { - purple_connection_error(gc, _("Unable to connect.")); + gchar *tmp; + tmp = g_strdup_printf(_("Could not establish a connection with the server:\n%s"), + error_message); + purple_connection_error(gc, tmp); + g_free(tmp); return; } @@ -2507,12 +2515,16 @@ if (written < 0 && errno == EAGAIN) written = 0; else if (written <= 0) { + gchar *tmp; g_free(yd->auth); yd->auth = NULL; if (gc->inpa) purple_input_remove(gc->inpa); gc->inpa = 0; - purple_connection_error(gc, _("Unable to connect.")); + tmp = g_strdup_printf(_("Lost connection with %s:\n%s"), + "login.yahoo.com:80", strerror(errno)); + purple_connection_error(gc, tmp); + g_free(tmp); return; } @@ -2533,7 +2545,11 @@ PurpleConnection *gc = data; if (source < 0) { - purple_connection_error(gc, _("Unable to connect.")); + gchar *tmp; + tmp = g_strdup_printf(_("Could not establish a connection with %s:\n%s"), + "login.yahoo.com:80", error_message); + purple_connection_error(gc, tmp); + g_free(tmp); return; } @@ -2616,8 +2632,7 @@ if (error_message != NULL) { - /* TODO: Include error_message in the message below */ - purple_connection_error(gc, _("Unable to connect.")); + purple_connection_error(gc, error_message); return; }
--- a/libpurple/protocols/yahoo/yahoo_packet.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/yahoo/yahoo_packet.c Mon Jun 18 01:48:35 2007 +0000 @@ -110,6 +110,29 @@ return len; } +/* + * 'len' is the value given to us by the server that is supposed to + * be the length of 'data'. But apparently there's a time when this + * length is incorrect. Christopher Layne thinks it might be a bug + * in their server code. + * + * The following information is from Christopher: + * + * It sometimes happens when Yahoo! sends a packet continuation within + * chat. Sometimes when joining a large chatroom the initial + * SERVICE_CHATJOIN packet will be so large that it will need to be + * split into multiple packets. That's fine, except that the length + * of the second packet is wrong. The packet has the same length as + * the first packet, and the length given in the header is the same, + * however the actual data in the packet is shorter than this length. + * So half of the packet contains good, valid data, and then the rest + * of the packet is junk. Luckily there is a null terminator after + * the valid data and before the invalid data. + * + * What does all this mean? It means that we parse through the data + * pulling out key/value pairs until we've parsed 'len' bytes, or until + * we run into a null terminator, whichever comes first. + */ void yahoo_packet_read(struct yahoo_packet *pkt, const guchar *data, int len) { int pos = 0; @@ -121,18 +144,8 @@ while (pos + 1 < len) { - /* this is weird, and in one of the chat packets, and causes us to - * think all the values are keys and all the keys are values after - * this point if we don't handle it */ - if (data[pos] == '\0') { - while (pos + 1 < len) { - if (data[pos] == 0xc0 && data[pos + 1] == 0x80) - break; - pos++; - } - pos += 2; - continue; - } + if (data[pos] == '\0') + break; pair = g_new0(struct yahoo_pair, 1);
--- a/libpurple/protocols/zephyr/zephyr.h Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/protocols/zephyr/zephyr.h Mon Jun 18 01:48:35 2007 +0000 @@ -109,7 +109,7 @@ ZChecksum_t z_checksum; int z_num_other_fields; char *z_other_fields[Z_MAXOTHERFIELDS]; - void *z_message; + caddr_t z_message; int z_message_len; } ZNotice_t;
--- a/libpurple/proxy.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/proxy.c Mon Jun 18 01:48:35 2007 +0000 @@ -559,7 +559,7 @@ int len, headers_len, status = 0; gboolean error; PurpleProxyConnectData *connect_data = data; - guchar *p; + char *p; gsize max_read; if (connect_data->read_buffer == NULL) @@ -569,7 +569,7 @@ connect_data->read_len = 0; } - p = connect_data->read_buffer + connect_data->read_len; + p = (char *)connect_data->read_buffer + connect_data->read_len; max_read = connect_data->read_buf_len - connect_data->read_len - 1; len = read(connect_data->fd, p, max_read); @@ -596,11 +596,11 @@ connect_data->read_len += len; p[len] = '\0'; - p = (guchar *)g_strstr_len((const gchar *)connect_data->read_buffer, + p = g_strstr_len((const gchar *)connect_data->read_buffer, connect_data->read_len, "\r\n\r\n"); if (p != NULL) { *p = '\0'; - headers_len = (p - connect_data->read_buffer) + 4; + headers_len = (p - (char *)connect_data->read_buffer) + 4; } else if(len == max_read) headers_len = len; else @@ -610,34 +610,34 @@ if (!error) { int major; - p = connect_data->read_buffer + 5; - major = strtol((const char *)p, (char**)&p, 10); + p = (char *)connect_data->read_buffer + 5; + major = strtol(p, &p, 10); error = (major == 0) || (*p != '.'); if(!error) { int minor; p++; - minor = strtol((const char *)p, (char **)&p, 10); + minor = strtol(p, &p, 10); error = (*p != ' '); if(!error) { p++; - status = strtol((const char *)p, (char **)&p, 10); + status = strtol(p, &p, 10); error = (*p != ' '); } } } /* Read the contents */ - p = (guchar *)g_strrstr((const gchar *)connect_data->read_buffer, "Content-Length: "); + p = g_strrstr((const gchar *)connect_data->read_buffer, "Content-Length: "); if (p != NULL) { gchar *tmp; int len = 0; char tmpc; p += strlen("Content-Length: "); - tmp = strchr((const char *)p, '\r'); + tmp = strchr(p, '\r'); if(tmp) *tmp = '\0'; - len = atoi((const char *)p); + len = atoi(p); if(tmp) *tmp = '\r'; @@ -1059,6 +1059,22 @@ } } +static gboolean +s5_ensure_buffer_length(PurpleProxyConnectData *connect_data, int len) +{ + if(connect_data->read_len < len) { + if(connect_data->read_buf_len < len) { + /* it's not just that we haven't read enough, it's that we haven't tried to read enough yet */ + purple_debug_info("s5", "reallocing from %d to %d\n", connect_data->read_buf_len, len); + connect_data->read_buf_len = len; + connect_data->read_buffer = g_realloc(connect_data->read_buffer, connect_data->read_buf_len); + } + return FALSE; + } + + return TRUE; +} + static void s5_canread_again(gpointer data, gint source, PurpleInputCondition cond) { @@ -1067,7 +1083,7 @@ int len; if (connect_data->read_buffer == NULL) { - connect_data->read_buf_len = 512; + connect_data->read_buf_len = 4; connect_data->read_buffer = g_malloc(connect_data->read_buf_len); connect_data->read_len = 0; } @@ -1075,8 +1091,6 @@ dest = connect_data->read_buffer + connect_data->read_len; buf = connect_data->read_buffer; - purple_debug_info("socks5 proxy", "Able to read again.\n"); - len = read(connect_data->fd, dest, (connect_data->read_buf_len - connect_data->read_len)); if (len == 0) @@ -1119,33 +1133,31 @@ /* Skip past BND.ADDR */ switch(buf[3]) { case 0x01: /* the address is a version-4 IP address, with a length of 4 octets */ - if(connect_data->read_len < 4 + 4) + if(!s5_ensure_buffer_length(connect_data, 4 + 4)) return; buf += 4 + 4; break; case 0x03: /* the address field contains a fully-qualified domain name. The first octet of the address field contains the number of octets of name that follow, there is no terminating NUL octet. */ - if(connect_data->read_len < 4 + 1) + if(!s5_ensure_buffer_length(connect_data, 4 + 1)) return; - buf += 4 + 1; - if(connect_data->read_len < 4 + 1 + buf[0]) + buf += 4; + if(!s5_ensure_buffer_length(connect_data, 4 + 1 + buf[0])) return; - buf += buf[0]; + buf += buf[0] + 1; break; case 0x04: /* the address is a version-6 IP address, with a length of 16 octets */ - if(connect_data->read_len < 4 + 16) + if(!s5_ensure_buffer_length(connect_data, 4 + 16)) return; buf += 4 + 16; break; } - if(connect_data->read_len < (buf - connect_data->read_buffer) + 2) + /* Skip past BND.PORT */ + if(!s5_ensure_buffer_length(connect_data, (buf - connect_data->read_buffer) + 2)) return; - /* Skip past BND.PORT */ - buf += 2; - purple_proxy_connect_data_connected(connect_data); }
--- a/libpurple/prpl.h Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/prpl.h Mon Jun 18 01:48:35 2007 +0000 @@ -54,7 +54,9 @@ */ #define NO_BUDDY_ICONS {NULL, 0, 0, 0, 0, 0, 0} +#ifdef HAVE_UNISTD_H #include <unistd.h> +#endif #include "blist.h" #include "conversation.h"
--- a/libpurple/purple-client.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/purple-client.c Mon Jun 18 01:48:35 2007 +0000 @@ -5,7 +5,7 @@ #include <stdlib.h> #include "dbus-purple.h" -#include "purple-client-bindings.h" +#include "purple-client.h" static DBusGConnection *bus; static DBusGProxy *purple_proxy;
--- a/libpurple/purple-remote Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/purple-remote Mon Jun 18 01:48:35 2007 +0000 @@ -31,7 +31,7 @@ return result def show_help(): - print """This program uses DBus to communicate with purple. + print """This program uses D-Bus to communicate with purple. Usage: @@ -94,10 +94,8 @@ def execute(uri): match = re.match(urlregexp, uri) protocol = match.group(2) - if protocol == "xmpp" + if protocol == "xmpp": protocol = "jabber" - if protocol == "aim" or protocol == "icq": - protocol = "oscar" if protocol is not None: protocol = "prpl-" + protocol command = match.group(5)
--- a/libpurple/sslconn.h Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/sslconn.h Mon Jun 18 01:48:35 2007 +0000 @@ -170,6 +170,7 @@ /** * Adds an input watcher for the specified SSL connection. + * Once the SSL handshake is complete, use this to watch for actual data across it. * * @param gsc The SSL connection handle. * @param func The callback function.
--- a/libpurple/status.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/status.c Mon Jun 18 01:48:35 2007 +0000 @@ -1275,6 +1275,7 @@ purple_presence_set_idle(PurplePresence *presence, gboolean idle, time_t idle_time) { gboolean old_idle; + time_t current_time; g_return_if_fail(presence != NULL); @@ -1285,14 +1286,14 @@ presence->idle = idle; presence->idle_time = (idle ? idle_time : 0); + current_time = time(NULL); + if (purple_presence_get_context(presence) == PURPLE_PRESENCE_CONTEXT_BUDDY) { - time_t current_time = time(NULL); - update_buddy_idle(purple_presence_get_buddy(presence), presence, current_time, - old_idle, idle); + old_idle, idle); } - else if(purple_presence_get_context(presence) == PURPLE_PRESENCE_CONTEXT_ACCOUNT) + else if (purple_presence_get_context(presence) == PURPLE_PRESENCE_CONTEXT_ACCOUNT) { PurpleAccount *account; PurpleConnection *gc; @@ -1312,9 +1313,10 @@ msg = g_strdup_printf(_("+++ %s became idle"), purple_account_get_username(account)); else msg = g_strdup_printf(_("+++ %s became unidle"), purple_account_get_username(account)); + purple_log_write(log, PURPLE_MESSAGE_SYSTEM, - purple_account_get_username(account), - idle_time, msg); + purple_account_get_username(account), + (idle ? idle_time : current_time), msg); g_free(msg); } } @@ -1326,7 +1328,7 @@ prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl); if (prpl_info && prpl_info->set_idle) - prpl_info->set_idle(gc, (idle ? (time(NULL) - idle_time) : 0)); + prpl_info->set_idle(gc, (idle ? (current_time - idle_time) : 0)); } }
--- a/libpurple/util.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/util.c Mon Jun 18 01:48:35 2007 +0000 @@ -46,6 +46,7 @@ } website; char *url; + int num_times_redirected; gboolean full; char *user_agent; gboolean http11; @@ -1259,14 +1260,17 @@ pt->dest_tag = y; \ tags = g_list_prepend(tags, pt); \ } \ - xhtml = g_string_append(xhtml, "<" y); \ - c += strlen("<" x ); \ - xhtml = g_string_append(xhtml, innards->str); \ - xhtml = g_string_append_c(xhtml, '>'); \ + if(xhtml) { \ + xhtml = g_string_append(xhtml, "<" y); \ + xhtml = g_string_append(xhtml, innards->str); \ + xhtml = g_string_append_c(xhtml, '>'); \ + } \ c = p + 1; \ } else { \ - xhtml = g_string_append(xhtml, "<"); \ - plain = g_string_append_c(plain, '<'); \ + if(xhtml) \ + xhtml = g_string_append(xhtml, "<"); \ + if(plain) \ + plain = g_string_append_c(plain, '<'); \ c++; \ } \ g_string_free(innards, TRUE); \ @@ -1275,16 +1279,19 @@ if(!g_ascii_strncasecmp(c, "<" x, strlen("<" x)) && \ (*(c+strlen("<" x)) == '>' || \ !g_ascii_strncasecmp(c+strlen("<" x), "/>", 2))) { \ - xhtml = g_string_append(xhtml, "<" y); \ + if(xhtml) \ + xhtml = g_string_append(xhtml, "<" y); \ c += strlen("<" x); \ if(*c != '/') { \ struct purple_parse_tag *pt = g_new0(struct purple_parse_tag, 1); \ pt->src_tag = x; \ pt->dest_tag = y; \ tags = g_list_prepend(tags, pt); \ - xhtml = g_string_append_c(xhtml, '>'); \ + if(xhtml) \ + xhtml = g_string_append_c(xhtml, '>'); \ } else { \ - xhtml = g_string_append(xhtml, "/>");\ + if(xhtml) \ + xhtml = g_string_append(xhtml, "/>");\ } \ c = strchr(c, '>') + 1; \ continue; \ @@ -1294,11 +1301,18 @@ purple_markup_html_to_xhtml(const char *html, char **xhtml_out, char **plain_out) { - GString *xhtml = g_string_new(""); - GString *plain = g_string_new(""); + GString *xhtml = NULL; + GString *plain = NULL; GList *tags = NULL, *tag; const char *c = html; + g_return_if_fail(xhtml_out != NULL || plain_out != NULL); + + if(xhtml_out) + xhtml = g_string_new(""); + if(plain_out) + plain = g_string_new(""); + while(c && *c) { if(*c == '<') { if(*(c+1) == '/') { /* closing tag */ @@ -1314,7 +1328,8 @@ if(tag) { while(tags) { struct purple_parse_tag *pt = tags->data; - g_string_append_printf(xhtml, "</%s>", pt->dest_tag); + if(xhtml) + g_string_append_printf(xhtml, "</%s>", pt->dest_tag); if(tags == tag) break; tags = g_list_remove(tags, pt); @@ -1332,8 +1347,10 @@ if(*end == '>') { c = end+1; } else { - xhtml = g_string_append(xhtml, "<"); - plain = g_string_append_c(plain, '<'); + if(xhtml) + xhtml = g_string_append(xhtml, "<"); + if(plain) + plain = g_string_append_c(plain, '<'); c++; } } @@ -1362,7 +1379,8 @@ ALLOW_TAG("span"); ALLOW_TAG("strong"); ALLOW_TAG("ul"); - + ALLOW_TAG("img"); + /* we skip <HR> because it's not legal in XHTML-IM. However, * we still want to send something sensible, so we put a * linebreak in its place. <BR> also needs special handling @@ -1373,8 +1391,9 @@ !g_ascii_strncasecmp(c+3, "/>", 2) || !g_ascii_strncasecmp(c+3, " />", 3))) { c = strchr(c, '>') + 1; - xhtml = g_string_append(xhtml, "<br/>"); - if(*c != '\n') + if(xhtml) + xhtml = g_string_append(xhtml, "<br/>"); + if(plain && *c != '\n') plain = g_string_append_c(plain, '\n'); continue; } @@ -1384,7 +1403,8 @@ pt->dest_tag = "span"; tags = g_list_prepend(tags, pt); c = strchr(c, '>') + 1; - xhtml = g_string_append(xhtml, "<span style='font-weight: bold;'>"); + if(xhtml) + xhtml = g_string_append(xhtml, "<span style='font-weight: bold;'>"); continue; } if(!g_ascii_strncasecmp(c, "<u>", 3) || !g_ascii_strncasecmp(c, "<underline>", strlen("<underline>"))) { @@ -1393,7 +1413,8 @@ pt->dest_tag = "span"; tags = g_list_prepend(tags, pt); c = strchr(c, '>') + 1; - xhtml = g_string_append(xhtml, "<span style='text-decoration: underline;'>"); + if (xhtml) + xhtml = g_string_append(xhtml, "<span style='text-decoration: underline;'>"); continue; } if(!g_ascii_strncasecmp(c, "<s>", 3) || !g_ascii_strncasecmp(c, "<strike>", strlen("<strike>"))) { @@ -1402,7 +1423,8 @@ pt->dest_tag = "span"; tags = g_list_prepend(tags, pt); c = strchr(c, '>') + 1; - xhtml = g_string_append(xhtml, "<span style='text-decoration: line-through;'>"); + if(xhtml) + xhtml = g_string_append(xhtml, "<span style='text-decoration: line-through;'>"); continue; } if(!g_ascii_strncasecmp(c, "<sub>", 5)) { @@ -1411,7 +1433,8 @@ pt->dest_tag = "span"; tags = g_list_prepend(tags, pt); c = strchr(c, '>') + 1; - xhtml = g_string_append(xhtml, "<span style='vertical-align:sub;'>"); + if(xhtml) + xhtml = g_string_append(xhtml, "<span style='vertical-align:sub;'>"); continue; } if(!g_ascii_strncasecmp(c, "<sup>", 5)) { @@ -1420,7 +1443,8 @@ pt->dest_tag = "span"; tags = g_list_prepend(tags, pt); c = strchr(c, '>') + 1; - xhtml = g_string_append(xhtml, "<span style='vertical-align:super;'>"); + if(xhtml) + xhtml = g_string_append(xhtml, "<span style='vertical-align:super;'>"); continue; } if(!g_ascii_strncasecmp(c, "<font", 5) && (*(c+5) == '>' || *(c+5) == ' ')) { @@ -1514,7 +1538,10 @@ pt->dest_tag = "span"; tags = g_list_prepend(tags, pt); if(style->len) - g_string_append_printf(xhtml, "<span style='%s'>", g_strstrip(style->str)); + { + if(xhtml) + g_string_append_printf(xhtml, "<span style='%s'>", g_strstrip(style->str)); + } else pt->ignore = TRUE; g_string_free(style, TRUE); @@ -1534,7 +1561,8 @@ color = g_string_append_c(color, *q); q++; } - g_string_append_printf(xhtml, "<span style='background: %s;'>", g_strstrip(color->str)); + if(xhtml) + g_string_append_printf(xhtml, "<span style='background: %s;'>", g_strstrip(color->str)); g_string_free(color, TRUE); if ((c = strchr(c, '>')) != NULL) c++; @@ -1555,14 +1583,17 @@ if(!g_ascii_strncasecmp(c, "<!--", strlen("<!--"))) { char *p = strstr(c + strlen("<!--"), "-->"); if(p) { - xhtml = g_string_append(xhtml, "<!--"); + if(xhtml) + xhtml = g_string_append(xhtml, "<!--"); c += strlen("<!--"); continue; } } - xhtml = g_string_append(xhtml, "<"); - plain = g_string_append_c(plain, '<'); + if(xhtml) + xhtml = g_string_append(xhtml, "<"); + if(plain) + plain = g_string_append_c(plain, '<'); c++; } } else if(*c == '&') { @@ -1575,29 +1606,31 @@ g_snprintf(buf, sizeof(buf), "%c", *c); pln = buf; } - xhtml = g_string_append_len(xhtml, c, len); - plain = g_string_append(plain, pln); + if(xhtml) + xhtml = g_string_append_len(xhtml, c, len); + if(plain) + plain = g_string_append(plain, pln); c += len; } else { - xhtml = g_string_append_c(xhtml, *c); - plain = g_string_append_c(plain, *c); + if(xhtml) + xhtml = g_string_append_c(xhtml, *c); + if(plain) + plain = g_string_append_c(plain, *c); c++; } } - tag = tags; - while(tag) { - struct purple_parse_tag *pt = tag->data; - if(!pt->ignore) - g_string_append_printf(xhtml, "</%s>", pt->dest_tag); - tag = tag->next; + if(xhtml) { + for (tag = tags; tag ; tag = tag->next) { + struct purple_parse_tag *pt = tag->data; + if(!pt->ignore) + g_string_append_printf(xhtml, "</%s>", pt->dest_tag); + } } g_list_free(tags); if(xhtml_out) - *xhtml_out = g_strdup(xhtml->str); + *xhtml_out = g_string_free(xhtml, FALSE); if(plain_out) - *plain_out = g_strdup(plain->str); - g_string_free(xhtml, TRUE); - g_string_free(plain, TRUE); + *plain_out = g_string_free(plain, FALSE); } /* The following are probably reasonable changes: @@ -2621,14 +2654,17 @@ if (len >= 4) { - if (!strncmp((char *)data, "BM", 2)) - return "bmp"; - else if (!strncmp((char *)data, "GIF8", 4)) + if (!strncmp((char *)data, "GIF8", 4)) return "gif"; - else if (!strncmp((char *)data, "\xff\xd8\xff\xe0", 4)) + else if (!strncmp((char *)data, "\xff\xd8\xff", 3)) /* 4th may be e0 through ef */ return "jpg"; else if (!strncmp((char *)data, "\x89PNG", 4)) return "png"; + else if (!strncmp((char *)data, "MM", 2) || + !strncmp((char *)data, "II", 2)) + return "tif"; + else if (!strncmp((char *)data, "BM", 2)) + return "bmp"; } return "icon"; @@ -3186,6 +3222,17 @@ g_hash_table_destroy(params); } +/* + * TODO: Should probably add a "gboolean *ret_ishttps" parameter that + * is set to TRUE if this URL is https, otherwise it is set to + * FALSE. But that change will break the API. + * + * This is important for Yahoo! web messenger login. They now + * force https login, and if you access the web messenger login + * page via http then it redirects you to the https version, but + * purple_util_fetch_url() ignores the "https" and attempts to + * fetch the URL via http again, which gets redirected again. + */ gboolean purple_url_parse(const char *url, char **ret_host, int *ret_port, char **ret_path, char **ret_user, char **ret_passwd) @@ -3206,12 +3253,16 @@ g_return_val_if_fail(url != NULL, FALSE); - if ((turl = strstr(url, "http://")) != NULL || - (turl = strstr(url, "HTTP://")) != NULL) + if ((turl = purple_strcasestr(url, "http://")) != NULL) { turl += 7; url = turl; } + else if ((turl = purple_strcasestr(url, "https://")) != NULL) + { + turl += 8; + url = turl; + } /* parse out authentication information if supplied */ /* Only care about @ char BEFORE the first / */ @@ -3291,85 +3342,92 @@ PurpleUtilFetchUrlData *gfud) { gchar *s; - - if ((s = g_strstr_len(data, data_len, "Location: ")) != NULL) + gchar *new_url, *temp_url, *end; + gboolean full; + int len; + + if ((s = g_strstr_len(data, data_len, "Location: ")) == NULL) + /* We're not being redirected */ + return FALSE; + + s += strlen("Location: "); + end = strchr(s, '\r'); + + /* Just in case :) */ + if (end == NULL) + end = strchr(s, '\n'); + + if (end == NULL) + return FALSE; + + len = end - s; + + new_url = g_malloc(len + 1); + strncpy(new_url, s, len); + new_url[len] = '\0'; + + full = gfud->full; + + if (*new_url == '/' || g_strstr_len(new_url, len, "://") == NULL) { - gchar *new_url, *temp_url, *end; - gboolean full; - int len; - - s += strlen("Location: "); - end = strchr(s, '\r'); - - /* Just in case :) */ - if (end == NULL) - end = strchr(s, '\n'); - - if (end == NULL) - return FALSE; - - len = end - s; - - new_url = g_malloc(len + 1); - strncpy(new_url, s, len); - new_url[len] = '\0'; - - full = gfud->full; - - if (*new_url == '/' || g_strstr_len(new_url, len, "://") == NULL) - { - temp_url = new_url; - - new_url = g_strdup_printf("%s:%d%s", gfud->website.address, - gfud->website.port, temp_url); - - g_free(temp_url); - - full = FALSE; - } - - purple_debug_info("util", "Redirecting to %s\n", new_url); - - /* - * Try again, with this new location. This code is somewhat - * ugly, but we need to reuse the gfud because whoever called - * us is holding a reference to it. - */ - g_free(gfud->url); - gfud->url = new_url; - gfud->full = full; - g_free(gfud->request); - gfud->request = NULL; - - purple_input_remove(gfud->inpa); - gfud->inpa = 0; - close(gfud->fd); - gfud->fd = -1; - gfud->request_written = 0; - gfud->len = 0; - gfud->data_len = 0; - - g_free(gfud->website.user); - g_free(gfud->website.passwd); - g_free(gfud->website.address); - g_free(gfud->website.page); - purple_url_parse(new_url, &gfud->website.address, &gfud->website.port, - &gfud->website.page, &gfud->website.user, &gfud->website.passwd); - - gfud->connect_data = purple_proxy_connect(NULL, NULL, - gfud->website.address, gfud->website.port, - url_fetch_connect_cb, gfud); - - if (gfud->connect_data == NULL) - { - purple_util_fetch_url_error(gfud, _("Unable to connect to %s"), - gfud->website.address); - } - + temp_url = new_url; + + new_url = g_strdup_printf("%s:%d%s", gfud->website.address, + gfud->website.port, temp_url); + + g_free(temp_url); + + full = FALSE; + } + + purple_debug_info("util", "Redirecting to %s\n", new_url); + + gfud->num_times_redirected++; + if (gfud->num_times_redirected >= 5) + { + purple_util_fetch_url_error(gfud, + _("Could not open %s: Redirected too many times"), + gfud->url); return TRUE; } - return FALSE; + /* + * Try again, with this new location. This code is somewhat + * ugly, but we need to reuse the gfud because whoever called + * us is holding a reference to it. + */ + g_free(gfud->url); + gfud->url = new_url; + gfud->full = full; + g_free(gfud->request); + gfud->request = NULL; + + purple_input_remove(gfud->inpa); + gfud->inpa = 0; + close(gfud->fd); + gfud->fd = -1; + gfud->request_written = 0; + gfud->len = 0; + gfud->data_len = 0; + + g_free(gfud->website.user); + g_free(gfud->website.passwd); + g_free(gfud->website.address); + g_free(gfud->website.page); + purple_url_parse(new_url, &gfud->website.address, &gfud->website.port, + &gfud->website.page, &gfud->website.user, &gfud->website.passwd); + + gfud->connect_data = purple_proxy_connect(NULL, NULL, + gfud->website.address, gfud->website.port, + url_fetch_connect_cb, gfud); + + if (gfud->connect_data == NULL) + { + purple_util_fetch_url_error(gfud, _("Unable to connect to %s"), + gfud->website.address); + } + + return TRUE; } static size_t
--- a/libpurple/win32/global.mak Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/win32/global.mak Mon Jun 18 01:48:35 2007 +0000 @@ -14,7 +14,7 @@ GTKSPELL_TOP ?= $(WIN32_DEV_TOP)/gtkspell-2.0.6 GTK_TOP ?= $(WIN32_DEV_TOP)/gtk_2_0 GTK_BIN ?= $(GTK_TOP)/bin -HOWL_TOP ?= $(WIN32_DEV_TOP)/howl-1.0.0 +BONJOUR_TOP ?= $(WIN32_DEV_TOP)/Bonjour_SDK LIBXML2_TOP ?= $(WIN32_DEV_TOP)/libxml2 MEANWHILE_TOP ?= $(WIN32_DEV_TOP)/meanwhile-1.0.2 NSPR_TOP ?= $(WIN32_DEV_TOP)/nspr-4.6.4
--- a/libpurple/win32/libc_interface.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/win32/libc_interface.c Mon Jun 18 01:48:35 2007 +0000 @@ -1,6 +1,6 @@ /* * purple - * + * * Copyright (C) 2002-2003, Herman Bloggs <hermanator12002@yahoo.com> * * This program is free software; you can redistribute it and/or modify @@ -74,7 +74,7 @@ int ret; ret = connect( socket, addr, length ); - + if( ret == SOCKET_ERROR ) { errno = WSAGetLastError(); if( errno == WSAEWOULDBLOCK ) @@ -129,6 +129,8 @@ if ((ret = sendto(socket, buf, len, flags, to, tolen) ) == SOCKET_ERROR) { errno = WSAGetLastError(); + if(errno == WSAEWOULDBLOCK || errno == WSAEINPROGRESS) + errno = EAGAIN; return -1; } return ret; @@ -302,7 +304,7 @@ if(wpurple_is_socket(fd)) { if((ret = recv(fd, buf, size, 0)) == SOCKET_ERROR) { errno = WSAGetLastError(); - if(errno == WSAEWOULDBLOCK) + if(errno == WSAEWOULDBLOCK || errno == WSAEINPROGRESS) errno = EAGAIN; return -1; } @@ -330,7 +332,7 @@ if (ret == SOCKET_ERROR) { errno = WSAGetLastError(); - if(errno == WSAEWOULDBLOCK) + if(errno == WSAEWOULDBLOCK || errno == WSAEINPROGRESS) errno = EAGAIN; return -1; } @@ -350,7 +352,7 @@ if((ret = recv(fd, buf, len, flags)) == SOCKET_ERROR) { errno = WSAGetLastError(); - if(errno == WSAEWOULDBLOCK) + if(errno == WSAEWOULDBLOCK || errno == WSAEINPROGRESS) errno = EAGAIN; return -1; } else { @@ -392,7 +394,7 @@ z->tz_minuteswest = _timezone/60; z->tz_dsttime = _daylight; } - + if (p != 0) { _ftime(&timebuffer); p->tv_sec = timebuffer.time; /* seconds since 1-1-1970 */ @@ -1044,7 +1046,7 @@ * 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 */ int @@ -1056,7 +1058,7 @@ wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL); int retval; int save_errno; - + if (wfilename == NULL) { errno = EINVAL; @@ -1072,7 +1074,7 @@ return retval; } else - { + { gchar *cp_filename = g_locale_from_utf8 (filename, -1, NULL, NULL, NULL); int retval; int save_errno;
--- a/libpurple/xmlnode.c Thu Jun 14 19:48:48 2007 +0000 +++ b/libpurple/xmlnode.c Mon Jun 18 01:48:35 2007 +0000 @@ -519,38 +519,38 @@ } static xmlSAXHandler xmlnode_parser_libxml = { - .internalSubset = NULL, - .isStandalone = NULL, - .hasInternalSubset = NULL, - .hasExternalSubset = NULL, - .resolveEntity = NULL, - .getEntity = NULL, - .entityDecl = NULL, - .notationDecl = NULL, - .attributeDecl = NULL, - .elementDecl = NULL, - .unparsedEntityDecl = NULL, - .setDocumentLocator = NULL, - .startDocument = NULL, - .endDocument = NULL, - .startElement = NULL, - .endElement = NULL, - .reference = NULL, - .characters = xmlnode_parser_element_text_libxml, - .ignorableWhitespace = NULL, - .processingInstruction = NULL, - .comment = NULL, - .warning = NULL, - .error = xmlnode_parser_error_libxml, - .fatalError = NULL, - .getParameterEntity = NULL, - .cdataBlock = NULL, - .externalSubset = NULL, - .initialized = XML_SAX2_MAGIC, - ._private = NULL, - .startElementNs = xmlnode_parser_element_start_libxml, - .endElementNs = xmlnode_parser_element_end_libxml, - .serror = NULL + NULL, /* internalSubset */ + NULL, /* isStandalone */ + NULL, /* hasInternalSubset */ + NULL, /* hasExternalSubset */ + NULL, /* resolveEntity */ + NULL, /* getEntity */ + NULL, /* entityDecl */ + NULL, /* notationDecl */ + NULL, /* attributeDecl */ + NULL, /* elementDecl */ + NULL, /* unparsedEntityDecl */ + NULL, /* setDocumentLocator */ + NULL, /* startDocument */ + NULL, /* endDocument */ + NULL, /* startElement */ + NULL, /* endElement */ + NULL, /* reference */ + xmlnode_parser_element_text_libxml, /* characters */ + NULL, /* ignorableWhitespace */ + NULL, /* processingInstruction */ + NULL, /* comment */ + NULL, /* warning */ + xmlnode_parser_error_libxml, /* error */ + NULL, /* fatalError */ + NULL, /* getParameterEntity */ + NULL, /* cdataBlock */ + NULL, /* externalSubset */ + XML_SAX2_MAGIC, /* initialized */ + NULL, /* _private */ + xmlnode_parser_element_start_libxml, /* startElementNs */ + xmlnode_parser_element_end_libxml, /* endElementNs */ + NULL, /* serror */ }; xmlnode *
--- a/pidgin.spec.in Thu Jun 14 19:48:48 2007 +0000 +++ b/pidgin.spec.in Mon Jun 18 01:48:35 2007 +0000 @@ -83,6 +83,7 @@ Summary: Development headers, documentation, and libraries for Pidgin Group: Applications/Internet Requires: pidgin = %{version}, libpurple-devel = %{version} +Requires: gtk2-devel Requires: pkgconfig Obsoletes: gaim-devel Provides: gaim-devel @@ -95,12 +96,19 @@ Obsoletes: gaim-gadugadu Obsoletes: pidgin-tcl < 2.0.0 Obsoletes: pidgin-silc < 2.0.0 +%{?_with_sasl:Requires: cyrus-sasl-plain, cyrus-sasl-md5} %package -n libpurple-devel Summary: Development headers, documentation, and libraries for libpurple Group: Applications/Internet Requires: libpurple = %{version} Requires: pkgconfig +%if "%{_vendor}" == "suse" +# For SuSE: +%{?_with_dbus:Requires: dbus-1-devel >= 0.35} +%else +%{?_with_dbus:Requires: dbus-devel >= 0.35} +%endif %if 0%{?_with_howl:1} || 0%{?_with_avahi:1} %package -n libpurple-bonjour @@ -133,6 +141,7 @@ Summary: Headers etc. for finch stuffs Group: Applications/Internet Requires: finch = %{version}, libpurple-devel = %{version} +Requires: ncurses-devel Requires: pkgconfig %endif @@ -449,6 +458,13 @@ %endif %changelog +* Tue Jun 5 2007 Stu Tomlinson <stu@nosnilmot.com> +- Add missing Requires for gtk2-devel, dbus-devel & ncurses-devel to + appropriate -devel subpackages + +* Sun May 27 2007 Stu Tomlinson <stu@nosnilmot.com> +- add cyrus-sasl-plain & cyrus-sasl-md5 to Requires + * Thu May 24 2007 Stu Tomlinson <stu@nosnilmot.com> - Silence errors from gtk-update-icon-cache - Change Mandriva build dependencies to reflect the correct (lower case)
--- a/pidgin/Makefile.am Thu Jun 14 19:48:48 2007 +0000 +++ b/pidgin/Makefile.am Mon Jun 18 01:48:35 2007 +0000 @@ -193,6 +193,7 @@ -DLIBDIR=\"$(libdir)/pidgin/\" \ -DLOCALEDIR=\"$(datadir)/locale\" \ -DSYSCONFDIR=\"$(sysconfdir)\" \ + -I$(top_builddir)/libpurple \ -I$(top_srcdir)/libpurple/ \ $(GLIB_CFLAGS) \ $(GSTREAMER_CFLAGS) \
--- a/pidgin/Makefile.mingw Thu Jun 14 19:48:48 2007 +0000 +++ b/pidgin/Makefile.mingw Mon Jun 18 01:48:35 2007 +0000 @@ -106,26 +106,22 @@ ## ## LIBRARIES ## -LIBPURPLES = \ - -lpurple \ - -lglib-2.0 \ - -lgthread-2.0 \ - -lgobject-2.0 \ - -lgmodule-2.0 \ + +PIDGIN_LIBS = \ -lintl \ - -lws2_32 \ - -lwinmm \ - -lz - -GTKPURPLES = \ - $(LIBPURPLES) \ + -lglib-2.0 \ + -lgobject-2.0 \ + -lgthread-2.0 \ + -lpurple \ + -lz \ -lidletrack \ -lgtk-win32-2.0 \ -latk-1.0 \ -lpango-1.0 \ -lgdk-win32-2.0 \ -lgdk_pixbuf-2.0 \ - -lgdi32 + -lgdi32 \ + -lwinmm include $(PIDGIN_COMMON_RULES) @@ -159,7 +155,7 @@ $(EXE_OBJECTS) $(PIDGIN_OBJECTS): $(PIDGIN_CONFIG_H) $(PIDGIN_TARGET).dll $(PIDGIN_TARGET).dll.a: $(PURPLE_DLL).a $(PIDGIN_IDLETRACK_DLL).a $(PIDGIN_OBJECTS) - $(CC) -shared $(PIDGIN_OBJECTS) $(LIB_PATHS) $(GTKPURPLES) $(DLL_LD_FLAGS) -Wl,--out-implib,$(PIDGIN_TARGET).dll.a -o $(PIDGIN_TARGET).dll + $(CC) -shared $(PIDGIN_OBJECTS) $(LIB_PATHS) $(PIDGIN_LIBS) $(DLL_LD_FLAGS) -Wl,--output-def,$(PIDGIN_TARGET).def,--out-implib,$(PIDGIN_TARGET).dll.a -o $(PIDGIN_TARGET).dll $(EXE_TARGET).exe: $(PIDGIN_CONFIG_H) $(PIDGIN_DLL).a $(PIDGIN_IDLETRACK_DLL).a $(EXE_OBJECTS) $(CC) $(LDFLAGS) $(EXE_OBJECTS) -o $(EXE_TARGET).exe
--- a/pidgin/gtkaccount.c Thu Jun 14 19:48:48 2007 +0000 +++ b/pidgin/gtkaccount.c Mon Jun 18 01:48:35 2007 +0000 @@ -184,6 +184,7 @@ gtk_size_group_add_widget(dialog->sg, label); gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); + gtk_label_set_mnemonic_widget(GTK_LABEL(label), widget); gtk_widget_show(label); gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, PIDGIN_HIG_BORDER); @@ -426,15 +427,18 @@ gtk_widget_ref(dialog->protocol_menu); } - hbox = add_pref_box(dialog, vbox, _("Protocol:"), dialog->protocol_menu); + hbox = add_pref_box(dialog, vbox, _("Pro_tocol:"), dialog->protocol_menu); g_object_set_data(G_OBJECT(dialog->protocol_menu), "container", hbox); gtk_widget_unref(dialog->protocol_menu); /* Screen name */ dialog->screenname_entry = gtk_entry_new(); - - add_pref_box(dialog, vbox, _("Screen name:"), dialog->screenname_entry); +#if GTK_CHECK_VERSION(2,10,0) + g_object_set(G_OBJECT(dialog->screenname_entry), "truncate-multiline", TRUE, NULL); +#endif + + add_pref_box(dialog, vbox, _("Screen _name:"), dialog->screenname_entry); g_signal_connect(G_OBJECT(dialog->screenname_entry), "changed", G_CALLBACK(screenname_changed_cb), dialog); @@ -457,7 +461,7 @@ PurpleAccountUserSplit *split = l->data; char *buf; - buf = g_strdup_printf("%s:", purple_account_user_split_get_text(split)); + buf = g_strdup_printf("_%s:", purple_account_user_split_get_text(split)); entry = gtk_entry_new(); @@ -497,8 +501,8 @@ menu = gtk_option_menu_get_menu(GTK_OPTION_MENU(dialog->protocol_menu)); item = gtk_menu_get_active(GTK_MENU(menu)); protocol = g_object_get_data(G_OBJECT(item), "protocol"); - if (value == NULL && !strcmp(protocol, "prpl-fake") && - !strcmp(purple_account_user_split_get_text(split), _("Domain"))) + if (value == NULL && protocol != NULL && !strcmp(protocol, "prpl-fake") && + !strcmp(purple_account_user_split_get_text(split), _("Domain"))) value = "gmail.com"; if (value != NULL) @@ -516,16 +520,16 @@ gtk_entry_set_visibility(GTK_ENTRY(dialog->password_entry), FALSE); if (gtk_entry_get_invisible_char(GTK_ENTRY(dialog->password_entry)) == '*') gtk_entry_set_invisible_char(GTK_ENTRY(dialog->password_entry), PIDGIN_INVISIBLE_CHAR); - dialog->password_box = add_pref_box(dialog, vbox, _("Password:"), + dialog->password_box = add_pref_box(dialog, vbox, _("_Password:"), dialog->password_entry); /* Alias */ dialog->alias_entry = gtk_entry_new(); - add_pref_box(dialog, vbox, _("Local alias:"), dialog->alias_entry); + add_pref_box(dialog, vbox, _("_Local alias:"), dialog->alias_entry); /* Remember Password */ dialog->remember_pass_check = - gtk_check_button_new_with_label(_("Remember password")); + gtk_check_button_new_with_mnemonic(_("Remember pass_word")); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->remember_pass_check), FALSE); gtk_box_pack_start(GTK_BOX(vbox), dialog->remember_pass_check, @@ -596,12 +600,12 @@ /* New mail notifications */ dialog->new_mail_check = - gtk_check_button_new_with_label(_("New mail notifications")); + gtk_check_button_new_with_mnemonic(_("New _mail notifications")); gtk_box_pack_start(GTK_BOX(vbox), dialog->new_mail_check, FALSE, FALSE, 0); gtk_widget_show(dialog->new_mail_check); /* Buddy icon */ - dialog->icon_check = gtk_check_button_new_with_label(_("Use this buddy icon for this account:")); + dialog->icon_check = gtk_check_button_new_with_mnemonic(_("Use this buddy _icon for this account:")); g_signal_connect(G_OBJECT(dialog->icon_check), "toggled", G_CALLBACK(icon_check_cb), dialog); gtk_widget_show(dialog->icon_check); gtk_box_pack_start(GTK_BOX(vbox), dialog->icon_check, FALSE, FALSE, 0); @@ -698,7 +702,7 @@ PurpleKeyValuePair *kvp; GList *l; char buf[1024]; - char *title; + char *title, *tmp; const char *str_value, *protocol; gboolean bool_value; @@ -755,8 +759,9 @@ purple_account_option_get_default_bool(option)); } - check = gtk_check_button_new_with_label( - purple_account_option_get_text(option)); + tmp = g_strconcat("_", purple_account_option_get_text(option), NULL); + check = gtk_check_button_new_with_mnemonic(tmp); + g_free(tmp); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), bool_value); @@ -788,7 +793,7 @@ entry = gtk_entry_new(); gtk_entry_set_text(GTK_ENTRY(entry), buf); - title = g_strdup_printf("%s:", + title = g_strdup_printf("_%s:", purple_account_option_get_text(option)); add_pref_box(dialog, vbox, title, entry); @@ -826,14 +831,14 @@ menu = gtk_option_menu_get_menu(GTK_OPTION_MENU(dialog->protocol_menu)); item = gtk_menu_get_active(GTK_MENU(menu)); protocol = g_object_get_data(G_OBJECT(item), "protocol"); - if (str_value == NULL && !strcmp(protocol, "prpl-fake") && + if (str_value == NULL && protocol != NULL && !strcmp(protocol, "prpl-fake") && !strcmp(_("Connect server"), purple_account_option_get_text(option))) - str_value = "talk.google.com"; - + str_value = "talk.google.com"; + if (str_value != NULL) gtk_entry_set_text(GTK_ENTRY(entry), str_value); - title = g_strdup_printf("%s:", + title = g_strdup_printf("_%s:", purple_account_option_get_text(option)); add_pref_box(dialog, vbox, title, entry); @@ -894,7 +899,7 @@ gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combo), renderer, "text", 0, NULL); - title = g_strdup_printf("%s:", + title = g_strdup_printf("_%s:", purple_account_option_get_text(option)); add_pref_box(dialog, vbox, title, combo); @@ -2024,19 +2029,26 @@ { GdkPixbuf *pixbuf, *buddyicon = NULL; PurpleStoredImage *img = NULL; + PurplePlugin *prpl; + PurplePluginProtocolInfo *prpl_info = NULL; pixbuf = pidgin_create_prpl_icon(account, PIDGIN_PRPL_ICON_MEDIUM); if ((pixbuf != NULL) && purple_account_is_disconnected(account)) gdk_pixbuf_saturate_and_pixelate(pixbuf, pixbuf, 0.0, FALSE); - if (purple_account_get_bool(account, "use-global-buddyicon", TRUE)) { - if (global_buddyicon != NULL) - buddyicon = g_object_ref(G_OBJECT(global_buddyicon)); - /* This is for when set_account() is called for a single account */ - else + prpl = purple_find_prpl(purple_account_get_protocol_id(account)); + if (prpl != NULL) + prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl); + if (prpl_info != NULL && prpl_info->icon_spec.format != NULL) { + if (purple_account_get_bool(account, "use-global-buddyicon", TRUE)) { + if (global_buddyicon != NULL) + buddyicon = g_object_ref(G_OBJECT(global_buddyicon)); + /* This is for when set_account() is called for a single account */ + else + img = purple_buddy_icons_find_account_icon(account); + } else { img = purple_buddy_icons_find_account_icon(account); - } else { - img = purple_buddy_icons_find_account_icon(account); + } } if (img != NULL) {
--- a/pidgin/gtkblist.c Thu Jun 14 19:48:48 2007 +0000 +++ b/pidgin/gtkblist.c Mon Jun 18 01:48:35 2007 +0000 @@ -108,6 +108,7 @@ static guint visibility_manager_count = 0; static gboolean gtk_blist_obscured = FALSE; +static gboolean editing_blist = FALSE; static GList *pidgin_blist_sort_methods = NULL; static struct pidgin_blist_sort_method *current_sort_method = NULL; @@ -266,8 +267,6 @@ purple_prefs_set_int(PIDGIN_PREFS_ROOT "/blist/width", event->width); purple_prefs_set_int(PIDGIN_PREFS_ROOT "/blist/height", event->height); - gtk_widget_set_size_request(gtkblist->headline_label, - purple_prefs_get_int(PIDGIN_PREFS_ROOT "/blist/width")-25,-1); /* continue to handle event normally */ return FALSE; } @@ -317,6 +316,12 @@ gtk_blist_join_chat(chat); } +static void gtk_blist_renderer_editing_cancelled_cb(GtkCellRenderer *renderer, PurpleBuddyList *list) +{ + editing_blist = FALSE; + pidgin_blist_refresh(list); +} + static void gtk_blist_renderer_editing_started_cb(GtkCellRenderer *renderer, GtkCellEditable *editable, gchar *path_str, @@ -353,10 +358,11 @@ GtkEntry *entry = GTK_ENTRY (editable); gtk_entry_set_text(entry, text); } + editing_blist = TRUE; } static void gtk_blist_renderer_edited_cb(GtkCellRendererText *text_rend, char *arg1, - char *arg2, gpointer nada) + char *arg2, PurpleBuddyList *list) { GtkTreeIter iter; GtkTreePath *path; @@ -364,6 +370,7 @@ PurpleBlistNode *node; PurpleGroup *dest; + editing_blist = FALSE; path = gtk_tree_path_new_from_string (arg1); gtk_tree_model_get_iter (GTK_TREE_MODEL(gtkblist->treemodel), &iter, path); gtk_tree_path_free (path); @@ -408,6 +415,7 @@ default: break; } + pidgin_blist_refresh(list); } static void gtk_blist_menu_alias_cb(GtkWidget *w, PurpleBlistNode *node) @@ -490,7 +498,7 @@ static void gtk_blist_show_onlinehelp_cb() { - purple_notify_uri(NULL, PURPLE_WEBSITE "documentation.php"); + purple_notify_uri(NULL, PURPLE_WEBSITE "documentation"); } static void @@ -1129,10 +1137,10 @@ if (((PurpleBlistNode*)buddy)->parent->child->next && !sub && !contact_expanded) { pidgin_separator(menu); pidgin_append_blist_node_privacy_menu(menu, (PurpleBlistNode *)buddy); - pidgin_new_item_from_stock(menu, _("Alias..."), PIDGIN_STOCK_ALIAS, + pidgin_new_item_from_stock(menu, _("_Alias..."), PIDGIN_STOCK_ALIAS, G_CALLBACK(gtk_blist_menu_alias_cb), contact, 0, 0, NULL); - pidgin_new_item_from_stock(menu, _("Remove"), GTK_STOCK_REMOVE, + pidgin_new_item_from_stock(menu, _("_Remove"), GTK_STOCK_REMOVE, G_CALLBACK(pidgin_blist_remove_cb), contact, 0, 0, NULL); } else if (!sub || contact_expanded) { @@ -1174,7 +1182,7 @@ return FALSE; } if(buddy) - serv_get_info(buddy->account->gc, buddy->name); + gtk_blist_menu_info_cb(NULL, buddy); } else if (event->keyval == GDK_F2) { gtk_blist_menu_alias_cb(tv, node); } @@ -1428,7 +1436,7 @@ prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl); if (prpl && prpl_info->get_info) - serv_get_info(b->account->gc, b->name); + gtk_blist_menu_info_cb(NULL, b); handled = TRUE; } @@ -2726,6 +2734,7 @@ { GtkTreePath *path; int delay; + GdkRectangle rect; /* * When dragging a buddy into a contact, this is the delay before @@ -2741,7 +2750,17 @@ } gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(tv), x, y, &path, NULL, NULL, NULL); - gtk_tree_view_get_cell_area(GTK_TREE_VIEW(tv), path, NULL, >kblist->tip_rect); + gtk_tree_view_get_cell_area(GTK_TREE_VIEW(tv), path, NULL, &rect); + + /* Only autoexpand when in the middle of the cell to avoid annoying un-intended expands */ + if (y < rect.y + (rect.height / 3) || + y > rect.y + (2 * (rect.height /3))) + return FALSE; + + rect.height = rect.height / 3; + rect.y += rect.height; + + gtkblist->tip_rect = rect; if (path) gtk_tree_path_free(path); @@ -2994,7 +3013,14 @@ signon = purple_presence_get_login_time(presence); if (full && PURPLE_BUDDY_IS_ONLINE(b) && signon > 0) { - tmp = purple_str_seconds_to_string(time(NULL) - signon); + if (time(NULL) - signon > 63072000 /* 2 years */) { + /* + * Our local clock must be wrong, show the actual + * date instead of "4 days", etc. + */ + tmp = g_strdup(purple_date_format_long(localtime(&signon))); + } else + tmp = purple_str_seconds_to_string(time(NULL) - signon); purple_notify_user_info_add_pair(user_info, _("Logged In"), tmp); g_free(tmp); } @@ -3244,6 +3270,9 @@ else if (purple_presence_is_idle(p) && size == PIDGIN_STATUS_ICON_SMALL) ret = gtk_widget_render_icon (GTK_WIDGET(gtkblist->treeview), PIDGIN_STOCK_STATUS_AVAILABLE_I, icon_size, "GtkTreeView"); + else if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_INVISIBLE)) + ret = gtk_widget_render_icon(GTK_WIDGET(gtkblist->treeview), PIDGIN_STOCK_STATUS_INVISIBLE, + icon_size, "GtkTreeView"); else ret = gtk_widget_render_icon(GTK_WIDGET(gtkblist->treeview), PIDGIN_STOCK_STATUS_AVAILABLE, icon_size, "GtkTreeView"); @@ -3413,8 +3442,16 @@ "<span color='%s' size='smaller'>%s</span>", dim_grey(), esc, dim_grey(), statustext != NULL ? statustext : ""); - } - + } else if (!PURPLE_BUDDY_IS_ONLINE(b)) { + if (!selected && !statustext) /* We handle selected text later */ + text = g_strdup_printf("<span color='%s'>%s</span>", dim_grey(), esc); + else if (!selected && !text) + text = g_strdup_printf("<span color='%s'>%s</span>\n" + "<span color='%s' size='smaller'>%s</span>", + dim_grey(), esc, dim_grey(), + statustext != NULL ? statustext : ""); + + } /* Not idle and not selected */ else if (!selected && !text) { @@ -3722,8 +3759,11 @@ gboolean pidgin_blist_node_is_contact_expanded(PurpleBlistNode *node) { - if PURPLE_BLIST_NODE_IS_BUDDY(node) + if (PURPLE_BLIST_NODE_IS_BUDDY(node)) { node = node->parent; + if (node == NULL) + return FALSE; + } g_return_val_if_fail(PURPLE_BLIST_NODE_IS_CONTACT(node), FALSE); @@ -4429,7 +4469,8 @@ "markup", NAME_COLUMN, NULL); g_signal_connect(G_OBJECT(rend), "editing-started", G_CALLBACK(gtk_blist_renderer_editing_started_cb), NULL); - g_signal_connect(G_OBJECT(rend), "edited", G_CALLBACK(gtk_blist_renderer_edited_cb), NULL); + g_signal_connect(G_OBJECT(rend), "editing-canceled", G_CALLBACK(gtk_blist_renderer_editing_cancelled_cb), list); + g_signal_connect(G_OBJECT(rend), "edited", G_CALLBACK(gtk_blist_renderer_edited_cb), list); g_object_set(rend, "ypad", 0, "yalign", 0.5, NULL); #if GTK_CHECK_VERSION(2,6,0) g_object_set(rend, "ellipsize", PANGO_ELLIPSIZE_END, NULL); @@ -4724,8 +4765,15 @@ NODE_COLUMN, &new_selection, -1); } - /* we set this up as a timeout, otherwise the blist flickers */ - g_timeout_add(0, (GSourceFunc)do_selection_changed, new_selection); + /* we set this up as a timeout, otherwise the blist flickers ... + * but we don't do it for groups, because it causes total bizarness - + * the previously selected buddy node might rendered at half height. + */ + if ((new_selection != NULL) && PURPLE_BLIST_NODE_IS_GROUP(new_selection)) { + do_selection_changed(new_selection); + } else { + g_timeout_add(0, (GSourceFunc)do_selection_changed, new_selection); + } } static gboolean insert_node(PurpleBuddyList *list, PurpleBlistNode *node, GtkTreeIter *iter) @@ -4764,9 +4812,10 @@ gtk_tree_path_free(newpath); - gtk_tree_store_set(gtkblist->treemodel, iter, - NODE_COLUMN, node, - -1); + if (!editing_blist) + gtk_tree_store_set(gtkblist->treemodel, iter, + NODE_COLUMN, node, + -1); if(node->parent) { GtkTreePath *expand = NULL; @@ -4799,6 +4848,9 @@ g_return_if_fail(node != NULL); + if (editing_blist) + return; + if (PURPLE_BLIST_NODE_IS_GROUP(node)) gnode = node; else if (PURPLE_BLIST_NODE_IS_BUDDY(node)) @@ -4850,7 +4902,7 @@ GROUP_EXPANDER_VISIBLE_COLUMN, TRUE, CONTACT_EXPANDER_VISIBLE_COLUMN, FALSE, BUDDY_ICON_VISIBLE_COLUMN, FALSE, - IDLE_VISIBLE_COLUMN, FALSE, + IDLE_VISIBLE_COLUMN, FALSE, EMBLEM_VISIBLE_COLUMN, FALSE, -1); g_free(title); @@ -4900,6 +4952,9 @@ gboolean biglist = purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/show_buddy_icons"); presence = purple_buddy_get_presence(buddy); + if (editing_blist) + return; + status = pidgin_blist_get_status_icon((PurpleBlistNode*)buddy, PIDGIN_STATUS_ICON_SMALL); @@ -4945,7 +5000,6 @@ idle = i2; } } - gtk_tree_store_set(gtkblist->treemodel, iter, STATUS_ICON_COLUMN, status, STATUS_ICON_VISIBLE_COLUMN, TRUE, @@ -4960,7 +5014,7 @@ CONTACT_EXPANDER_COLUMN, NULL, CONTACT_EXPANDER_VISIBLE_COLUMN, expanded, GROUP_EXPANDER_VISIBLE_COLUMN, FALSE, - -1); + -1); g_free(mark); g_free(idle); @@ -4979,6 +5033,9 @@ PurpleBuddy *buddy; struct _pidgin_blist_node *gtknode; + if (editing_blist) + return; + if (PURPLE_BLIST_NODE_IS_BUDDY(node)) cnode = node->parent; else @@ -5075,6 +5132,9 @@ g_return_if_fail(PURPLE_BLIST_NODE_IS_CHAT(node)); + if (editing_blist) + return; + /* First things first, update the group */ pidgin_blist_update_group(list, node->parent); @@ -5386,12 +5446,25 @@ gtk_container_set_border_width(GTK_CONTAINER(table), 0); gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0); - label = gtk_label_new(_("Screen name:")); + /* Set up stuff for the account box */ + label = gtk_label_new_with_mnemonic(_("_Account:")); gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 0, 1); + data->account_box = pidgin_account_option_menu_new(account, FALSE, + G_CALLBACK(add_buddy_select_account_cb), NULL, data); + + gtk_table_attach_defaults(GTK_TABLE(table), data->account_box, 1, 2, 0, 1); + gtk_label_set_mnemonic_widget(GTK_LABEL(label), data->account_box); + pidgin_set_accessible_label (data->account_box, label); + /* End of account box */ + + label = gtk_label_new_with_mnemonic(_("_Screen name:")); + gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); + gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 1, 2); + data->entry = gtk_entry_new(); - gtk_table_attach_defaults(GTK_TABLE(table), data->entry, 1, 2, 0, 1); + gtk_table_attach_defaults(GTK_TABLE(table), data->entry, 1, 2, 1, 2); gtk_widget_grab_focus(data->entry); if (username != NULL) @@ -5401,19 +5474,20 @@ GTK_RESPONSE_OK, FALSE); gtk_entry_set_activates_default (GTK_ENTRY(data->entry), TRUE); + gtk_label_set_mnemonic_widget(GTK_LABEL(label), data->entry); pidgin_set_accessible_label (data->entry, label); g_signal_connect(G_OBJECT(data->entry), "changed", G_CALLBACK(pidgin_set_sensitive_if_input), data->window); - label = gtk_label_new(_("Alias:")); + label = gtk_label_new_with_mnemonic(_("A_lias:")); gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); - gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 1, 2); + gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 2, 3); data->entry_for_alias = gtk_entry_new(); gtk_table_attach_defaults(GTK_TABLE(table), - data->entry_for_alias, 1, 2, 1, 2); + data->entry_for_alias, 1, 2, 2, 3); if (alias != NULL) gtk_entry_set_text(GTK_ENTRY(data->entry_for_alias), alias); @@ -5422,29 +5496,19 @@ gtk_widget_grab_focus(GTK_WIDGET(data->entry_for_alias)); gtk_entry_set_activates_default (GTK_ENTRY(data->entry_for_alias), TRUE); + gtk_label_set_mnemonic_widget(GTK_LABEL(label), data->entry_for_alias); pidgin_set_accessible_label (data->entry_for_alias, label); - label = gtk_label_new(_("Group:")); + label = gtk_label_new_with_mnemonic(_("_Group:")); gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); - gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 2, 3); + gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 3, 4); data->combo = gtk_combo_new(); gtk_combo_set_popdown_strings(GTK_COMBO(data->combo), groups_tree()); - gtk_table_attach_defaults(GTK_TABLE(table), data->combo, 1, 2, 2, 3); + gtk_table_attach_defaults(GTK_TABLE(table), data->combo, 1, 2, 3, 4); + gtk_label_set_mnemonic_widget(GTK_LABEL(label), GTK_COMBO(data->combo)->entry); pidgin_set_accessible_label (data->combo, label); - /* Set up stuff for the account box */ - label = gtk_label_new(_("Account:")); - gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); - gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 3, 4); - - data->account_box = pidgin_account_option_menu_new(account, FALSE, - G_CALLBACK(add_buddy_select_account_cb), NULL, data); - - gtk_table_attach_defaults(GTK_TABLE(table), data->account_box, 1, 2, 3, 4); - pidgin_set_accessible_label (data->account_box, label); - /* End of account box */ - g_signal_connect(G_OBJECT(data->window), "response", G_CALLBACK(add_buddy_cb), data); @@ -5750,7 +5814,7 @@ rowbox = gtk_hbox_new(FALSE, 5); gtk_box_pack_start(GTK_BOX(vbox), rowbox, FALSE, FALSE, 0); - label = gtk_label_new(_("Account:")); + label = gtk_label_new_with_mnemonic(_("_Account:")); gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); gtk_size_group_add_widget(data->sg, label); gtk_box_pack_start(GTK_BOX(rowbox), label, FALSE, FALSE, 0); @@ -5759,6 +5823,7 @@ G_CALLBACK(addchat_select_account_cb), chat_account_filter_func, data); gtk_box_pack_start(GTK_BOX(rowbox), data->account_menu, TRUE, TRUE, 0); + gtk_label_set_mnemonic_widget(GTK_LABEL(label), data->account_menu); pidgin_set_accessible_label (data->account_menu, label); data->entries_box = gtk_vbox_new(FALSE, 5); @@ -5770,7 +5835,7 @@ rowbox = gtk_hbox_new(FALSE, 5); gtk_box_pack_start(GTK_BOX(vbox), rowbox, FALSE, FALSE, 0); - label = gtk_label_new(_("Alias:")); + label = gtk_label_new_with_mnemonic(_("A_lias:")); gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); gtk_size_group_add_widget(data->sg, label); gtk_box_pack_start(GTK_BOX(rowbox), label, FALSE, FALSE, 0); @@ -5780,12 +5845,15 @@ gtk_entry_set_text(GTK_ENTRY(data->alias_entry), alias); gtk_box_pack_end(GTK_BOX(rowbox), data->alias_entry, TRUE, TRUE, 0); gtk_entry_set_activates_default(GTK_ENTRY(data->alias_entry), TRUE); + gtk_label_set_mnemonic_widget(GTK_LABEL(label), data->alias_entry); pidgin_set_accessible_label (data->alias_entry, label); + if (name != NULL) + gtk_widget_grab_focus(data->alias_entry); rowbox = gtk_hbox_new(FALSE, 5); gtk_box_pack_start(GTK_BOX(vbox), rowbox, FALSE, FALSE, 0); - label = gtk_label_new(_("Group:")); + label = gtk_label_new_with_mnemonic(_("_Group:")); gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); gtk_size_group_add_widget(data->sg, label); gtk_box_pack_start(GTK_BOX(rowbox), label, FALSE, FALSE, 0); @@ -5799,6 +5867,7 @@ gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(data->group_combo)->entry), group->name); } + gtk_label_set_mnemonic_widget(GTK_LABEL(label), GTK_COMBO(data->group_combo)->entry); pidgin_set_accessible_label (data->group_combo, label); g_signal_connect(G_OBJECT(data->window), "response",
--- a/pidgin/gtkconv.c Thu Jun 14 19:48:48 2007 +0000 +++ b/pidgin/gtkconv.c Mon Jun 18 01:48:35 2007 +0000 @@ -49,6 +49,7 @@ #include "prpl.h" #include "request.h" #include "util.h" +#include "version.h" #include "gtkdnd-hints.h" #include "gtkblist.h" @@ -235,6 +236,10 @@ return FALSE; } + if (gdk_window_get_state(gtkconv->win->window->window) & GDK_WINDOW_STATE_MAXIMIZED) { + return FALSE; + } + /* I find that I resize the window when it has a bunch of conversations in it, mostly so that the * tab bar will fit, but then I don't want new windows taking up the entire screen. I check to see * if there is only one conversation in the window. This way we'll be setting new windows to the @@ -1243,6 +1248,37 @@ } static void +menu_insert_link_cb(gpointer data, guint action, GtkWidget *widget) +{ + PidginWindow *win = data; + PidginConversation *gtkconv; + GtkIMHtmlToolbar *toolbar; + + gtkconv = pidgin_conv_window_get_active_gtkconv(win); + toolbar = GTK_IMHTMLTOOLBAR(gtkconv->toolbar); + + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toolbar->link), + !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(toolbar->link))); +} + +static void +menu_insert_image_cb(gpointer data, guint action, GtkWidget *widget) +{ + PidginWindow *win = data; + PurpleConversation *conv; + PidginConversation *gtkconv; + GtkIMHtmlToolbar *toolbar; + + gtkconv = pidgin_conv_window_get_active_gtkconv(win); + conv = gtkconv->active_conv; + toolbar = GTK_IMHTMLTOOLBAR(gtkconv->toolbar); + + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toolbar->image), + !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(toolbar->image))); +} + + +static void menu_alias_cb(gpointer data, guint action, GtkWidget *widget) { PidginWindow *win = data; @@ -1821,6 +1857,9 @@ if (!gtkconv->send_history) break; + if (gtkconv->entry != entry) + break; + if (!gtkconv->send_history->prev) { GtkTextIter start, end; @@ -1869,6 +1908,9 @@ if (!gtkconv->send_history) break; + if (gtkconv->entry != entry) + break; + if (gtkconv->send_history->prev && gtkconv->send_history->prev->data) { GObject *object; GtkTextIter iter; @@ -1972,6 +2014,8 @@ switch (event->keyval) { case GDK_Tab: + if (gtkconv->entry != entry) + break; return tab_complete(conv); break; @@ -2048,6 +2092,9 @@ return TRUE; } +static void +regenerate_options_items(PidginWindow *win); + void pidgin_conv_switch_active_conversation(PurpleConversation *conv) { @@ -2148,6 +2195,8 @@ gray_stuff_out(gtkconv); update_typing_icon(gtkconv); + g_object_set_data(G_OBJECT(entry), "transient_buddy", NULL); + regenerate_options_items(gtkconv->win); gtk_window_set_title(GTK_WINDOW(gtkconv->win->window), gtk_label_get_text(GTK_LABEL(gtkconv->tab_label))); @@ -2814,6 +2863,14 @@ { "/Conversation/sep3", NULL, NULL, 0, "<Separator>", NULL }, + { N_("/Conversation/Insert Lin_k..."), NULL, menu_insert_link_cb, 0, + "<StockItem>", PIDGIN_STOCK_TOOLBAR_INSERT_LINK }, + { N_("/Conversation/Insert Imag_e..."), NULL, menu_insert_image_cb, 0, + "<StockItem>", PIDGIN_STOCK_TOOLBAR_INSERT_IMAGE }, + + { "/Conversation/sep4", NULL, NULL, 0, "<Separator>", NULL }, + + { N_("/Conversation/_Close"), NULL, menu_close_conv_cb, 0, "<StockItem>", GTK_STOCK_CLOSE }, @@ -2893,14 +2950,59 @@ GList *list; PidginConversation *gtkconv; PurpleConversation *conv; - PurpleBuddy *buddy; + PurpleBlistNode *node = NULL; + PurpleChat *chat = NULL; + PurpleBuddy *buddy = NULL; gtkconv = pidgin_conv_window_get_active_gtkconv(win); conv = gtkconv->active_conv; - buddy = purple_find_buddy(conv->account, conv->name); menu = gtk_item_factory_get_widget(win->menu.item_factory, N_("/Conversation/More")); + if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_CHAT) { + chat = purple_blist_find_chat(conv->account, conv->name); + + if ((chat == NULL) && (gtkconv->imhtml != NULL)) { + chat = g_object_get_data(G_OBJECT(gtkconv->imhtml), "transient_chat"); + } + + if ((chat == NULL) && (gtkconv->imhtml != NULL)) { + GHashTable *components; + components = g_hash_table_new_full(g_str_hash, g_str_equal, + g_free, g_free); + g_hash_table_replace(components, g_strdup("channel"), + g_strdup(conv->name)); + chat = purple_chat_new(conv->account, NULL, components); + purple_blist_node_set_flags((PurpleBlistNode *)chat, + PURPLE_BLIST_NODE_FLAG_NO_SAVE); + g_object_set_data_full(G_OBJECT(gtkconv->imhtml), "transient_chat", + chat, (GDestroyNotify)purple_blist_remove_chat); + } + } else { + buddy = purple_find_buddy(conv->account, conv->name); + + /* gotta remain bug-compatible :( libpurple < 2.0.2 didn't handle + * removing "isolated" buddy nodes well */ + if (purple_version_check(2, 0, 2) == NULL) { + if ((buddy == NULL) && (gtkconv->imhtml != NULL)) { + buddy = g_object_get_data(G_OBJECT(gtkconv->imhtml), "transient_buddy"); + } + + if ((buddy == NULL) && (gtkconv->imhtml != NULL)) { + buddy = purple_buddy_new(conv->account, conv->name, NULL); + purple_blist_node_set_flags((PurpleBlistNode *)buddy, + PURPLE_BLIST_NODE_FLAG_NO_SAVE); + g_object_set_data_full(G_OBJECT(gtkconv->imhtml), "transient_buddy", + buddy, (GDestroyNotify)purple_blist_remove_buddy); + } + } + } + + if (chat) + node = (PurpleBlistNode *)chat; + else if (buddy) + node = (PurpleBlistNode *)buddy; + /* Remove the previous entries */ for (list = gtk_container_get_children(GTK_CONTAINER(menu)); list; ) { @@ -2910,12 +3012,11 @@ } /* Now add the stuff */ - if (buddy) + if (node) { if (purple_account_is_connected(conv->account)) - pidgin_append_blist_node_proto_menu(menu, conv->account->gc, - (PurpleBlistNode *)buddy); - pidgin_append_blist_node_extended_menu(menu, (PurpleBlistNode *)buddy); + pidgin_append_blist_node_proto_menu(menu, conv->account->gc, node); + pidgin_append_blist_node_extended_menu(menu, node); } if ((list = gtk_container_get_children(GTK_CONTAINER(menu))) == NULL) @@ -3028,6 +3129,18 @@ gtk_item_factory_get_widget(win->menu.item_factory, N_("/Conversation/Remove...")); + /* --- */ + + win->menu.insert_link = + gtk_item_factory_get_widget(win->menu.item_factory, + N_("/Conversation/Insert Link...")); + + win->menu.insert_image = + gtk_item_factory_get_widget(win->menu.item_factory, + N_("/Conversation/Insert Image...")); + + /* --- */ + win->menu.logging = gtk_item_factory_get_widget(win->menu.item_factory, N_("/Options/Enable Logging")); @@ -4189,6 +4302,8 @@ gtk_box_pack_start(GTK_BOX(hbox), gtkchat->topic_text, TRUE, TRUE, 0); gtk_widget_show(gtkchat->topic_text); + g_signal_connect(G_OBJECT(gtkchat->topic_text), "key_press_event", + G_CALLBACK(entry_key_press_cb), gtkconv); } /* Setup the horizontal pane. */ @@ -5893,6 +6008,8 @@ gtk_widget_hide(win->menu.add); } + gtk_widget_show(win->menu.insert_link); + gtk_widget_show(win->menu.insert_image); gtk_widget_show(win->menu.show_icon); } else if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_CHAT) { /* Show stuff that applies to Chats, hide stuff that applies to IMs */ @@ -5918,6 +6035,8 @@ gtk_widget_show(win->menu.remove); } + gtk_widget_show(win->menu.insert_link); + gtk_widget_show(win->menu.insert_image); } /* @@ -5959,6 +6078,8 @@ gtk_widget_set_sensitive(win->menu.add_pounce, TRUE); gtk_widget_set_sensitive(win->menu.get_info, (prpl_info->get_info != NULL)); gtk_widget_set_sensitive(win->menu.invite, (prpl_info->chat_invite != NULL)); + gtk_widget_set_sensitive(win->menu.insert_link, (conv->features & PURPLE_CONNECTION_HTML)); + gtk_widget_set_sensitive(win->menu.insert_image, (prpl_info->options & OPT_PROTO_IM_IMAGE) && !(conv->features & PURPLE_CONNECTION_NO_IMAGES)); if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_IM) { @@ -5993,6 +6114,8 @@ gtk_widget_set_sensitive(win->menu.alias, FALSE); gtk_widget_set_sensitive(win->menu.add, FALSE); gtk_widget_set_sensitive(win->menu.remove, FALSE); + gtk_widget_set_sensitive(win->menu.insert_link, TRUE); + gtk_widget_set_sensitive(win->menu.insert_image, FALSE); } /* @@ -6951,6 +7074,9 @@ purple_prefs_add_int(PIDGIN_PREFS_ROOT "/conversations/tab_side", GTK_POS_TOP); purple_prefs_add_int(PIDGIN_PREFS_ROOT "/conversations/scrollback_lines", 4000); + purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/conversations/use_theme_font", TRUE); + purple_prefs_add_string(PIDGIN_PREFS_ROOT "/conversations/custom_font", ""); + /* Conversations -> Chat */ purple_prefs_add_none(PIDGIN_PREFS_ROOT "/conversations/chat"); purple_prefs_add_int(PIDGIN_PREFS_ROOT "/conversations/chat/default_width", 410); @@ -7919,7 +8045,9 @@ entry = gtk_entry_new(); gtk_entry_set_has_frame(GTK_ENTRY(entry), FALSE); gtk_entry_set_width_chars(GTK_ENTRY(entry), 10); +#if GTK_CHECK_VERSION(2,4,0) gtk_entry_set_alignment(GTK_ENTRY(entry), 0.5); +#endif gtk_box_pack_start(GTK_BOX(gtkconv->tabby), entry, TRUE, TRUE, 0); /* after the tab label */ @@ -8326,7 +8454,9 @@ } ebox = gtk_event_box_new(); +#if GTK_CHECK_VERSION(2,4,0) gtk_event_box_set_visible_window(GTK_EVENT_BOX(ebox), FALSE); +#endif gtk_container_add(GTK_CONTAINER(ebox), gtkconv->tabby); g_signal_connect(G_OBJECT(ebox), "button-press-event", G_CALLBACK(alias_double_click_cb), gtkconv);
--- a/pidgin/gtkdialogs.c Thu Jun 14 19:48:48 2007 +0000 +++ b/pidgin/gtkdialogs.c Mon Jun 18 01:48:35 2007 +0000 @@ -822,8 +822,17 @@ if (username != NULL && purple_str_has_suffix(username, "rocksmyworld")) found = pidgin_dialogs_ee(username); - if (!found && username != NULL && *username != '\0' && account != NULL) - serv_get_info(purple_account_get_connection(account), username); + if (!found && username != NULL && *username != '\0' && account != NULL) { + + PurpleConnection *gc = purple_account_get_connection(account); + + PurpleNotifyUserInfo *info = purple_notify_user_info_new(); + purple_notify_user_info_add_pair(info, _("Information"), _("Retrieving...")); + purple_notify_userinfo(gc, username, info, NULL, NULL); + purple_notify_user_info_destroy(info); + + serv_get_info(gc, username); + } g_free(username); }
--- a/pidgin/gtkdialogs.h Thu Jun 14 19:48:48 2007 +0000 +++ b/pidgin/gtkdialogs.h Mon Jun 18 01:48:35 2007 +0000 @@ -36,10 +36,15 @@ void pidgin_dialogs_im_with_user(PurpleAccount *, const char *); void pidgin_dialogs_info(void); void pidgin_dialogs_log(void); + +/** + * @deprecated This function is no longer used and will be removed in + * Pidgin 3.0.0 unless there is sufficient demand to keep it. + */ void pidgin_dialogs_alias_contact(PurpleContact *); + void pidgin_dialogs_alias_buddy(PurpleBuddy *); void pidgin_dialogs_alias_chat(PurpleChat *); - void pidgin_dialogs_remove_buddy(PurpleBuddy *); void pidgin_dialogs_remove_group(PurpleGroup *); void pidgin_dialogs_remove_chat(PurpleChat *);
--- a/pidgin/gtkdocklet-x11.c Thu Jun 14 19:48:48 2007 +0000 +++ b/pidgin/gtkdocklet-x11.c Mon Jun 18 01:48:35 2007 +0000 @@ -125,8 +125,12 @@ 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_SMALL); + icon_size = gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_LARGE); gtk_image_set_from_stock(GTK_IMAGE(image), icon_name, icon_size); } @@ -281,7 +285,7 @@ * 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 gaim is started on login. + * list not properly starting hidden when Pidgin is started on login. */ if(!recreate) { pidgin_docklet_embedded();
--- a/pidgin/gtkft.c Thu Jun 14 19:48:48 2007 +0000 +++ b/pidgin/gtkft.c Mon Jun 18 01:48:35 2007 +0000 @@ -248,10 +248,10 @@ get_xfer_info_strings(xfer, &kbsec, &time_elapsed, &time_remaining); - status = g_strdup_printf("%ld%% (%ld of %ld bytes)", - (unsigned long)(purple_xfer_get_progress(xfer)*100), - (unsigned long)purple_xfer_get_bytes_sent(xfer), - (unsigned long)purple_xfer_get_size(xfer)); + status = g_strdup_printf("%d%% (%" G_GSIZE_FORMAT " of %" G_GSIZE_FORMAT " bytes)", + (int)(purple_xfer_get_progress(xfer)*100), + purple_xfer_get_bytes_sent(xfer), + purple_xfer_get_size(xfer)); if (purple_xfer_is_completed(xfer)) {
--- a/pidgin/gtkimhtml.c Thu Jun 14 19:48:48 2007 +0000 +++ b/pidgin/gtkimhtml.c Mon Jun 18 01:48:35 2007 +0000 @@ -140,6 +140,10 @@ }; static guint signals [LAST_SIGNAL] = { 0 }; +static char *html_clipboard = NULL; +static char *text_clipboard = NULL; +GtkClipboard *clipboard_selection = NULL; + static GtkTargetEntry selection_targets[] = { #ifndef _WIN32 { "text/html", 0, TARGET_HTML }, @@ -871,14 +875,17 @@ static void gtk_imhtml_clipboard_get(GtkClipboard *clipboard, GtkSelectionData *selection_data, guint info, GtkIMHtml *imhtml) { char *text = NULL; - gboolean primary; + gboolean primary = (clipboard != clipboard_selection); GtkTextIter start, end; - GtkTextMark *sel = gtk_text_buffer_get_selection_bound(imhtml->text_buffer); - GtkTextMark *ins = gtk_text_buffer_get_insert(imhtml->text_buffer); - - gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &start, sel); - gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &end, ins); - primary = gtk_widget_get_clipboard(GTK_WIDGET(imhtml), GDK_SELECTION_PRIMARY) == clipboard; + GtkTextMark *sel = NULL; + GtkTextMark *ins = NULL; + + if (primary) { + ins = gtk_text_buffer_get_insert(imhtml->text_buffer); + sel = gtk_text_buffer_get_selection_bound(imhtml->text_buffer); + gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &start, sel); + gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &end, ins); + } if (info == TARGET_HTML) { char *selection; @@ -888,7 +895,7 @@ if (primary) { text = gtk_imhtml_get_markup_range(imhtml, &start, &end); } else - text = imhtml->clipboard_html_string; + text = html_clipboard; /* Mozilla asks that we start our text/html with the Unicode byte order mark */ str = g_string_append_unichar(str, 0xfeff); @@ -906,7 +913,7 @@ if (primary) { text = gtk_imhtml_get_text(imhtml, &start, &end); } else - text = imhtml->clipboard_text_string; + text = text_clipboard; gtk_selection_data_set_text(selection_data, text, strlen(text)); } if (primary) /* This was allocated here */ @@ -929,20 +936,32 @@ &insert); } +static void gtk_imhtml_clipboard_clear (GtkClipboard *clipboard, GtkSelectionData *sel_data, + guint info, gpointer user_data_or_owner) +{ + clipboard_selection = NULL; +} + static void copy_clipboard_cb(GtkIMHtml *imhtml, gpointer unused) { GtkTextIter start, end; if (gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, &start, &end)) { - gtk_clipboard_set_with_owner(gtk_widget_get_clipboard(GTK_WIDGET(imhtml), GDK_SELECTION_CLIPBOARD), + if (!clipboard_selection) + clipboard_selection = gtk_widget_get_clipboard(GTK_WIDGET(imhtml), GDK_SELECTION_CLIPBOARD); + gtk_clipboard_set_with_owner(clipboard_selection, selection_targets, sizeof(selection_targets) / sizeof(GtkTargetEntry), (GtkClipboardGetFunc)gtk_imhtml_clipboard_get, - (GtkClipboardClearFunc)NULL, G_OBJECT(imhtml)); + (GtkClipboardClearFunc)gtk_imhtml_clipboard_clear, G_OBJECT(imhtml)); g_free(imhtml->clipboard_html_string); g_free(imhtml->clipboard_text_string); imhtml->clipboard_html_string = gtk_imhtml_get_markup_range(imhtml, &start, &end); imhtml->clipboard_text_string = gtk_imhtml_get_text(imhtml, &start, &end); + + text_clipboard = imhtml->clipboard_text_string; + html_clipboard = imhtml->clipboard_html_string; + } g_signal_stop_emission_by_name(imhtml, "copy-clipboard"); @@ -952,10 +971,12 @@ { GtkTextIter start, end; if (gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, &start, &end)) { - gtk_clipboard_set_with_owner(gtk_widget_get_clipboard(GTK_WIDGET(imhtml), GDK_SELECTION_CLIPBOARD), + if (!clipboard_selection) + clipboard_selection = gtk_widget_get_clipboard(GTK_WIDGET(imhtml), GDK_SELECTION_CLIPBOARD); + gtk_clipboard_set_with_owner(clipboard_selection, selection_targets, sizeof(selection_targets) / sizeof(GtkTargetEntry), (GtkClipboardGetFunc)gtk_imhtml_clipboard_get, - (GtkClipboardClearFunc)NULL, G_OBJECT(imhtml)); + (GtkClipboardClearFunc)gtk_imhtml_clipboard_clear, G_OBJECT(imhtml)); g_free(imhtml->clipboard_html_string); g_free(imhtml->clipboard_text_string); @@ -963,6 +984,9 @@ imhtml->clipboard_html_string = gtk_imhtml_get_markup_range(imhtml, &start, &end); imhtml->clipboard_text_string = gtk_imhtml_get_text(imhtml, &start, &end); + text_clipboard = imhtml->clipboard_text_string; + html_clipboard = imhtml->clipboard_html_string; + if (imhtml->editable) gtk_text_buffer_delete_selection(imhtml->text_buffer, FALSE, FALSE); } @@ -1199,17 +1223,18 @@ g_free(img_data); } - if (imhtml->clipboard_text_string) { - g_free(imhtml->clipboard_text_string); - g_free(imhtml->clipboard_html_string); - } - g_list_free(imhtml->scalables); g_slist_free(imhtml->im_images); g_queue_free(imhtml->animations); g_free(imhtml->protocol_name); g_free(imhtml->search_string); G_OBJECT_CLASS(parent_class)->finalize (object); + if (clipboard_selection) + gtk_clipboard_set_with_owner(clipboard_selection, + selection_targets, sizeof(selection_targets) / sizeof(GtkTargetEntry), + (GtkClipboardGetFunc)gtk_imhtml_clipboard_get, + (GtkClipboardClearFunc)NULL, G_OBJECT(imhtml)); + } /* Boring GTK+ stuff */ @@ -3148,6 +3173,7 @@ char *basename = g_path_get_basename(filename); char *ext = strrchr(basename, '.'); #endif + char *newfilename; gtk_widget_destroy(image->filesel); image->filesel = NULL; @@ -3162,7 +3188,7 @@ gchar *fmt_ext = extensions[0]; const gchar* file_ext = filename + strlen(filename) - strlen(fmt_ext); - if(!strcmp(fmt_ext, file_ext)){ + if(!g_ascii_strcasecmp(fmt_ext, file_ext)){ type = gdk_pixbuf_format_get_name(format); break; } @@ -3195,6 +3221,7 @@ /* If I can't find a valid type, I will just tell the user about it and then assume it's a png */ if (!type){ + char *basename, *tmp; #if GTK_CHECK_VERSION(2,4,0) GtkWidget *dialog = gtk_message_dialog_new_with_markup(NULL, 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("<span size='larger' weight='bold'>Unrecognized file type</span>\n\nDefaulting to PNG.")); @@ -3205,10 +3232,26 @@ g_signal_connect_swapped(dialog, "response", G_CALLBACK (gtk_widget_destroy), dialog); gtk_widget_show(dialog); + type = g_strdup("png"); + basename = g_path_get_basename(filename); + tmp = strrchr(basename, '.'); + if (tmp != NULL) + tmp[0] = '\0'; + newfilename = g_strdup_printf("%s.png", basename); + g_free(basename); + } else { + /* + * We're able to save the file in it's original format, so we + * can use the original file name. + */ + newfilename = g_strdup(filename); } - gdk_pixbuf_save(image->pixbuf, filename, type, &error, NULL); + gdk_pixbuf_save(image->pixbuf, newfilename, type, &error, NULL); + + g_free(newfilename); + g_free(type); if (error){ #if GTK_CHECK_VERSION(2,4,0) @@ -3222,8 +3265,6 @@ gtk_widget_show(dialog); g_error_free(error); } - - g_free(type); } #if GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */ @@ -4432,7 +4473,9 @@ if (imhtml_smiley && imhtml_smiley->flags & GTK_IMHTML_SMILEY_CUSTOM) { ebox = gtk_event_box_new(); +#if GTK_CHECK_VERSION(2,4,0) gtk_event_box_set_visible_window(GTK_EVENT_BOX(ebox), FALSE); +#endif gtk_widget_show(ebox); }
--- a/pidgin/gtkimhtmltoolbar.c Thu Jun 14 19:48:48 2007 +0000 +++ b/pidgin/gtkimhtmltoolbar.c Mon Jun 18 01:48:35 2007 +0000 @@ -71,7 +71,9 @@ do_small(GtkWidget *smalltb, GtkIMHtmlToolbar *toolbar) { g_return_if_fail(toolbar != NULL); - gtk_imhtml_font_shrink(GTK_IMHTML(toolbar->imhtml)); + /* Only shrink the font on activation, not deactivation as well */ + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(smalltb))) + gtk_imhtml_font_shrink(GTK_IMHTML(toolbar->imhtml)); gtk_widget_grab_focus(toolbar->imhtml); } @@ -79,7 +81,9 @@ do_big(GtkWidget *large, GtkIMHtmlToolbar *toolbar) { g_return_if_fail(toolbar); - gtk_imhtml_font_grow(GTK_IMHTML(toolbar->imhtml)); + /* Only grow the font on activation, not deactivation as well */ + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(large))) + gtk_imhtml_font_grow(GTK_IMHTML(toolbar->imhtml)); gtk_widget_grab_focus(toolbar->imhtml); }
--- a/pidgin/gtkmain.c Thu Jun 14 19:48:48 2007 +0000 +++ b/pidgin/gtkmain.c Mon Jun 18 01:48:35 2007 +0000 @@ -108,21 +108,19 @@ }; #endif -static int +static void dologin_named(const char *name) { PurpleAccount *account; char **names; int i; - int ret = -1; if (name != NULL) { /* list of names given */ names = g_strsplit(name, ",", 64); for (i = 0; names[i] != NULL; i++) { account = purple_accounts_find(names[i], NULL); if (account != NULL) { /* found a user */ - ret = 0; - purple_account_connect(account); + purple_account_set_enabled(account, PIDGIN_UI, TRUE); } } g_strfreev(names); @@ -133,12 +131,9 @@ if (accounts != NULL) { account = (PurpleAccount *)accounts->data; - ret = 0; - purple_account_connect(account); + purple_account_set_enabled(account, PIDGIN_UI, TRUE); } } - - return ret; } #ifdef HAVE_SIGNAL_H @@ -439,7 +434,6 @@ char *opt_config_dir_arg = NULL; char *opt_login_arg = NULL; char *opt_session_arg = NULL; - int dologin_ret = -1; char *search_path; GList *accounts; #ifdef HAVE_SIGNAL_H @@ -473,6 +467,9 @@ #else debug_enabled = FALSE; #endif + + /* This is the first Glib function call. Make sure to initialize GThread bfeore then */ + g_thread_init(NULL); #ifdef ENABLE_NLS bindtextdomain(PACKAGE, LOCALEDIR); @@ -785,14 +782,23 @@ pidgin_debug_window_show(); if (opt_login) { - dologin_ret = dologin_named(opt_login_arg); + /* disable all accounts */ + for (accounts = purple_accounts_get_all(); accounts != NULL; accounts = accounts->next) { + PurpleAccount *account = accounts->data; + purple_account_set_enabled(account, PIDGIN_UI, FALSE); + } + /* honor the startup status preference */ + if (!purple_prefs_get_bool("/purple/savedstatus/startup_current_status")) + purple_savedstatus_activate(purple_savedstatus_get_startup()); + /* now enable the requested ones */ + dologin_named(opt_login_arg); if (opt_login_arg != NULL) { g_free(opt_login_arg); opt_login_arg = NULL; } } - if (opt_nologin) + if (opt_nologin && !opt_login) { /* Set all accounts to "offline" */ PurpleSavedStatus *saved_status; @@ -808,7 +814,7 @@ /* Set the status for each account */ purple_savedstatus_activate(saved_status); } - else + else if (!opt_login) { /* Everything is good to go--sign on already */ if (!purple_prefs_get_bool("/purple/savedstatus/startup_current_status"))
--- a/pidgin/gtknotify.c Thu Jun 14 19:48:48 2007 +0000 +++ b/pidgin/gtknotify.c Mon Jun 18 01:48:35 2007 +0000 @@ -40,6 +40,12 @@ typedef struct { + GtkWidget *window; + int count; +} PidginUserInfo; + +typedef struct +{ PurpleAccount *account; char *url; GtkWidget *label; @@ -624,7 +630,7 @@ gtk_widget_show(button); g_signal_connect_swapped(G_OBJECT(button), "clicked", - G_CALLBACK(formatted_close_cb), window); + G_CALLBACK(gtk_widget_destroy), window); g_signal_connect(G_OBJECT(window), "key_press_event", G_CALLBACK(formatted_input_cb), NULL); @@ -878,6 +884,11 @@ static void remove_userinfo(GtkWidget *widget, gpointer key) { + PidginUserInfo *pinfo = g_hash_table_lookup(userinfo, key); + + while (pinfo->count--) + purple_notify_close(PURPLE_NOTIFY_USERINFO, widget); + g_hash_table_remove(userinfo, key); } @@ -888,26 +899,33 @@ char *info; void *ui_handle; char *key = userinfo_hash(purple_connection_get_account(gc), who); + PidginUserInfo *pinfo = NULL; if (!userinfo) { - userinfo = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); + userinfo = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); } info = purple_notify_user_info_get_text_with_newline(user_info, "<br />"); - ui_handle = g_hash_table_lookup(userinfo, key); - if (ui_handle != NULL) { - GtkIMHtml *imhtml = g_object_get_data(G_OBJECT(ui_handle), "info-widget"); + pinfo = g_hash_table_lookup(userinfo, key); + if (pinfo != NULL) { + GtkIMHtml *imhtml = g_object_get_data(G_OBJECT(pinfo->window), "info-widget"); char *linked_text = purple_markup_linkify(info); gtk_imhtml_clear(imhtml); gtk_imhtml_append_text(imhtml, linked_text, notify_imhtml_options()); g_free(linked_text); g_free(key); + ui_handle = pinfo->window; + pinfo->count++; } else { char *primary = g_strdup_printf(_("Info for %s"), who); ui_handle = pidgin_notify_formatted(_("Buddy Information"), primary, NULL, info); - g_hash_table_insert(userinfo, key, ui_handle); + g_signal_handlers_disconnect_by_func(G_OBJECT(ui_handle), G_CALLBACK(formatted_close_cb), NULL); g_signal_connect(G_OBJECT(ui_handle), "destroy", G_CALLBACK(remove_userinfo), key); g_free(primary); + pinfo = g_new0(PidginUserInfo, 1); + pinfo->window = ui_handle; + pinfo->count = 1; + g_hash_table_insert(userinfo, key, pinfo); } g_free(info); return ui_handle;
--- a/pidgin/gtkpounce.c Thu Jun 14 19:48:48 2007 +0000 +++ b/pidgin/gtkpounce.c Mon Jun 18 01:48:35 2007 +0000 @@ -783,7 +783,7 @@ gtk_widget_show(table); dialog->on_away = - gtk_check_button_new_with_mnemonic(_("P_ounce only when my status is not available")); + gtk_check_button_new_with_mnemonic(_("P_ounce only when my status is not Available")); gtk_table_attach(GTK_TABLE(table), dialog->on_away, 0, 1, 0, 1, GTK_FILL, 0, 0, 0);
--- a/pidgin/gtkprefs.c Thu Jun 14 19:48:48 2007 +0000 +++ b/pidgin/gtkprefs.c Mon Jun 18 01:48:35 2007 +0000 @@ -382,7 +382,7 @@ new_theme = current_smiley_theme; description = g_strdup_printf("<span size='larger' weight='bold'>%s</span> - %s\n" "<span size='smaller' foreground='white'>%s</span>", - new_theme->name, new_theme->author, new_theme->desc); + _(new_theme->name), _(new_theme->author), _(new_theme->desc)); gtk_list_store_set(smiley_theme_store, &iter, 1, description, -1); g_free(description); @@ -391,7 +391,7 @@ if (gtk_tree_model_get_iter(model, &iter, oldpath)) { description = g_strdup_printf("<span size='larger' weight='bold'>%s</span> - %s\n" "<span size='smaller' foreground='dim grey'>%s</span>", - old_theme->name, old_theme->author, old_theme->desc); + _(old_theme->name), _(old_theme->author), _(old_theme->desc)); gtk_list_store_set(smiley_theme_store, &iter, 1, description, -1); g_free(description); @@ -426,7 +426,7 @@ struct smiley_theme *theme = themes->data; char *description = g_strdup_printf("<span size='larger' weight='bold'>%s</span> - %s\n" "<span size='smaller' foreground='dim grey'>%s</span>", - theme->name, theme->author, theme->desc); + _(theme->name), _(theme->author), _(theme->desc)); gtk_list_store_append (smiley_theme_store, &iter); /* @@ -881,6 +881,15 @@ return ret; } +#if GTK_CHECK_VERSION(2,4,0) +static void +pidgin_custom_font_set(GtkFontButton *font_button, gpointer nul) +{ + purple_prefs_set_string(PIDGIN_PREFS_ROOT "/conversations/custom_font", + gtk_font_button_get_font_name(font_button)); +} +#endif + static GtkWidget * conv_page() { @@ -889,9 +898,17 @@ GtkWidget *toolbar; GtkWidget *iconpref1; GtkWidget *iconpref2; + GtkWidget *fontpref; GtkWidget *imhtml; GtkWidget *frame; +#if GTK_CHECK_VERSION(2,4,0) + GtkWidget *hbox; + GtkWidget *label; + GtkWidget *font_button; + const char *font_name; +#endif + ret = gtk_vbox_new(FALSE, PIDGIN_HIG_CAT_SPACE); gtk_container_set_border_width(GTK_CONTAINER(ret), PIDGIN_HIG_BORDER); @@ -922,6 +939,26 @@ pidgin_prefs_checkbox(_("F_lash window when IMs are received"), PIDGIN_PREFS_ROOT "/win32/blink_im", vbox); #endif +#if GTK_CHECK_VERSION(2,4,0) + vbox = pidgin_make_frame(ret, _("Font")); + if (purple_running_gnome()) + fontpref = pidgin_prefs_checkbox(_("Use document font from _theme"), PIDGIN_PREFS_ROOT "/conversations/use_theme_font", vbox); + else + fontpref = pidgin_prefs_checkbox(_("Use font from _theme"), PIDGIN_PREFS_ROOT "/conversations/use_theme_font", vbox); + hbox = gtk_hbox_new(FALSE, 3); + label = gtk_label_new_with_mnemonic(_("Conversation _font:")); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); + font_name = purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/custom_font"); + font_button = gtk_font_button_new_with_font(purple_prefs_get_string(font_name ? font_name : NULL)); + gtk_font_button_set_show_style(GTK_FONT_BUTTON(font_button), TRUE); + gtk_box_pack_start(GTK_BOX(hbox), font_button, FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); + if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/use_theme_font")) + gtk_widget_set_sensitive(hbox, FALSE); + g_signal_connect(G_OBJECT(fontpref), "clicked", G_CALLBACK(pidgin_toggle_sensitive), hbox); + g_signal_connect(G_OBJECT(font_button), "font-set", G_CALLBACK(pidgin_custom_font_set), NULL); +#endif + vbox = pidgin_make_frame(ret, _("Default Formatting")); frame = pidgin_create_imhtml(TRUE, &imhtml, &toolbar, NULL); @@ -1693,6 +1730,7 @@ vbox->parent->parent, TRUE, TRUE, 0, GTK_PACK_START); sw = gtk_scrolled_window_new(NULL,NULL); + gtk_widget_set_size_request(sw, -1, 100); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_IN);
--- a/pidgin/gtkrequest.c Thu Jun 14 19:48:48 2007 +0000 +++ b/pidgin/gtkrequest.c Mon Jun 18 01:48:35 2007 +0000 @@ -323,7 +323,8 @@ /* Setup the dialog */ gtk_container_set_border_width(GTK_CONTAINER(dialog), PIDGIN_HIG_BORDER/2); gtk_container_set_border_width(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), PIDGIN_HIG_BORDER/2); - gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE); + if (!multiline) + gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE); gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE); gtk_dialog_set_default_response(GTK_DIALOG(dialog), 0); gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(dialog)->vbox), PIDGIN_HIG_BORDER); @@ -341,7 +342,7 @@ /* Vertical box */ vbox = gtk_vbox_new(FALSE, PIDGIN_HIG_BORDER); - gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(hbox), vbox, TRUE, TRUE, 0); /* Descriptive label */ primary_esc = (primary != NULL) ? g_markup_escape_text(primary, -1) : NULL; @@ -359,7 +360,7 @@ gtk_label_set_markup(GTK_LABEL(label), label_text); gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); gtk_misc_set_alignment(GTK_MISC(label), 0, 0); - gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); g_free(label_text);
--- a/pidgin/gtksavedstatuses.c Thu Jun 14 19:48:48 2007 +0000 +++ b/pidgin/gtksavedstatuses.c Mon Jun 18 01:48:35 2007 +0000 @@ -1088,7 +1088,6 @@ dialog->window = win = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_role(GTK_WINDOW(win), "status"); gtk_window_set_title(GTK_WINDOW(win), _("Status")); - gtk_window_set_resizable(GTK_WINDOW(win), FALSE); gtk_container_set_border_width(GTK_CONTAINER(win), PIDGIN_HIG_BORDER); g_signal_connect(G_OBJECT(win), "delete_event", @@ -1137,7 +1136,7 @@ /* Status message */ hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE); - gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0); label = gtk_label_new_with_mnemonic(_("_Message:")); gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
--- a/pidgin/gtksound.c Thu Jun 14 19:48:48 2007 +0000 +++ b/pidgin/gtksound.c Mon Jun 18 01:48:35 2007 +0000 @@ -370,12 +370,12 @@ break; case GST_MESSAGE_ERROR: gst_message_parse_error(msg, &err, NULL); - purple_debug_error("gstreamer", err->message); + purple_debug_error("gstreamer", "%s\n", err->message); g_error_free(err); break; case GST_MESSAGE_WARNING: gst_message_parse_warning(msg, &err, NULL); - purple_debug_warning("gstreamer", err->message); + purple_debug_warning("gstreamer", "%s\n", err->message); g_error_free(err); break; default:
--- a/pidgin/gtkstatusbox.c Thu Jun 14 19:48:48 2007 +0000 +++ b/pidgin/gtkstatusbox.c Mon Jun 18 01:48:35 2007 +0000 @@ -2029,6 +2029,10 @@ int w, h; GtkIconSize icon_size = gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_MEDIUM); gtk_icon_size_lookup(icon_size, &w, &h); + if (height > width) + w = width * h / height; + else if (width > height) + h = height * w / width; gdk_pixbuf_loader_set_size(loader, w, h); #endif }
--- a/pidgin/gtkthemes.c Thu Jun 14 19:48:48 2007 +0000 +++ b/pidgin/gtkthemes.c Mon Jun 18 01:48:35 2007 +0000 @@ -146,11 +146,14 @@ list->next = child; else theme->list = child; + /* Reverse the Smiley list since it was built in reverse order for efficiency reasons */ + if (list != NULL) + list->smileys = g_slist_reverse(list->smileys); list = child; } else if (!g_ascii_strncasecmp(i, "Name=", strlen("Name="))) { int len; g_free(theme->name); - theme->name = g_strdup(i+ strlen("Name=")); + theme->name = g_strdup(i + strlen("Name=")); len = strlen(theme->name); theme->name[len-1] = 0; if(len > 2 && theme->name[len-2] == '\r') @@ -201,14 +204,16 @@ } - /* Reverse the Smiley list since it was built in reverse order for efficiency reasons */ - list->smileys = g_slist_reverse(list->smileys); if (!have_used_sfile) g_free(sfile); } } + /* Reverse the Smiley list since it was built in reverse order for efficiency reasons */ + if (list != NULL) + list->smileys = g_slist_reverse(list->smileys); + g_free(dirname); fclose(f);
--- a/pidgin/gtkutils.c Thu Jun 14 19:48:48 2007 +0000 +++ b/pidgin/gtkutils.c Mon Jun 18 01:48:35 2007 +0000 @@ -61,6 +61,11 @@ #include "gtkthemes.h" #include "gtkutils.h" +typedef struct { + GtkWidget *menu; + gint default_item; +} AopMenu; + static guint accels_save_timer = 0; static gboolean @@ -89,6 +94,7 @@ void pidgin_setup_imhtml(GtkWidget *imhtml) { + PangoFontDescription *desc = NULL; g_return_if_fail(imhtml != NULL); g_return_if_fail(GTK_IS_IMHTML(imhtml)); @@ -99,10 +105,12 @@ gtk_imhtml_set_funcs(GTK_IMHTML(imhtml), >kimhtml_cbs); - /* Use the GNOME "document" font, if applicable */ - if (purple_running_gnome()) { + if (!purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/use_theme_font")) { + const char *font = purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/custom_font"); + desc = pango_font_description_from_string(font); + } else if (purple_running_gnome()) { + /* Use the GNOME "document" font, if applicable */ char *path, *font; - PangoFontDescription *desc = NULL; if ((path = g_find_program_in_path("gconftool-2"))) { g_free(path); @@ -113,11 +121,11 @@ } desc = pango_font_description_from_string(font); g_free(font); - - if (desc) { - gtk_widget_modify_font(imhtml, desc); - pango_font_description_free(desc); - } + } + + if (desc) { + gtk_widget_modify_font(imhtml, desc); + pango_font_description_free(desc); } } @@ -430,101 +438,160 @@ return vbox; } +static gpointer +aop_option_menu_get_selected(GtkWidget *optmenu, GtkWidget **p_item) +{ + GtkWidget *menu = gtk_option_menu_get_menu(GTK_OPTION_MENU(optmenu)); + GtkWidget *item = gtk_menu_get_active(GTK_MENU(menu)); + if (p_item) + (*p_item) = item; + return g_object_get_data(G_OBJECT(item), "aop_per_item_data"); +} + static void -protocol_menu_cb(GtkWidget *optmenu, GCallback cb) +aop_menu_cb(GtkWidget *optmenu, GCallback cb) { - GtkWidget *menu; GtkWidget *item; - const char *protocol; - gpointer user_data; - - menu = gtk_option_menu_get_menu(GTK_OPTION_MENU(optmenu)); - item = gtk_menu_get_active(GTK_MENU(menu)); - - protocol = g_object_get_data(G_OBJECT(item), "protocol"); - - if (!strcmp(protocol, "prpl-fake")) - protocol = g_object_get_data(G_OBJECT(item), "real_protocol"); - - if (!strcmp(protocol, g_object_get_data(G_OBJECT(optmenu), "last_protocol"))) - return; - - user_data = (g_object_get_data(G_OBJECT(optmenu), "user_data")); - g_object_set_data(G_OBJECT(optmenu), "last_protocol", (gpointer)protocol); - - if (cb != NULL) - ((void (*)(GtkWidget *, const char *, gpointer))cb)(item, protocol, - user_data); + gpointer per_item_data; + + per_item_data = aop_option_menu_get_selected(optmenu, &item); + + if (cb != NULL) { + ((void (*)(GtkWidget *, gpointer, gpointer))cb)(item, per_item_data, g_object_get_data(G_OBJECT(optmenu), "user_data")); + } } static GtkWidget * -pidgin_protocol_option_menu_item(GtkWidget *menu, GtkSizeGroup *sg, GtkWidget *image, - const char *name, const char *id) +aop_menu_item_new(GtkSizeGroup *sg, GdkPixbuf *pixbuf, const char *lbl, gpointer per_item_data) { GtkWidget *item; GtkWidget *hbox; + GtkWidget *image; GtkWidget *label; - /* Create the item. */ item = gtk_menu_item_new(); - - /* Create the hbox. */ + gtk_widget_show(item); + hbox = gtk_hbox_new(FALSE, 4); - gtk_container_add(GTK_CONTAINER(item), hbox); gtk_widget_show(hbox); - gtk_size_group_add_widget(sg, image); - - gtk_box_pack_start(GTK_BOX(hbox), image, FALSE, FALSE, 0); + /* Create the image */ + if (pixbuf == NULL) + image = gtk_image_new(); + else + image = gtk_image_new_from_pixbuf(pixbuf); gtk_widget_show(image); - /* Create the label. */ - label = gtk_label_new(name); + if (sg) + gtk_size_group_add_widget(sg, image); + + /* Create the label */ + label = gtk_label_new (lbl); + gtk_widget_show (label); gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT); - gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); + gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); + + gtk_container_add(GTK_CONTAINER(item), hbox); + gtk_box_pack_start(GTK_BOX(hbox), image, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0); - gtk_widget_show(label); - - g_object_set_data(G_OBJECT(item), "protocol", (gpointer)id); - - gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); - gtk_widget_show(item); - pidgin_set_accessible_label (item, label); + + g_object_set_data(G_OBJECT (item), "aop_per_item_data", per_item_data); + + pidgin_set_accessible_label(item, label); return item; } -GtkWidget * -pidgin_protocol_option_menu_new(const char *id, GCallback cb, - gpointer user_data) +static GtkWidget * +aop_option_menu_new(AopMenu *aop_menu, GCallback cb, gpointer user_data) +{ + GtkWidget *optmenu; + + optmenu = gtk_option_menu_new(); + gtk_widget_show(optmenu); + gtk_option_menu_set_menu(GTK_OPTION_MENU(optmenu), aop_menu->menu); + + if (aop_menu->default_item != -1) + gtk_option_menu_set_history(GTK_OPTION_MENU(optmenu), aop_menu->default_item); + + g_object_set_data_full(G_OBJECT(optmenu), "aop_menu", aop_menu, (GDestroyNotify)g_free); + g_object_set_data(G_OBJECT(optmenu), "user_data", user_data); + + g_signal_connect(G_OBJECT(optmenu), "changed", G_CALLBACK(aop_menu_cb), cb); + + return optmenu; +} + +static void +aop_option_menu_replace_menu(GtkWidget *optmenu, AopMenu *new_aop_menu) +{ + if (gtk_option_menu_get_menu(GTK_OPTION_MENU(optmenu))) + gtk_option_menu_remove_menu(GTK_OPTION_MENU(optmenu)); + + gtk_option_menu_set_menu(GTK_OPTION_MENU(optmenu), new_aop_menu->menu); + + if (new_aop_menu->default_item != -1) + gtk_option_menu_set_history(GTK_OPTION_MENU(optmenu), new_aop_menu->default_item); + + g_object_set_data_full(G_OBJECT(optmenu), "aop_menu", new_aop_menu, (GDestroyNotify)g_free); +} + +static void +aop_option_menu_select_by_data(GtkWidget *optmenu, gpointer data) { + guint idx; + GList *llItr = NULL; + + for (idx = 0, llItr = GTK_MENU_SHELL(gtk_option_menu_get_menu(GTK_OPTION_MENU(optmenu)))->children; + llItr != NULL; + llItr = llItr->next, idx++) { + if (data == g_object_get_data(G_OBJECT(llItr->data), "aop_per_item_data")) { + gtk_option_menu_set_history(GTK_OPTION_MENU(optmenu), idx); + break; + } + } +} + +static GdkPixbuf * +get_prpl_pixbuf(PurplePluginProtocolInfo *prpl_info) +{ + const char *proto_name; + GdkPixbuf *pixbuf = NULL; + char *filename; + char buf[256]; + + proto_name = prpl_info->list_icon(NULL, NULL); + g_return_val_if_fail(proto_name != NULL, NULL); + + g_snprintf(buf, sizeof(buf), "%s.png", proto_name); + filename = g_build_filename(DATADIR, "pixmaps", "pidgin", "protocols", "16", buf, NULL); + pixbuf = gdk_pixbuf_new_from_file(filename, NULL); + g_free(filename); + + return pixbuf; +} + +static AopMenu * +create_protocols_menu(const char *default_proto_id) +{ + AopMenu *aop_menu = NULL; PurplePluginProtocolInfo *prpl_info; PurplePlugin *plugin; - GtkWidget *optmenu; - GtkWidget *menu; - GdkPixbuf *pixbuf; - GtkWidget *image; - GList *p; + GdkPixbuf *pixbuf = NULL; GtkSizeGroup *sg; - char *filename; - const char *proto_name; - char buf[256]; - int i, selected_index = -1; + GList *p; const char *gtalk_name = NULL; + int i; + + aop_menu = g_malloc0(sizeof(AopMenu)); + aop_menu->default_item = -1; + aop_menu->menu = gtk_menu_new(); + gtk_widget_show(aop_menu->menu); + sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); if (purple_find_prpl("prpl-jabber")) gtalk_name = _("Google Talk"); - optmenu = gtk_option_menu_new(); - gtk_widget_show(optmenu); - - g_object_set_data(G_OBJECT(optmenu), "user_data", user_data); - - menu = gtk_menu_new(); - gtk_widget_show(menu); - - sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); - for (p = purple_plugins_get_protocols(), i = 0; p != NULL; p = p->next, i++) { @@ -532,126 +599,74 @@ plugin = (PurplePlugin *)p->data; prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(plugin); - if (gtalk_name && strcmp(gtalk_name, plugin->info->name) < 0) - { - GtkWidget *gtalk_item; - - filename = g_build_filename(DATADIR, "pixmaps", "pidgin", "protocols", - "16", "google-talk.png", NULL); + if (gtalk_name && strcmp(gtalk_name, plugin->info->name) < 0) { + char *filename = g_build_filename(DATADIR, "pixmaps", "pidgin", "protocols", + "16", "google-talk.png", NULL); pixbuf = gdk_pixbuf_new_from_file(filename, NULL); g_free(filename); + gtk_menu_shell_append(GTK_MENU_SHELL(aop_menu->menu), + aop_menu_item_new(sg, pixbuf, gtalk_name, "prpl-jabber")); if (pixbuf) - image = gtk_image_new_from_pixbuf(pixbuf); - else - image = gtk_image_new(); - - gtalk_item = pidgin_protocol_option_menu_item(menu, sg, image, gtalk_name, "prpl-fake"); - g_object_set_data(G_OBJECT(gtalk_item), "real_protocol", "prpl-jabber"); - i++; + g_object_unref(pixbuf); gtalk_name = NULL; + i++; } - /* Load the image. */ - proto_name = prpl_info->list_icon(NULL, NULL); - g_snprintf(buf, sizeof(buf), "%s.png", proto_name); - - filename = g_build_filename(DATADIR, "pixmaps", "pidgin", "protocols", - "16", buf, NULL); - pixbuf = gdk_pixbuf_new_from_file(filename, NULL); - g_free(filename); + pixbuf = get_prpl_pixbuf(prpl_info); + + gtk_menu_shell_append(GTK_MENU_SHELL(aop_menu->menu), + aop_menu_item_new(sg, pixbuf, plugin->info->name, plugin->info->id)); if (pixbuf) - image = gtk_image_new_from_pixbuf(pixbuf); - else - image = gtk_image_new(); - - pidgin_protocol_option_menu_item(menu, sg, image, plugin->info->name, plugin->info->id); - - if (id != NULL && !strcmp(plugin->info->id, id)) - { - g_object_set_data(G_OBJECT(optmenu), "last_protocol", plugin->info->id); - selected_index = i; - } - else if (i == 0) - { - /* Ensure we set the protocol even if id is NULL or can't be found. */ - g_object_set_data(G_OBJECT(optmenu), "last_protocol", plugin->info->id); - } - - if (pixbuf) - g_object_unref(G_OBJECT(pixbuf)); + g_object_unref(pixbuf); + + if (default_proto_id != NULL && !strcmp(plugin->info->id, default_proto_id)) + aop_menu->default_item = i; } - gtk_option_menu_set_menu(GTK_OPTION_MENU(optmenu), menu); - - if (selected_index != -1) - gtk_option_menu_set_history(GTK_OPTION_MENU(optmenu), selected_index); - - g_signal_connect(G_OBJECT(optmenu), "changed", - G_CALLBACK(protocol_menu_cb), cb); - g_object_unref(sg); - return optmenu; + return aop_menu; +} + +GtkWidget * +pidgin_protocol_option_menu_new(const char *id, GCallback cb, + gpointer user_data) +{ + return aop_option_menu_new(create_protocols_menu(id), cb, user_data); } PurpleAccount * pidgin_account_option_menu_get_selected(GtkWidget *optmenu) { - GtkWidget *menu = gtk_option_menu_get_menu(GTK_OPTION_MENU(optmenu)); - GtkWidget *item = gtk_menu_get_active(GTK_MENU(menu)); - return g_object_get_data(G_OBJECT(item), "account"); + return (PurpleAccount *)aop_option_menu_get_selected(optmenu, NULL); } -static void -account_menu_cb(GtkWidget *optmenu, GCallback cb) -{ - GtkWidget *menu; - GtkWidget *item; - PurpleAccount *account; - gpointer user_data; - - menu = gtk_option_menu_get_menu(GTK_OPTION_MENU(optmenu)); - item = gtk_menu_get_active(GTK_MENU(menu)); - - account = g_object_get_data(G_OBJECT(item), "account"); - user_data = g_object_get_data(G_OBJECT(optmenu), "user_data"); - - if (cb != NULL) - ((void (*)(GtkWidget *, PurpleAccount *, gpointer))cb)(item, account, - user_data); -} - -static void -create_account_menu(GtkWidget *optmenu, PurpleAccount *default_account, +static AopMenu * +create_account_menu(PurpleAccount *default_account, PurpleFilterAccountFunc filter_func, gboolean show_all) { + AopMenu *aop_menu = NULL; PurpleAccount *account; - GtkWidget *menu; - GtkWidget *item; - GtkWidget *image; - GtkWidget *hbox; - GtkWidget *label; - GdkPixbuf *pixbuf; + GdkPixbuf *pixbuf = NULL; GList *list; GList *p; GtkSizeGroup *sg; - char *filename; - const char *proto_name; + int i; char buf[256]; - int i, selected_index = -1; if (show_all) list = purple_accounts_get_all(); else list = purple_connections_get_all(); - menu = gtk_menu_new(); - gtk_widget_show(menu); - + aop_menu = g_malloc0(sizeof(AopMenu)); + aop_menu->default_item = -1; + aop_menu->menu = gtk_menu_new(); + gtk_widget_show(aop_menu->menu); sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); for (p = list, i = 0; p != NULL; p = p->next, i++) { @@ -673,46 +688,19 @@ plugin = purple_find_prpl(purple_account_get_protocol_id(account)); - if (plugin != NULL) + if (plugin) prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(plugin); - /* Create the item. */ - item = gtk_menu_item_new(); - - /* Create the hbox. */ - hbox = gtk_hbox_new(FALSE, 4); - gtk_container_add(GTK_CONTAINER(item), hbox); - gtk_widget_show(hbox); - /* Load the image. */ - if (prpl_info != NULL) { - proto_name = prpl_info->list_icon(account, NULL); - g_snprintf(buf, sizeof(buf), "%s.png", proto_name); - - filename = g_build_filename(DATADIR, "pixmaps", "pidgin", "protocols", - "16", buf, NULL); - pixbuf = gdk_pixbuf_new_from_file(filename, NULL); - g_free(filename); - - if (pixbuf != NULL) { + if (prpl_info) { + pixbuf = get_prpl_pixbuf(prpl_info); + + if (pixbuf) { if (purple_account_is_disconnected(account) && show_all && purple_connections_get_all()) gdk_pixbuf_saturate_and_pixelate(pixbuf, pixbuf, 0.0, FALSE); - - image = gtk_image_new_from_pixbuf(pixbuf); - - g_object_unref(G_OBJECT(pixbuf)); } - else - image = gtk_image_new(); } - else - image = gtk_image_new(); - - gtk_size_group_add_widget(sg, image); - - gtk_box_pack_start(GTK_BOX(hbox), image, FALSE, FALSE, 0); - gtk_widget_show(image); if (purple_account_get_alias(account)) { g_snprintf(buf, sizeof(buf), "%s (%s) (%s)", @@ -725,54 +713,33 @@ purple_account_get_protocol_name(account)); } - /* Create the label. */ - label = gtk_label_new(buf); - gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT); - gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); - gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0); - gtk_widget_show(label); - - g_object_set_data(G_OBJECT(item), "account", account); - - gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); - gtk_widget_show(item); - pidgin_set_accessible_label (item, label); - - if (default_account != NULL && account == default_account) - selected_index = i; + gtk_menu_shell_append(GTK_MENU_SHELL(aop_menu->menu), + aop_menu_item_new(sg, pixbuf, buf, account)); + + if (pixbuf) + g_object_unref(pixbuf); + + if (default_account && account == default_account) + aop_menu->default_item = i; } g_object_unref(sg); - gtk_option_menu_set_menu(GTK_OPTION_MENU(optmenu), menu); - - /* Set the place we should be at. */ - if (selected_index != -1) - gtk_option_menu_set_history(GTK_OPTION_MENU(optmenu), selected_index); + return aop_menu; } static void regenerate_account_menu(GtkWidget *optmenu) { - GtkWidget *menu; - GtkWidget *item; gboolean show_all; PurpleAccount *account; PurpleFilterAccountFunc filter_func; - menu = gtk_option_menu_get_menu(GTK_OPTION_MENU(optmenu)); - item = gtk_menu_get_active(GTK_MENU(menu)); - account = g_object_get_data(G_OBJECT(item), "account"); - - show_all = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(optmenu), - "show_all")); - - filter_func = g_object_get_data(G_OBJECT(optmenu), - "filter_func"); - - gtk_option_menu_remove_menu(GTK_OPTION_MENU(optmenu)); - - create_account_menu(optmenu, account, filter_func, show_all); + account = (PurpleAccount *)aop_option_menu_get_selected(optmenu, NULL); + show_all = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(optmenu), "show_all")); + filter_func = g_object_get_data(G_OBJECT(optmenu), "filter_func"); + + aop_option_menu_replace_menu(optmenu, create_account_menu(account, filter_func, show_all)); } static void @@ -799,28 +766,7 @@ void pidgin_account_option_menu_set_selected(GtkWidget *optmenu, PurpleAccount *account) { - GtkWidget *menu; - GtkWidget *item; - gboolean show_all; - PurpleAccount *curaccount; - PurpleFilterAccountFunc filter_func; - - menu = gtk_option_menu_get_menu(GTK_OPTION_MENU(optmenu)); - item = gtk_menu_get_active(GTK_MENU(menu)); - curaccount = g_object_get_data(G_OBJECT(item), "account"); - - if (account == curaccount) - return; - - show_all = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(optmenu), - "show_all")); - - filter_func = g_object_get_data(G_OBJECT(optmenu), - "filter_func"); - - gtk_option_menu_remove_menu(GTK_OPTION_MENU(optmenu)); - - create_account_menu(optmenu, account, filter_func, show_all); + aop_option_menu_select_by_data(optmenu, account); } GtkWidget * @@ -832,8 +778,7 @@ GtkWidget *optmenu; /* Create the option menu */ - optmenu = gtk_option_menu_new(); - gtk_widget_show(optmenu); + optmenu = aop_option_menu_new(create_account_menu(default_account, filter_func, show_all), cb, user_data); g_signal_connect(G_OBJECT(optmenu), "destroy", G_CALLBACK(account_menu_destroyed_cb), NULL); @@ -855,15 +800,7 @@ /* Set some data. */ g_object_set_data(G_OBJECT(optmenu), "user_data", user_data); g_object_set_data(G_OBJECT(optmenu), "show_all", GINT_TO_POINTER(show_all)); - g_object_set_data(G_OBJECT(optmenu), "filter_func", - filter_func); - - /* Create and set the actual menu. */ - create_account_menu(optmenu, default_account, filter_func, show_all); - - /* And now the last callback. */ - g_signal_connect(G_OBJECT(optmenu), "changed", - G_CALLBACK(account_menu_cb), cb); + g_object_set_data(G_OBJECT(optmenu), "filter_func", filter_func); return optmenu; } @@ -1521,8 +1458,7 @@ else purple_request_choice(NULL, NULL, _("You have dragged an image"), - (ft ? _("You can send this image as a file transfer or " - "embed it into this message, or use it as the buddy icon for this user.") : + (ft ? _("You can send this image as a file transfer, or use it as the buddy icon for this user.") : _("You can insert this image into this message, or use it as the buddy icon for this user")), (ft ? DND_FILE_TRANSFER : DND_IM_IMAGE), "OK", (GCallback)dnd_image_ok_callback, @@ -1903,21 +1839,8 @@ if (account == NULL) return TRUE; - if (optmenu != NULL) { - GList *items; - guint index = 0; - pidgin_account_option_menu_set_selected(optmenu, account); - items = GTK_MENU_SHELL(gtk_option_menu_get_menu(GTK_OPTION_MENU(optmenu)))->children; - - do { - if (account == g_object_get_data(G_OBJECT(items->data), "account")) { - /* Set the account in the GUI. */ - gtk_option_menu_set_history(GTK_OPTION_MENU(optmenu), index); - return TRUE; - } - index++; - } while ((items = items->next) != NULL); - } + if (optmenu != NULL) + aop_option_menu_select_by_data(optmenu, account); return TRUE; } @@ -2115,6 +2038,7 @@ static void screenname_autocomplete_destroyed_cb(GtkWidget *widget, gpointer data) { + g_free(data); purple_signals_disconnect_by_handle(widget); } @@ -2196,7 +2120,7 @@ purple_signal_connect(purple_accounts_get_handle(), "account-removed", entry, PURPLE_CALLBACK(repopulate_autocomplete), cb_data); - g_signal_connect(G_OBJECT(entry), "destroy", G_CALLBACK(screenname_autocomplete_destroyed_cb), NULL); + g_signal_connect(G_OBJECT(entry), "destroy", G_CALLBACK(screenname_autocomplete_destroyed_cb), data); } void pidgin_set_cursor(GtkWidget *widget, GdkCursorType cursor_type) @@ -3111,20 +3035,20 @@ row = pixels; for (i = 3; i < rowstride; i+=4) { - if (row[i] != 0xff) + if (row[i] < 0xfe) return FALSE; } for (i = 1; i < height - 1; i++) { row = pixels + (i*rowstride); - if (row[3] != 0xff || row[rowstride-1] != 0xff) { + if (row[3] < 0xfe || row[rowstride-1] < 0xfe) { return FALSE; - } + } } row = pixels + ((height-1) * rowstride); for (i = 3; i < rowstride; i+=4) { - if (row[i] != 0xff) + if (row[i] < 0xfe) return FALSE; }
--- a/pidgin/pidginstock.c Thu Jun 14 19:48:48 2007 +0000 +++ b/pidgin/pidginstock.c Mon Jun 18 01:48:35 2007 +0000 @@ -109,7 +109,7 @@ { PIDGIN_STOCK_STATUS_XA, "status", "extended-away.png", TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, PIDGIN_STOCK_STATUS_XA_I }, { PIDGIN_STOCK_STATUS_LOGIN, "status", "log-in.png", TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, NULL }, { PIDGIN_STOCK_STATUS_LOGOUT, "status", "log-out.png", TRUE, TRUE, TRUE, TRUE, FALSE, FALSE , NULL }, - { PIDGIN_STOCK_STATUS_OFFLINE, "status", "offline.png", TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, NULL }, + { PIDGIN_STOCK_STATUS_OFFLINE, "status", "offline.png", TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, PIDGIN_STOCK_STATUS_OFFLINE_I }, { PIDGIN_STOCK_STATUS_PERSON, "status", "person.png", TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, NULL }, { PIDGIN_STOCK_STATUS_MESSAGE, "status", "message-pending.png",TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL }, @@ -161,14 +161,17 @@ { PIDGIN_STOCK_TOOLBAR_SELECT_AVATAR, "toolbar", "select-avatar.png", FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, NULL }, { PIDGIN_STOCK_TOOLBAR_SEND_FILE, "toolbar", "send-file.png", TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL }, - { PIDGIN_STOCK_TRAY_AVAILABLE, "tray", "tray-online.png", TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, NULL }, - { PIDGIN_STOCK_TRAY_INVISIBLE, "tray", "tray-invisible.png", TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, NULL }, - { PIDGIN_STOCK_TRAY_AWAY, "tray", "tray-away.png", TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, NULL }, - { PIDGIN_STOCK_TRAY_BUSY, "tray", "tray-busy.png", TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, NULL }, - { PIDGIN_STOCK_TRAY_XA, "tray", "tray-extended-away.png", TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, NULL }, - { PIDGIN_STOCK_TRAY_OFFLINE, "tray", "tray-offline.png", TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, NULL }, - { PIDGIN_STOCK_TRAY_CONNECT, "tray", "tray-connecting.png", TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, NULL }, - { PIDGIN_STOCK_TRAY_PENDING, "tray", "tray-message.png", TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, NULL } + { PIDGIN_STOCK_TRAY_AVAILABLE, "tray", "tray-online.png", TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, NULL }, + { PIDGIN_STOCK_TRAY_INVISIBLE, "tray", "tray-invisible.png", TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, NULL }, + { PIDGIN_STOCK_TRAY_AWAY, "tray", "tray-away.png", TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, NULL }, + { PIDGIN_STOCK_TRAY_BUSY, "tray", "tray-busy.png", TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, NULL }, + { PIDGIN_STOCK_TRAY_XA, "tray", "tray-extended-away.png", TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, NULL }, + { PIDGIN_STOCK_TRAY_OFFLINE, "tray", "tray-offline.png", TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, NULL }, + { PIDGIN_STOCK_TRAY_CONNECT, "tray", "tray-connecting.png", TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, NULL }, + { PIDGIN_STOCK_TRAY_PENDING, "tray", "tray-new-im.png", TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, NULL } +/* Uncomment me after 2.0.2! + * { PIDGIN_STOCK_TRAY_EMAIL, "tray", "tray-message.png", TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, NULL } + */ }; static gchar *
--- a/pidgin/pidginstock.h Thu Jun 14 19:48:48 2007 +0000 +++ b/pidgin/pidginstock.h Mon Jun 18 01:48:35 2007 +0000 @@ -70,6 +70,7 @@ #define PIDGIN_STOCK_STATUS_LOGIN "pidgin-status-login" #define PIDGIN_STOCK_STATUS_LOGOUT "pidgin-status-logout" #define PIDGIN_STOCK_STATUS_OFFLINE "pidgin-status-offline" +#define PIDGIN_STOCK_STATUS_OFFLINE_I "pidgin-status-offline" #define PIDGIN_STOCK_STATUS_PERSON "pidgin-status-person" #define PIDGIN_STOCK_STATUS_MESSAGE "pidgin-status-message" @@ -135,6 +136,9 @@ #define PIDGIN_STOCK_TRAY_OFFLINE "pidgin-tray-offline" #define PIDGIN_STOCK_TRAY_CONNECT "pidgin-tray-connect" #define PIDGIN_STOCK_TRAY_PENDING "pidgin-tray-pending" +/* Uncomment me after 2.0.2! + * #define PIDGIN_STOCK_TRAY_EMAIL "pidgin-tray-email" + */ /*@}*/
--- a/pidgin/pixmaps/emotes/default/22/Makefile.am Thu Jun 14 19:48:48 2007 +0000 +++ b/pidgin/pixmaps/emotes/default/22/Makefile.am Mon Jun 18 01:48:35 2007 +0000 @@ -173,8 +173,15 @@ yin-yang.png pidginsmileypixdir = $(datadir)/pixmaps/pidgin/emotes/default +pidginsmileypix_in_files = default.theme.in pidginsmileypix_DATA = \ $(SMILEYS) \ theme -EXTRA_DIST = $(pidginsmileypix_DATA) +theme: default.theme.in + sed -e 's/^_Name=/Name=/' \ + -e 's/^_Description=/Description=/' \ + -e 's/^_Author=/Author=/' \ + $< > $@ + +EXTRA_DIST = $(pidginsmileypix_DATA) $(pidginsmileypix_in_files)
--- a/pidgin/pixmaps/emotes/default/22/Makefile.mingw Thu Jun 14 19:48:48 2007 +0000 +++ b/pidgin/pixmaps/emotes/default/22/Makefile.mingw Mon Jun 18 01:48:35 2007 +0000 @@ -10,11 +10,13 @@ datadir = $(PIDGIN_INSTALL_DIR) include ./Makefile.am -.PHONY: install +.PHONY: install clean -install: +install: theme if test '$(pidginsmileypix_DATA)'; then \ mkdir -p $(pidginsmileypixdir); \ cp $(pidginsmileypix_DATA) $(pidginsmileypixdir); \ fi; +clean: + rm -f theme
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pidgin/pixmaps/emotes/default/22/default.theme.in Mon Jun 18 01:48:35 2007 +0000 @@ -0,0 +1,357 @@ +_Name=Default +_Description=Pidgin smileys +Icon=smile.png +Author=Hylke Bons + +# default smileys +[default] +smile.png :) :-) +smile-big.png :-D :-d :D :d +sad.png :-( :( +wink.png ;-) ;) +tongue.png :P :-P :-p :p +shock.png =-O =-o +kiss.png :-* +glasses-cool.png 8-) +embarrassed.png :-[ +crying.png :'( +thinking.png :-/ :-\\ +angel.png O:-) o:-) +shut-mouth.png :-X +moneymouth.png :-$ +foot-in-mouth.png :-! +shout.png >:o >:O +! skywalker.png C:-) c:-) C:) c:) +! monkey.png :-(|) + +### Following AIM 6.1 +[AIM] +smile.png :-) :) +wink.png ;-) ;) +sad.png :-( :( +tongue.png :-P :P +shock.png =-O +kiss.png :-* +shout.png >:o +smile-big.png :-D :D +moneymouth.png :-$ +foot-in-mouth.png :-! +embarrassed.png :-[ +angel.png O:-) +thinking.png :-\\ :-/ +crying.png :'( +shut-mouth.png :-X +glasses-cool.png 8-) +! skywalker.png C:-) c:-) C:) c:) +! monkey.png :-(|) + +### Following Windows Live Messenger 8.1 +[MSN] +smile.png :) :-) +smile-big.png :D :d :-D :-d +wink.png ;) ;-) +shock.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 +sad.png :( :-( +crying.png :'( +neutral.png :| :-| +devil.png (6) +angel.png (A) (a) +love.png (L) (l) +love-over.png (U) (u) +msn.png (M) (m) +cat.png (@) +dog.png (&) +moon.png (S) +star.png (*) +film.png (~) +musical-note.png (8) +mail.png (E) (e) +rose.png (F) (f) +rose-dead.png (W) (w) +clock.png (O) (o) +kiss.png (K) (k) +present.png (G) (g) +cake.png (^) +camera.png (P) (p) +lamp.png (I) (i) +coffee.png (C) (c) +phone.png (T) (t) +hug-left.png ({) +hug-right.png (}) +beer.png (B) (b) +drink.png (D) (d) +boy.png (Z) (z) +girl.png (X) (x) +good.png (Y) (y) +bad.png (N) (n) +vampire.png :[ :-[ +goat.png (nah) +sun.png (#) +rainbow.png (R) (r) +quiet.png :-# +teeth.png 8o| +glasses-nerdy.png 8-| +sarcastic.png ^o) +secret.png :-* +sick.png +o( +snail.png (sn) +turtle.png (tu) +plate.png (pl) +bowl.png (||) +pizza.png (pi) +soccerball.png (so) +car.png (au) +airplane.png (ap) +umbrella.png (um) +island.png (ip) +computer.png (co) +mobile.png (mp) +brb.png (brb) +rain.png (st) +highfive.png (h5) +coins.png (mo) +sheep.png (bah) +dont-know.png :^) +thinking.png *-) +thunder.png (li) +party.png <:o) +eyeroll.png 8-) +yawn.png |-) +! skywalker.png C:-) c:-) C:) c:) +! monkey.png :-(|) + +### Hidden MSN emotes +sigarette.png (ci) (CI) +handcuffs.png (%) +console.png (xx) (XX) +fingers-crossed.png (yn) (YN) + +### Following QQ 2006 +[QQ] +shock.png /惊讶 /:O /jy /surprised +curl-lip.png /撇嘴 /:~ /pz /curl_lip +desire.png /色 /:* /se /desire +dazed.png /发呆 /:| /dazed +party.png /得意 /8-) /dy /revel +crying.png /流泪 /:< /ll /cry +bashful.png /害羞 /:$ /hx /bashful +shut-mouth.png /闭嘴 /:X /bz /shut_mouth +sleepy.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 +sad.png /难过 /:( /ng /sad +glasses-cool.png /酷 /:+ /kuk /cool +doctor.png /非典 /:# /feid /SARS +silly.png /抓狂 /:Q /zk /crazy +sick.png /吐 /:T /tu /vomit +snicker.png /偷笑 /;p /tx /titter +cute.png /可爱 /;-D /ka /cute +disdain.png /白眼 /;d /by /disdain +arrogant.png /傲慢 /;o /am /arrogant +starving.png /饥饿 /:g /jie /starving +yawn.png /困 /|-) /kun /sleepy +terror.png /惊恐 /:! /jk /terror +sweat.png /流汗 /:L /sweat +smirk.png /憨笑 /:> /hanx /smirk +soldier.png /大兵 /:; /db /soldier +struggle.png /奋斗 /;f /fendou /struggle +curse.png /咒骂 /:-S /zhm /curse +question.png /疑问 /? /yiw /question +quiet.png /嘘... /;x /xu /shh +hypnotized.png /晕 /;@ /yun /dizzy +excruciating.png /折磨 /:8 /zhem /excrutiating +freaked-out.png /衰 /;! /shuai /freaked_out +skeleton.png /骷髅 /!!! /kl /skeleton +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 +jump.png /跳 /jump /tiao /jump +search.png /找 /find /zhao /search +lashes.png /美眉 /& /mm /beautiful_eyebrows +pig.png /猪头 /pig /zt /pig +cat.png /猫咪 /cat /mm /cat +dog.png /小狗 /dog /xg /dog +hug-left.png /拥抱 /hug /yb /hug +coins.png /钱 /$ /qianc /money +lamp.png /灯泡 /! /dp /lightbulb +bowl.png /酒杯 /cup /bei /cup +cake.png /蛋糕 /cake /dg /cake +thunder.png /闪电 /li /shd /lightning +bomb.png /炸弹 /bome /zhd /bomb +knife.png /刀 /kn /dao /knife +soccerball.png /足球 /footb /zq /soccer +musical-note.png /音乐 /music /yy /music +poop.png /便便 /shit /bb /shit +coffee.png /咖啡 /coffee /kf /coffee +eat.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 +love-over.png /心碎 /break /xs /broken_heart +meeting.png /会议 /meeting /hy /meeting +present.png /礼物 /gift /lw /gift +phone.png /电话 /phone /dh /phone +clock.png /时间 /time /sj /time +mail.png /邮件 /email /yj /email +tv.png /电视 /TV /ds /TV +sun.png /太阳 /sun /ty /sun +moon.png /月亮 /moon /yl /moon +good.png /强 /strong /qiang /thumbs_up +bad.png /弱 /weak /ruo /thumbs_down +handshake.png /握手 /share /ws /handshake +victory.png /胜利 /v /shl /victory +beauty.png /美女 /<J> /mn /beauty +qq.png /Q仔 /<QQ> /qz /qq +blowkiss.png /飞吻 /<L> /fw /blow_kiss +angry.png /怄火 /<O> /oh /angry +liquor.png /白酒 /<B> /bj /baijiu +can.png /汽水 /<U> /qsh /soda +watermelon.png /西瓜 /<W> /xigua /watermelon +rain.png /下雨 /<!!> /xy /rain +cloudy.png /多云 /<~> /duoy /cloudy +snowman.png /雪人 /<Z> /xr /snowman +star.png /星星 /<*> /xixing /star +girl.png /女 /<00> /nv /woman +boy.png /男 /<11> /nan /man +! skywalker.png C:-) c:-) C:) c:) +! monkey.png :-(|) + +### Following ICQ 5.1 +[ICQ] +smile.png :-) :) +sad.png :-( :( +wink.png ;-) ;) +tongue.png :-P :P +laugh.png *JOKINGLY* +crying.png :'( +#*KISSED* +kiss.png :-* +embarrassed.png :-[ +angel.png O:-) +shut-mouth.png :-X :X +thinking.png :-\\ :-/ +shout.png >:o >:O +smile-big.png :-D :D +moneymouth.png :-$ +shock.png =-O +glasses-cool.png 8-) +#[:-} +sleepy.png *TIRED* +sick.png :-! +#*STOP* +#*KISSING* +devil.png ]:-> +rose.png @}->-- +bomb.png @= +good.png *THUMBS\ UP* +beer.png *DRINK* +in-love.png *IN\ LOVE* +! skywalker.png C:-) c:-) C:) c:) +! monkey.png :-(|) + +### Following Yahoo! Messenger 8.1 +[Yahoo] +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 :)] MISSING: "Wait,I'm phoning!" (not phone.png) => smily showing phone and hand ("stop") +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 ~x( ~X( MISSING: "Why.Does.This.Not.Work.AAAAARGH!!" => angry smily shouting and pulling hair off +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 +#timeout :-t :-T MISSING: "Let's have a break." +hug-left.png >:D< >:d< +love-over.png =(( +sweat.png #:-S #:-s +rotfl.png =)) +#loser L-) l-) MISSING/YAHOO 6: "Loser!" +party.png <:-P <:-p +nailbiting.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 :-@ +#youkiddingme.png :-j :-J + +### These only work in a certain IMvironment +#malefighter1.png o-> O-> +#malefighter2.png o=> O=> +#femalefighter.png o-+ O-+ +yin-yang.png (%) +
--- a/pidgin/pixmaps/emotes/default/22/theme Thu Jun 14 19:48:48 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,358 +0,0 @@ -Name=Default -Description=Pidgin smileys -Icon=smile.png -Author=Hylke Bons - -# default smileys -[default] -smile.png :) :-) -smile-big.png :-D :-d :D :d -sad.png :-( :( -wink.png ;-) ;) -tongue.png :P :-P :-p :p -shock.png =-O =-o -kiss.png :-* -glasses-cool.png 8-) -embarrassed.png :-[ -crying.png :'( -thinking.png :-/ :-\\ -angel.png O:-) o:-) -shut-mouth.png :-X -moneymouth.png :-$ -foot-in-mouth.png :-! -shout.png >:o >:O -! skywalker.png C:-) c:-) C:) c:) -! monkey.png :-(|) - -### Following AIM 6.1 -[AIM] -smile.png :-) :) -wink.png ;-) ;) -sad.png :-( :( -tongue.png :-P :P -shock.png =-O -kiss.png :-* -shout.png >:o -smile-big.png :-D :D -moneymouth.png :-$ -foot-in-mouth.png :-! -embarrassed.png :-[ -angel.png O:-) -thinking.png :-\\ :-/ -crying.png :'( -shut-mouth.png :-X -glasses-cool.png 8-) -! skywalker.png C:-) c:-) C:) c:) -! monkey.png :-(|) - -### Following Windows Live Messenger 8.1 -[MSN] -smile.png :) :-) -smile-big.png :D :d :-D :-d -wink.png ;) ;-) -shock.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 -sad.png :( :-( -crying.png :'( -neutral.png :| :-| -devil.png (6) -angel.png (A) (a) -love.png (L) (l) -love-over.png (U) (u) -msn.png (M) (m) -cat.png (@) -dog.png (&) -moon.png (S) -star.png (*) -film.png (~) -musical-note.png (8) -mail.png (E) (e) -rose.png (F) (f) -rose-dead.png (W) (w) -clock.png (O) (o) -kiss.png (K) (k) -present.png (G) (g) -cake.png (^) -camera.png (P) (p) -lamp.png (I) (i) -coffee.png (C) (c) -phone.png (T) (t) -hug-left.png ({) -hug-right.png (}) -beer.png (B) (b) -drink.png (D) (d) -boy.png (Z) (z) -girl.png (X) (x) -good.png (Y) (y) -bad.png (N) (n) -vampire.png :[ :-[ -#goat.png (nah) -sun.png (#) -rainbow.png (R) (r) -quiet.png :-# -teeth.png 8o| -glasses-nerdy.png 8-| -sarcastic.png ^o) -secret.png :-* -sick.png +o( -snail.png (sn) -turtle.png (tu) -plate.png (pl) -bowl.png (||) -pizza.png (pi) -soccerball.png (so) -car.png (au) -airplane.png (ap) -umbrella.png (um) -island.png (ip) -computer.png (co) -mobile.png (mp) -brb.png (brb) -rain.png (st) -highfive.png (h5) -coins.png (mo) -sheep.png (bah) -dont-know.png :^) -thinking.png *-) -thunder.png (li) -party.png <:o) -eyeroll.png 8-) -yawn.png |-) -goat.png (nah) -! skywalker.png C:-) c:-) C:) c:) -! monkey.png :-(|) - -### Hidden MSN emotes -sigarette.png (ci) (CI) -handcuffs.png (%) -console.png (xx) (XX) -fingers-crossed.png (yn) (YN) - -### Following QQ 2006 -[QQ] -shock.png /惊讶 /:O /jy /surprised -curl-lip.png /撇嘴 /:~ /pz /curl_lip -desire.png /色 /:* /se /desire -dazed.png /发呆 /:| /dazed -party.png /得意 /8-) /dy /revel -crying.png /流泪 /:< /ll /cry -bashful.png /害羞 /:$ /hx /bashful -shut-mouth.png /闭嘴 /:X /bz /shut_mouth -sleepy.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 -sad.png /难过 /:( /ng /sad -glasses-cool.png /酷 /:+ /kuk /cool -doctor.png /非典 /:# /feid /SARS -silly.png /抓狂 /:Q /zk /crazy -sick.png /吐 /:T /tu /vomit -snicker.png /偷笑 /;p /tx /titter -cute.png /可爱 /;-D /ka /cute -disdain.png /白眼 /;d /by /disdain -arrogant.png /傲慢 /;o /am /arrogant -starving.png /饥饿 /:g /jie /starving -yawn.png /困 /|-) /kun /sleepy -terror.png /惊恐 /:! /jk /terror -sweat.png /流汗 /:L /sweat -smirk.png /憨笑 /:> /hanx /smirk -soldier.png /大兵 /:; /db /soldier -struggle.png /奋斗 /;f /fendou /struggle -curse.png /咒骂 /:-S /zhm /curse -question.png /疑问 /? /yiw /question -quiet.png /嘘... /;x /xu /shh -hypnotized.png /晕 /;@ /yun /dizzy -excruciating.png /折磨 /:8 /zhem /excrutiating -freaked-out.png /衰 /;! /shuai /freaked_out -skeleton.png /骷髅 /!!! /kl /skeleton -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 -jump.png /跳 /jump /tiao /jump -search.png /找 /find /zhao /search -lashes.png /美眉 /& /mm /beautiful_eyebrows -pig.png /猪头 /pig /zt /pig -cat.png /猫咪 /cat /mm /cat -dog.png /小狗 /dog /xg /dog -hug-left.png /拥抱 /hug /yb /hug -coins.png /钱 /$ /qianc /money -lamp.png /灯泡 /! /dp /lightbulb -bowl.png /酒杯 /cup /bei /cup -cake.png /蛋糕 /cake /dg /cake -thunder.png /闪电 /li /shd /lightning -bomb.png /炸弹 /bome /zhd /bomb -knife.png /刀 /kn /dao /knife -soccerball.png /足球 /footb /zq /soccer -musical-note.png /音乐 /music /yy /music -poop.png /便便 /shit /bb /shit -coffee.png /咖啡 /coffee /kf /coffee -eat.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 -love-over.png /心碎 /break /xs /broken_heart -meeting.png /会议 /meeting /hy /meeting -present.png /礼物 /gift /lw /gift -phone.png /电话 /phone /dh /phone -clock.png /时间 /time /sj /time -mail.png /邮件 /email /yj /email -tv.png /电视 /TV /ds /TV -sun.png /太阳 /sun /ty /sun -moon.png /月亮 /moon /yl /moon -good.png /强 /strong /qiang /thumbs_up -bad.png /弱 /weak /ruo /thumbs_down -handshake.png /握手 /share /ws /handshake -victory.png /胜利 /v /shl /victory -beauty.png /美女 /<J> /mn /beauty -qq.png /Q仔 /<QQ> /qz /qq -blowkiss.png /飞吻 /<L> /fw /blow_kiss -angry.png /怄火 /<O> /oh /angry -liquor.png /白酒 /<B> /bj /baijiu -can.png /汽水 /<U> /qsh /soda -watermelon.png /西瓜 /<W> /xigua /watermelon -rain.png /下雨 /<!!> /xy /rain -cloudy.png /多云 /<~> /duoy /cloudy -snowman.png /雪人 /<Z> /xr /snowman -star.png /星星 /<*> /xixing /star -girl.png /女 /<00> /nv /woman -boy.png /男 /<11> /nan /man -! skywalker.png C:-) c:-) C:) c:) -! monkey.png :-(|) - -### Following ICQ 5.1 -[ICQ] -smile.png :-) :) -sad.png :-( :( -wink.png ;-) ;) -tongue.png :-P :P -laugh.png *JOKINGLY* -crying.png :'( -#*KISSED* -kiss.png :-* -embarrassed.png :-[ -angel.png O:-) -shut-mouth.png :-X :X -thinking.png :-\\ :-/ -shout.png >:o >:O -smile-big.png :-D :D -moneymouth.png :-$ -shock.png =-O -glasses-cool.png 8-) -#[:-} -sleepy.png *TIRED* -sick.png :-! -#*STOP* -#*KISSING* -devil.png ]:-> -rose.png @}->-- -bomb.png @= -good.png *THUMBS\ UP* -beer.png *DRINK* -in-love.png *IN\ LOVE* -! skywalker.png C:-) c:-) C:) c:) -! monkey.png :-(|) - -### Following Yahoo! Messenger 8.1 -[Yahoo] -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 :)] MISSING: "Wait,I'm phoning!" (not phone.png) => smily showing phone and hand ("stop") -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 ~x( ~X( MISSING: "Why.Does.This.Not.Work.AAAAARGH!!" => angry smily shouting and pulling hair off -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 -#timeout :-t :-T MISSING: "Let's have a break." -hug-left.png >:D< >:d< -love-over.png =(( -sweat.png #:-S #:-s -rotfl.png =)) -#loser L-) l-) MISSING/YAHOO 6: "Loser!" -party.png <:-P <:-p -nailbiting.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 :-@ -#youkiddingme.png :-j :-J - -### These only work in a certain IMvironment -#malefighter1.png o-> O-> -#malefighter2.png o=> O=> -#femalefighter.png o-+ O-+ -yin-yang.png (%) -
--- a/pidgin/pixmaps/emotes/none/Makefile.am Thu Jun 14 19:48:48 2007 +0000 +++ b/pidgin/pixmaps/emotes/none/Makefile.am Mon Jun 18 01:48:35 2007 +0000 @@ -1,5 +1,13 @@ pidginsmileypixdir = $(datadir)/pixmaps/pidgin/emotes/none +pidginsmileypix_in_files = none.theme.in pidginsmileypix_DATA = theme +theme: none.theme.in + sed -e 's/^_Name=/Name=/' \ + -e 's/^_Description=/Description=/' \ + -e 's/^_Author=/Author=/' \ + $< > $@ + EXTRA_DIST = $(pidginsmileypix_DATA) \ + $(pidginsmileypix_in_files) \ Makefile.mingw
--- a/pidgin/pixmaps/emotes/none/Makefile.mingw Thu Jun 14 19:48:48 2007 +0000 +++ b/pidgin/pixmaps/emotes/none/Makefile.mingw Mon Jun 18 01:48:35 2007 +0000 @@ -10,11 +10,14 @@ datadir = $(PIDGIN_INSTALL_DIR) include ./Makefile.am -.PHONY: install +.PHONY: install clean -install: +install: theme if test '$(pidginsmileypix_DATA)'; then \ mkdir -p $(pidginsmileypixdir); \ cp $(pidginsmileypix_DATA) $(pidginsmileypixdir); \ fi; +clean: + rm -f theme +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pidgin/pixmaps/emotes/none/none.theme.in Mon Jun 18 01:48:35 2007 +0000 @@ -0,0 +1,3 @@ +_Name=none +_Description=Selecting this disables graphical emoticons. +_Author=Penguin Pimps
--- a/pidgin/pixmaps/emotes/none/theme Thu Jun 14 19:48:48 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ -Name=none -Description=Selecting this disables graphical emoticons. -Author=Penguin Pimps
--- a/pidgin/pixmaps/icons/16/scalable/pidgin.svg Thu Jun 14 19:48:48 2007 +0000 +++ b/pidgin/pixmaps/icons/16/scalable/pidgin.svg Mon Jun 18 01:48:35 2007 +0000 @@ -14,7 +14,7 @@ id="svg4345" sodipodi:version="0.32" inkscape:version="0.44.1" - sodipodi:docbase="/home/hbons/Desktop/icons/16/scalable" + sodipodi:docbase="/home/hbons/Desktop/2.0.2/pidgin/pixmaps/icons/16/scalable" sodipodi:docname="pidgin.svg" inkscape:export-filename="/home/hbons/Desktop/pidgin16.png" inkscape:export-xdpi="90" @@ -24,6 +24,54 @@ id="defs4347"> <linearGradient inkscape:collect="always" + id="linearGradient3157"> + <stop + style="stop-color:#eeeeec;stop-opacity:1;" + offset="0" + id="stop3159" /> + <stop + style="stop-color:#eeeeec;stop-opacity:0;" + offset="1" + id="stop3161" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient3149"> + <stop + style="stop-color:#3b1941;stop-opacity:1;" + offset="0" + id="stop3151" /> + <stop + style="stop-color:#3b1941;stop-opacity:0;" + offset="1" + id="stop3153" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient3141"> + <stop + style="stop-color:#82508e;stop-opacity:1;" + offset="0" + id="stop3143" /> + <stop + style="stop-color:#82508e;stop-opacity:0;" + offset="1" + id="stop3145" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient3128"> + <stop + style="stop-color:#eeeeec;stop-opacity:1;" + offset="0" + id="stop3130" /> + <stop + style="stop-color:#eeeeec;stop-opacity:0;" + offset="1" + id="stop3132" /> + </linearGradient> + <linearGradient + inkscape:collect="always" id="linearGradient5438"> <stop style="stop-color:white;stop-opacity:1;" @@ -72,18 +120,6 @@ </linearGradient> <linearGradient inkscape:collect="always" - id="linearGradient5304"> - <stop - style="stop-color:#2e3436;stop-opacity:1;" - offset="0" - id="stop5306" /> - <stop - style="stop-color:#2e3436;stop-opacity:0;" - offset="1" - id="stop5308" /> - </linearGradient> - <linearGradient - inkscape:collect="always" id="linearGradient5280"> <stop style="stop-color:#82508e;stop-opacity:1;" @@ -178,24 +214,6 @@ gradientUnits="userSpaceOnUse" /> <linearGradient inkscape:collect="always" - xlink:href="#linearGradient5304" - id="linearGradient5310" - x1="12.606371" - y1="15.069461" - x2="12.606371" - y2="21.152372" - gradientUnits="userSpaceOnUse" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient6506" - id="linearGradient6512" - x1="15.645709" - y1="39.743458" - x2="15.645709" - y2="53.502155" - gradientUnits="userSpaceOnUse" /> - <linearGradient - inkscape:collect="always" xlink:href="#linearGradient6537" id="linearGradient6543" x1="30.5" @@ -211,7 +229,8 @@ y1="38.950283" x2="5.7089725" y2="42.982571" - gradientUnits="userSpaceOnUse" /> + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.63556,0,0,0.371995,11.16667,-5.489292)" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient5438" @@ -221,6 +240,421 @@ x2="30.152058" y2="23.011967" gradientUnits="userSpaceOnUse" /> + <linearGradient + inkscape:collect="always" + id="linearGradient3976"> + <stop + style="stop-color:#3b1941;stop-opacity:1;" + offset="0" + id="stop3978" /> + <stop + style="stop-color:#3b1941;stop-opacity:0;" + offset="1" + id="stop3980" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient3968"> + <stop + style="stop-color:#82508e;stop-opacity:1;" + offset="0" + id="stop3970" /> + <stop + style="stop-color:#82508e;stop-opacity:0;" + offset="1" + id="stop3972" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient3958"> + <stop + style="stop-color:#eeeeec;stop-opacity:1;" + offset="0" + id="stop3960" /> + <stop + style="stop-color:#eeeeec;stop-opacity:0;" + offset="1" + id="stop3962" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient2850"> + <stop + style="stop-color:#ce5c00;stop-opacity:1;" + offset="0" + id="stop2852" /> + <stop + style="stop-color:#ce5c00;stop-opacity:0;" + offset="1" + id="stop2854" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient6563"> + <stop + style="stop-color:white;stop-opacity:1;" + offset="0" + id="stop6565" /> + <stop + style="stop-color:white;stop-opacity:0;" + offset="1" + id="stop6567" /> + </linearGradient> + <linearGradient + id="linearGradient2110"> + <stop + style="stop-color:black;stop-opacity:0;" + offset="0" + id="stop2112" /> + <stop + id="stop2114" + offset="0.5" + style="stop-color:black;stop-opacity:1;" /> + <stop + style="stop-color:black;stop-opacity:0;" + offset="1" + id="stop2067" /> + </linearGradient> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient25546" + id="radialGradient2069" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1,0,0,0.994693,0,4.16407e-2)" + cx="7.8836637" + cy="1.5104795" + fx="7.8836637" + fy="1.5104795" + r="8.4883642" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient25546" + id="radialGradient2071" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1,0,0,0.994693,0,4.16407e-2)" + cx="7.8836741" + cy="0.14505707" + fx="7.8836741" + fy="0.14505707" + r="8.4883642" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient25546" + id="radialGradient2079" + cx="7.8836637" + cy="2.6242435" + fx="7.8836637" + fy="2.6242435" + r="8.4883642" + gradientTransform="matrix(1.131317,0,0,1.125313,-1.035262,-0.301139)" + gradientUnits="userSpaceOnUse" /> + <linearGradient + id="linearGradient2081"> + <stop + style="stop-color:#f4d9b1;stop-opacity:1.0000000;" + offset="0.0000000" + id="stop2104" /> + <stop + style="stop-color:#df9725;stop-opacity:1.0000000;" + offset="1.0000000" + id="stop2085" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient6506" + id="linearGradient2101" + x1="15.645709" + y1="39.743458" + x2="14.943421" + y2="50.079575" + gradientUnits="userSpaceOnUse" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient6537" + id="linearGradient2089" + x1="30.5" + y1="0.033532728" + x2="30.5" + y2="23.559282" + gradientUnits="userSpaceOnUse" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient6563" + id="linearGradient6569" + x1="-1.6841649" + y1="39.902092" + x2="5.5366187" + y2="44.272076" + gradientUnits="userSpaceOnUse" /> + <linearGradient + gradientUnits="userSpaceOnUse" + y2="23.011967" + x2="30.152058" + y1="-0.86487341" + x1="30.152058" + id="linearGradient2097" + xlink:href="#linearGradient5438" + inkscape:collect="always" /> + <linearGradient + gradientUnits="userSpaceOnUse" + y2="42.982571" + x2="5.7089725" + y1="38.950283" + x1="0.23931108" + id="linearGradient2095" + xlink:href="#linearGradient6817" + inkscape:collect="always" /> + <linearGradient + gradientUnits="userSpaceOnUse" + y2="50.726673" + x2="15.645709" + y1="40.434063" + x1="15.645709" + id="linearGradient2093" + xlink:href="#linearGradient6506" + inkscape:collect="always" /> + <linearGradient + id="linearGradient2087"> + <stop + id="stop2089" + offset="0.0000000" + style="stop-color:#f4d9b1;stop-opacity:1.0000000;" /> + <stop + id="stop2091" + offset="1.0000000" + style="stop-color:#df9725;stop-opacity:1.0000000;" /> + </linearGradient> + <radialGradient + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1.131317,0,0,1.125313,-1.035262,-0.301139)" + r="8.4883642" + fy="2.6242435" + fx="7.8836637" + cy="2.6242435" + cx="7.8836637" + id="radialGradient2085" + xlink:href="#linearGradient25546" + inkscape:collect="always" /> + <radialGradient + r="8.4883642" + fy="0.14505707" + fx="7.8836741" + cy="0.14505707" + cx="7.8836741" + gradientTransform="matrix(1,0,0,0.994693,0,4.16407e-2)" + gradientUnits="userSpaceOnUse" + id="radialGradient2077" + xlink:href="#linearGradient25546" + inkscape:collect="always" /> + <radialGradient + r="8.4883642" + fy="1.5104795" + fx="7.8836637" + cy="1.5104795" + cx="7.8836637" + gradientTransform="matrix(1,0,0,0.994693,0,4.16407e-2)" + gradientUnits="userSpaceOnUse" + id="radialGradient2075" + xlink:href="#linearGradient25546" + inkscape:collect="always" /> + <linearGradient + id="linearGradient2067"> + <stop + id="stop2069" + offset="0" + style="stop-color:black;stop-opacity:0;" /> + <stop + style="stop-color:black;stop-opacity:1;" + offset="0.5" + id="stop2071" /> + <stop + id="stop2073" + offset="1" + style="stop-color:black;stop-opacity:0;" /> + </linearGradient> + <linearGradient + id="linearGradient3108" + inkscape:collect="always"> + <stop + id="stop3110" + offset="0" + style="stop-color:#eeeeec;stop-opacity:1;" /> + <stop + id="stop3112" + offset="1" + style="stop-color:#eeeeec;stop-opacity:0;" /> + </linearGradient> + <linearGradient + id="linearGradient3116" + inkscape:collect="always"> + <stop + id="stop3118" + offset="0" + style="stop-color:#82508e;stop-opacity:1;" /> + <stop + id="stop3120" + offset="1" + style="stop-color:#82508e;stop-opacity:0;" /> + </linearGradient> + <linearGradient + id="linearGradient3124" + inkscape:collect="always"> + <stop + id="stop3126" + offset="0" + style="stop-color:#3b1941;stop-opacity:1;" /> + <stop + id="stop3128" + offset="1" + style="stop-color:#3b1941;stop-opacity:0;" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2850" + id="linearGradient2187" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.769231,0,0,0.714287,47.76924,-9.285729)" + x1="21.785719" + y1="28.142857" + x2="17.785713" + y2="30.07143" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2850" + id="linearGradient2195" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.769231,0,0,0.714287,13.76923,-8.28573)" + x1="21.785719" + y1="28.142857" + x2="17.785713" + y2="30.07143" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3958" + id="radialGradient2209" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1.116159,0,0,1.076653,14.60502,-22.28695)" + cx="9.0640488" + cy="21.511742" + fx="9.0640488" + fy="21.511742" + r="16.663956" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient6506" + id="linearGradient2211" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.660903,0,0,0.627207,18.73149,-12.3201)" + x1="15.645709" + y1="39.743458" + x2="15.645709" + y2="53.502155" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3968" + id="linearGradient2214" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.67692,0,0,0.646801,18.46433,-12.90841)" + x1="16.13257" + y1="40.781811" + x2="16.13257" + y2="48.068741" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3976" + id="linearGradient2216" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.67692,0,0,0.646801,18.46433,-12.90841)" + x1="12.095973" + y1="40.907658" + x2="12.095973" + y2="46.463146" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient6537" + id="linearGradient2219" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.668893,0,0,0.668627,18.08624,-12.19246)" + x1="30.5" + y1="0.033532728" + x2="30.5" + y2="23.559282" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3108" + id="linearGradient2229" + gradientUnits="userSpaceOnUse" + x1="10.18327" + y1="16.618088" + x2="27.598003" + y2="36.64465" + gradientTransform="matrix(0.660903,0,0,0.627207,49.74106,-7.361383)" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient6506" + id="linearGradient2231" + gradientUnits="userSpaceOnUse" + x1="15.645709" + y1="39.743458" + x2="15.645709" + y2="53.502155" + gradientTransform="matrix(0.660903,0,0,0.627207,49.74106,-7.361383)" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3116" + id="linearGradient2234" + gradientUnits="userSpaceOnUse" + x1="15.722902" + y1="39.585075" + x2="15.722902" + y2="45.76453" + gradientTransform="matrix(0.67692,0,0,0.646801,49.4739,-7.949693)" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3124" + id="linearGradient2236" + gradientUnits="userSpaceOnUse" + x1="13.150809" + y1="39.39394" + x2="13.150809" + y2="45.551888" + gradientTransform="matrix(0.67692,0,0,0.646801,49.4739,-7.949693)" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3128" + id="linearGradient3134" + x1="8.0725698" + y1="17.765934" + x2="24.284664" + y2="37.578945" + gradientUnits="userSpaceOnUse" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3141" + id="linearGradient3147" + x1="12.353984" + y1="38.611191" + x2="12.353984" + y2="45.595356" + gradientUnits="userSpaceOnUse" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3149" + id="linearGradient3155" + x1="10.166225" + y1="38.766953" + x2="10.166225" + y2="45.595673" + gradientUnits="userSpaceOnUse" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3157" + id="linearGradient3163" + x1="11.982447" + y1="39.088425" + x2="11.982447" + y2="45.778931" + gradientUnits="userSpaceOnUse" /> </defs> <sodipodi:namedview id="base" @@ -229,17 +663,17 @@ borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="42.440064" - inkscape:cx="13.087113" - inkscape:cy="8.5298663" + inkscape:zoom="30.009658" + inkscape:cx="12.410351" + inkscape:cy="9.6914614" inkscape:current-layer="layer1" showgrid="true" inkscape:grid-bbox="true" inkscape:document-units="px" - inkscape:window-width="1274" - inkscape:window-height="966" - inkscape:window-x="3" - inkscape:window-y="25" + inkscape:window-width="1434" + inkscape:window-height="840" + inkscape:window-x="0" + inkscape:window-y="0" showguides="true" inkscape:guide-bbox="true" inkscape:grid-points="false" @@ -268,7 +702,7 @@ transform="matrix(1.148904,0,0,0.920169,-34.28919,-3.241212)" sodipodi:nodetypes="csccccc" /> <path - style="opacity:1;fill:#82508e;fill-opacity:1;stroke:#3b1941;stroke-width:2.30209565;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + style="opacity:1;fill:url(#linearGradient3147);fill-opacity:1.0;stroke:url(#linearGradient3155);stroke-width:2.30209565;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" d="M 15,13 C 8.3759979,13 3,18.600001 3,25.5 C 3,31.153143 2.9750563,38.402618 2.9750563,45.572826 C 4.1625449,45.572826 27.946366,45.600605 30.637365,45.600605 C 32.751492,45.600605 32.586331,43.541005 32.586331,43.541005 C 32.586331,40.875594 27.597902,38.639057 25.813453,36.682531 C 23.985035,34.68151 26,30.884078 26,30.884078 C 26.641306,29.354278 28.01889,26.891006 28.01889,25.115922 C 28.01889,18.215923 21.624002,13 15,13 z " id="path5176" sodipodi:nodetypes="ccccszcsc" @@ -284,34 +718,17 @@ ry="0.32910046" transform="matrix(1.147027,0,0,0.866113,-0.324314,2.386999)" /> <path - sodipodi:type="arc" - style="opacity:1;fill:url(#radialGradient5286);fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="path5273" - sodipodi:cx="15.004828" - sodipodi:cy="39.80859" - sodipodi:rx="9.7225161" - sodipodi:ry="7.119638" - d="M 24.727345 39.80859 A 9.7225161 7.119638 0 1 1 5.2823124,39.80859 A 9.7225161 7.119638 0 1 1 24.727345 39.80859 z" - transform="matrix(0.434788,0,0,0.500648,-1.130366,-6.547801)" /> - <path - style="opacity:0.5152838;fill:#5c3466;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1" - d="M -42.833794,49.038847 C -42.833794,49.038847 -42.815855,44.709724 -42.815855,37.951005 C -42.815855,37.951005 -39.03087,40.509965 -38.631892,41.678764 C -39.153711,41.596001 -40.372039,41.685633 -40.372039,41.685633 C -40.038351,42.463101 -38.163796,45.952105 -36.121045,48.058218 C -37.780497,47.329365 -39.471111,47.196178 -39.471111,47.196178 C -39.009636,48.111847 -37.250115,48.69173 -36.943887,49.110993 C -36.943887,49.110993 -41.348464,49.038847 -42.833794,49.038847 z " - id="rect5312" - sodipodi:nodetypes="cccccccc" - transform="matrix(0.446908,0,0,0.358425,20.14277,-2.602607)" /> - <path - style="opacity:0.5152838;fill:#5c3466;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1" - d="M -49.441852,47.4154 C -47.112614,42.001764 -42.19329,43.469796 -40.961409,37.951005 C -40.961409,37.951005 -39.025024,40.280009 -38.974466,41.581367 C -39.496285,41.498604 -39.881988,41.516405 -39.881988,41.516405 C -39.5483,42.293873 -38.196948,45.748112 -36.154197,47.854225 C -37.813649,47.125372 -38.925816,46.898039 -38.925816,46.898039 C -38.847603,47.794771 -38.376224,47.369394 -38.122982,48.215235 C -42.942294,48.046898 -46.252916,49.195571 -49.441852,47.4154 z " - id="path5317" - sodipodi:nodetypes="cccccccc" - transform="matrix(-0.376289,0,0,0.381853,-5.604413,-3.491724)" /> - <path transform="matrix(0.399589,0,0,0.393554,-5.973603e-2,-3.038964)" - style="opacity:0.31004363;fill:url(#linearGradient5310);fill-opacity:1;stroke:url(#linearGradient6512);stroke-width:2.5216887;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + style="opacity:0.5;fill:url(#linearGradient3134);fill-opacity:1.0;stroke:url(#linearGradient3163);stroke-width:2.5216887;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" d="M 15,14.0625 C 8.9877035,14.0625 4.0789961,19.13808 4.0625,25.46875 C 4.0624722,25.479427 4.0617033,25.489349 4.0625,25.5 C 4.0625,32.787473 3.9033639,38.26012 3.9033639,44.499878 C 5.8399452,44.499878 24.86993,44.470084 30.695903,44.470084 C 29.746978,42.549359 26.273076,40.711023 23.972608,38.78763 C 23.362603,37.973536 23.023697,35.459892 22.969233,34.418473 C 23.611113,31.359155 25.129532,28.401757 26.527172,25.440129 C 26.527172,19.094533 21.022436,14.0625 15,14.0625 z " id="path5241" sodipodi:nodetypes="csccccccc" /> <path + style="opacity:1;fill:#a46bb0;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1" + d="M 6,7.2175674 C 6,8.8735678 4.5070272,10 3.4999996,10 C 2.1199999,10 1,8.6559998 1,6.9999995 C 1,5.5609093 1.7677476,4 3.1477475,4 C 4.5277481,4 6,5.9092686 6,7.2175674 z " + id="path3137" + sodipodi:nodetypes="csssc" /> + <path transform="matrix(0.626764,0,0,0.689441,-3.309086,-9.833164)" style="opacity:1;fill:white;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1" d="M 13.257119,24.626053 C 13.257119,26.227351 11.8279,27.316574 10.863875,27.316574 C 9.5428049,27.316574 8.4706318,26.01697 8.4706318,24.415672 C 8.4706318,23.024119 9.2055946,21.514771 10.526665,21.514771 C 11.847736,21.514771 13.257119,23.360971 13.257119,24.626053 z " @@ -326,7 +743,12 @@ sodipodi:rx="1.2410715" sodipodi:ry="1.2946428" d="M 11.410714 24.3125 A 1.2410715 1.2946428 0 1 1 8.928571,24.3125 A 1.2410715 1.2946428 0 1 1 11.410714 24.3125 z" - transform="matrix(0.805756,0,0,0.772414,-5.19425,-11.77932)" /> + transform="matrix(1.208634,0,0,1.158623,-8.791372,-20.66902)" /> + <path + style="opacity:1;fill:#a46bb0;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1" + d="M 11.387086,4.6790601 C 10.509745,3.6558267 9.0824486,3.9284339 8.5222543,4.5817815 C 7.7545814,5.4771092 7.8435868,7.0342022 8.7209273,8.0574357 C 9.4833498,8.9466415 10.737398,9.413013 11.505071,8.5176851 C 12.272744,7.6223568 12.080215,5.4874505 11.387086,4.6790601 z " + id="path3139" + sodipodi:nodetypes="csssc" /> <path transform="matrix(0.29055,-0.412361,-0.273947,-0.388798,13.58792,20.45445)" style="opacity:1;fill:white;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1" @@ -342,30 +764,21 @@ sodipodi:rx="1.2410715" sodipodi:ry="1.2946428" d="M 11.410714 24.3125 A 1.2410715 1.2946428 0 1 1 8.928571,24.3125 A 1.2410715 1.2946428 0 1 1 11.410714 24.3125 z" - transform="matrix(0.805755,0,0,0.772417,0.805755,-11.77938)" /> + transform="matrix(1.208633,0,0,1.158626,-2.791363,-20.66909)" /> <path - transform="matrix(0.63556,0,0,0.371992,4.635114,-6.489142)" - style="fill:#f9751a;fill-opacity:1;stroke:none;stroke-width:1.0283047;stroke-miterlimit:4;stroke-opacity:1" - d="M -0.99929609,42.004237 C 2.9290204,42.117701 4.1278823,38.950282 4.9828709,38.950282 C 5.8260957,38.950282 7.1161651,42.240122 10.014606,42.007796 C 9.2074596,43.955072 6.7265914,47.014858 5.6807127,47.014858 C 4.6230593,47.014858 0.31231911,44.880662 -0.99929609,42.004237 z " - id="rect5187" - sodipodi:nodetypes="ccczc" /> - <path - transform="matrix(0.743268,0,0,0.267357,-7.659906,-1.671861)" style="fill:#3b1941;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1" - d="M 11.651119,11.193815 C 13.577759,8.2509126 16.249277,11.481501 17.614226,12.804399 L 14.761306,13.747613 L 11.651119,11.193815 z " + d="M -3.174544e-16,1.7837407 C 0.49897694,0.43045085 3.4176637,1.3941391 4.4321866,1.7478251 L 2.7448964,2 L -3.174544e-16,1.7837407 z " id="path5192" sodipodi:nodetypes="cccc" /> <path - transform="matrix(0.686065,0,0,0.46633,-5.019573,-4.365629)" - style="fill:#3b1941;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1" - d="M 11.689238,9.8218679 C 13.591296,8.0161941 17.174576,11.994261 17.519594,13.650486 L 14.543472,12.891665 L 11.689238,9.8218679 z " - id="rect5189" - sodipodi:nodetypes="cccc" /> + style="fill:#fcaf3e;fill-opacity:1;stroke:none;stroke-width:1.0283047;stroke-miterlimit:4;stroke-opacity:1" + d="M 4,8.9694498 C 6.5363255,9.6796143 7.1434322,8 7.6676187,8 C 8.1845929,8 8.1150542,9.7216455 10.752536,9.1373864 C 10.257681,9.8617678 8.7366795,11 8.0954601,11 C 7.4470215,11 4.8041406,10.039472 4,8.9694498 z " + id="path3987" + sodipodi:nodetypes="czczc" /> <path - transform="matrix(0.63556,0,0,0.371995,4.635112,-6.489295)" - style="fill:url(#linearGradient6823);fill-opacity:1;stroke:none;stroke-width:1.0283047;stroke-miterlimit:4;stroke-opacity:1" - d="M -0.99929609,42.004237 C 2.9290204,42.117701 4.1278823,38.950282 4.9828709,38.950282 C 5.8260957,38.950282 7.1161651,42.240122 10.014606,42.007796 C 9.2074596,43.955072 6.7265914,47.014858 5.6807127,47.014858 C 4.6230593,47.014858 0.31231911,44.880662 -0.99929609,42.004237 z " - id="path6815" - sodipodi:nodetypes="ccczc" /> + style="fill:#3b1941;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1" + d="M 2.5678134,0.78213791 C 3.0667903,-0.57115198 7,-0.11652293 7,1.7459005 L 5.3127098,0.99839721 L 2.5678134,0.78213791 z " + id="path1991" + sodipodi:nodetypes="cccc" /> </g> </svg>
--- a/pidgin/pixmaps/icons/24/scalable/pidgin.svg Thu Jun 14 19:48:48 2007 +0000 +++ b/pidgin/pixmaps/icons/24/scalable/pidgin.svg Mon Jun 18 01:48:35 2007 +0000 @@ -14,9 +14,9 @@ id="svg4345" sodipodi:version="0.32" inkscape:version="0.44.1" - sodipodi:docbase="/home/hbons/Desktop/icons/24/scalable" + sodipodi:docbase="/home/hbons/Desktop/2.0.2/pidgin/pixmaps/icons/24/scalable" sodipodi:docname="pidgin.svg" - inkscape:export-filename="/home/hbons/Desktop/pidgin24-2.png" + inkscape:export-filename="/home/hbons/Desktop/pidgin24.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" version="1.0"> @@ -24,6 +24,42 @@ id="defs4347"> <linearGradient inkscape:collect="always" + id="linearGradient3124"> + <stop + style="stop-color:#3b1941;stop-opacity:1;" + offset="0" + id="stop3126" /> + <stop + style="stop-color:#3b1941;stop-opacity:0;" + offset="1" + id="stop3128" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient3116"> + <stop + style="stop-color:#82508e;stop-opacity:1;" + offset="0" + id="stop3118" /> + <stop + style="stop-color:#82508e;stop-opacity:0;" + offset="1" + id="stop3120" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient3108"> + <stop + style="stop-color:#eeeeec;stop-opacity:1;" + offset="0" + id="stop3110" /> + <stop + style="stop-color:#eeeeec;stop-opacity:0;" + offset="1" + id="stop3112" /> + </linearGradient> + <linearGradient + inkscape:collect="always" id="linearGradient5438"> <stop style="stop-color:white;stop-opacity:1;" @@ -71,30 +107,6 @@ id="stop6510" /> </linearGradient> <linearGradient - inkscape:collect="always" - id="linearGradient5304"> - <stop - style="stop-color:#2e3436;stop-opacity:1;" - offset="0" - id="stop5306" /> - <stop - style="stop-color:#2e3436;stop-opacity:0;" - offset="1" - id="stop5308" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - id="linearGradient5280"> - <stop - style="stop-color:#82508e;stop-opacity:1;" - offset="0" - id="stop5282" /> - <stop - style="stop-color:#82508e;stop-opacity:0;" - offset="1" - id="stop5284" /> - </linearGradient> - <linearGradient id="linearGradient2804"> <stop style="stop-color:black;stop-opacity:0;" @@ -165,43 +177,14 @@ offset="1.0000000" id="stop3804" /> </linearGradient> - <radialGradient - inkscape:collect="always" - xlink:href="#linearGradient5280" - id="radialGradient5286" - cx="15.004828" - cy="39.80859" - fx="15.004828" - fy="39.80859" - r="9.7225161" - gradientTransform="matrix(1,0,0,0.732283,0,10.65742)" - gradientUnits="userSpaceOnUse" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient5304" - id="linearGradient5310" - x1="12.606371" - y1="15.069461" - x2="12.606371" - y2="21.152372" - gradientUnits="userSpaceOnUse" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient6506" id="linearGradient6512" x1="15.645709" - y1="39.743458" + y1="40.434063" x2="15.645709" - y2="53.502155" - gradientUnits="userSpaceOnUse" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient6537" - id="linearGradient6543" - x1="30.5" - y1="0.033532728" - x2="30.5" - y2="23.559282" + y2="43.693668" gradientUnits="userSpaceOnUse" /> <linearGradient inkscape:collect="always" @@ -221,6 +204,250 @@ x2="30.152058" y2="23.011967" gradientUnits="userSpaceOnUse" /> + <linearGradient + gradientUnits="userSpaceOnUse" + y2="44.272076" + x2="5.5366187" + y1="39.902092" + x1="-1.6841649" + id="linearGradient6569" + xlink:href="#linearGradient6563" + inkscape:collect="always" /> + <linearGradient + gradientUnits="userSpaceOnUse" + y2="23.559282" + x2="30.5" + y1="0.033532728" + x1="30.5" + id="linearGradient2089" + xlink:href="#linearGradient6537" + inkscape:collect="always" /> + <linearGradient + gradientUnits="userSpaceOnUse" + y2="50.079575" + x2="14.943421" + y1="39.743458" + x1="15.645709" + id="linearGradient2087" + xlink:href="#linearGradient6506" + inkscape:collect="always" /> + <linearGradient + id="linearGradient2081"> + <stop + id="stop2083" + offset="0.0000000" + style="stop-color:#f4d9b1;stop-opacity:1.0000000;" /> + <stop + id="stop2085" + offset="1.0000000" + style="stop-color:#df9725;stop-opacity:1.0000000;" /> + </linearGradient> + <radialGradient + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1.131317,0,0,1.125313,-1.035262,-0.301139)" + r="8.4883642" + fy="2.6242435" + fx="7.8836637" + cy="2.6242435" + cx="7.8836637" + id="radialGradient2079" + xlink:href="#linearGradient25546" + inkscape:collect="always" /> + <radialGradient + r="8.4883642" + fy="0.14505707" + fx="7.8836741" + cy="0.14505707" + cx="7.8836741" + gradientTransform="matrix(1,0,0,0.994693,0,4.16407e-2)" + gradientUnits="userSpaceOnUse" + id="radialGradient2071" + xlink:href="#linearGradient25546" + inkscape:collect="always" /> + <radialGradient + r="8.4883642" + fy="1.5104795" + fx="7.8836637" + cy="1.5104795" + cx="7.8836637" + gradientTransform="matrix(1,0,0,0.994693,0,4.16407e-2)" + gradientUnits="userSpaceOnUse" + id="radialGradient2069" + xlink:href="#linearGradient25546" + inkscape:collect="always" /> + <linearGradient + id="linearGradient2061"> + <stop + id="stop2063" + offset="0" + style="stop-color:black;stop-opacity:0;" /> + <stop + style="stop-color:black;stop-opacity:1;" + offset="0.5" + id="stop2065" /> + <stop + id="stop2067" + offset="1" + style="stop-color:black;stop-opacity:0;" /> + </linearGradient> + <linearGradient + id="linearGradient6563" + inkscape:collect="always"> + <stop + id="stop6565" + offset="0" + style="stop-color:white;stop-opacity:1;" /> + <stop + id="stop6567" + offset="1" + style="stop-color:white;stop-opacity:0;" /> + </linearGradient> + <linearGradient + id="linearGradient2850" + inkscape:collect="always"> + <stop + id="stop2852" + offset="0" + style="stop-color:#ce5c00;stop-opacity:1;" /> + <stop + id="stop2854" + offset="1" + style="stop-color:#ce5c00;stop-opacity:0;" /> + </linearGradient> + <linearGradient + id="linearGradient3958" + inkscape:collect="always"> + <stop + id="stop3960" + offset="0" + style="stop-color:#eeeeec;stop-opacity:1;" /> + <stop + id="stop3962" + offset="1" + style="stop-color:#eeeeec;stop-opacity:0;" /> + </linearGradient> + <linearGradient + id="linearGradient3968" + inkscape:collect="always"> + <stop + id="stop3970" + offset="0" + style="stop-color:#82508e;stop-opacity:1;" /> + <stop + id="stop3972" + offset="1" + style="stop-color:#82508e;stop-opacity:0;" /> + </linearGradient> + <linearGradient + id="linearGradient3976" + inkscape:collect="always"> + <stop + id="stop3978" + offset="0" + style="stop-color:#3b1941;stop-opacity:1;" /> + <stop + id="stop3980" + offset="1" + style="stop-color:#3b1941;stop-opacity:0;" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2850" + id="linearGradient2149" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.769231,0,0,0.714287,-34.23081,-12.28573)" + x1="21.785719" + y1="28.142857" + x2="17.785713" + y2="30.07143" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3958" + id="radialGradient2191" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1.116159,0,0,1.076653,-36.39499,-20.28695)" + cx="9.0640488" + cy="21.511742" + fx="9.0640488" + fy="21.511742" + r="16.663956" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient6506" + id="linearGradient2193" + gradientUnits="userSpaceOnUse" + x1="15.645709" + y1="39.743458" + x2="15.645709" + y2="53.502155" + gradientTransform="matrix(0.660903,0,0,0.627207,-32.26852,-10.3201)" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3968" + id="linearGradient2196" + gradientUnits="userSpaceOnUse" + x1="16.13257" + y1="40.781811" + x2="16.13257" + y2="48.068741" + gradientTransform="matrix(0.67692,0,0,0.646801,-32.53568,-10.90841)" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3976" + id="linearGradient2198" + gradientUnits="userSpaceOnUse" + x1="12.095973" + y1="40.907658" + x2="12.095973" + y2="46.463146" + gradientTransform="matrix(0.67692,0,0,0.646801,-32.53568,-10.90841)" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient6537" + id="linearGradient2201" + gradientUnits="userSpaceOnUse" + x1="30.5" + y1="0.033532728" + x2="30.5" + y2="23.559282" + gradientTransform="matrix(0.668893,0,0,0.668627,-32.91377,-10.19246)" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3108" + id="linearGradient3114" + x1="10.18327" + y1="16.618088" + x2="27.598003" + y2="36.64465" + gradientUnits="userSpaceOnUse" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3116" + id="linearGradient3122" + x1="15.722902" + y1="39.585075" + x2="15.722902" + y2="45.76453" + gradientUnits="userSpaceOnUse" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3124" + id="linearGradient3130" + x1="13.150809" + y1="39.39394" + x2="13.150809" + y2="45.551888" + gradientUnits="userSpaceOnUse" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2850" + id="linearGradient3146" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.769231,0,0,0.714287,-3.230767,-7.285729)" + x1="21.785719" + y1="28.142857" + x2="17.785713" + y2="30.07143" /> </defs> <sodipodi:namedview id="base" @@ -229,17 +456,17 @@ borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="26.124924" - inkscape:cx="19.621039" - inkscape:cy="12.735051" + inkscape:zoom="16.081777" + inkscape:cx="21.855503" + inkscape:cy="14.873812" inkscape:current-layer="layer1" showgrid="true" inkscape:grid-bbox="true" inkscape:document-units="px" - inkscape:window-width="1274" - inkscape:window-height="966" - inkscape:window-x="3" - inkscape:window-y="25" + inkscape:window-width="1434" + inkscape:window-height="840" + inkscape:window-x="0" + inkscape:window-y="0" showguides="true" inkscape:guide-bbox="true" inkscape:grid-points="false" @@ -282,44 +509,21 @@ transform="matrix(1.747787,0,0,1.397993,-52.41719,-5.183942)" sodipodi:nodetypes="csccccc" /> <path - style="opacity:1;fill:#82508e;fill-opacity:1;stroke:#3b1941;stroke-width:1.51128328;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + style="opacity:1;fill:url(#linearGradient3122);fill-opacity:1.0;stroke:url(#linearGradient3130);stroke-width:1.51128328;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" d="M 15,13 C 8.3759979,13 3,18.600001 3,25.5 C 3,31.153143 2.9750563,38.402618 2.9750563,45.572826 C 4.1625449,45.572826 27.946366,45.600605 30.637365,45.600605 C 32.751492,45.600605 32.586331,43.541005 32.586331,43.541005 C 32.586331,40.875594 27.597902,38.639057 25.813453,36.682531 C 23.985035,34.68151 26,30.5 26,30.5 C 26.641306,28.9702 27,27.275084 27,25.5 C 27,18.600001 21.624002,13 15,13 z " id="path5176" sodipodi:nodetypes="ccccszcsc" transform="matrix(0.67692,0,0,0.646801,-1.52611,-5.949693)" /> <path - sodipodi:type="arc" - style="opacity:1;fill:url(#radialGradient5286);fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="path5273" - sodipodi:cx="15.004828" - sodipodi:cy="39.80859" - sodipodi:rx="9.7225161" - sodipodi:ry="7.119638" - d="M 24.727345 39.80859 A 9.7225161 7.119638 0 1 1 5.2823124,39.80859 A 9.7225161 7.119638 0 1 1 24.727345 39.80859 z" - transform="matrix(0.661428,0,0,0.760624,-1.973841,-10.20757)" /> - <path - style="opacity:0.5152838;fill:#5c3466;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1" - d="M -42.833794,49.038847 C -42.833794,49.038847 -42.815855,44.709724 -42.815855,37.951005 C -42.815855,37.951005 -39.03087,40.509965 -38.631892,41.678764 C -39.153711,41.596001 -40.372039,41.685633 -40.372039,41.685633 C -40.038351,42.463101 -38.163796,45.952105 -36.121045,48.058218 C -37.780497,47.329365 -39.471111,47.196178 -39.471111,47.196178 C -39.009636,48.111847 -37.250115,48.69173 -36.943887,49.110993 C -36.943887,49.110993 -41.348464,49.038847 -42.833794,49.038847 z " - id="rect5312" - sodipodi:nodetypes="cccccccc" - transform="matrix(0.799568,0,0,0.627241,35.24855,-7.804428)" /> - <path - style="opacity:0.5152838;fill:#5c3466;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1" - d="M -49.441852,47.4154 C -48.364983,40.273995 -40.690447,44.765623 -40.961409,37.951005 C -40.961409,37.951005 -39.025024,40.280009 -38.974466,41.581367 C -39.496285,41.498604 -39.881988,41.516405 -39.881988,41.516405 C -39.5483,42.293873 -38.196948,45.748112 -36.154197,47.854225 C -37.813649,47.125372 -38.925816,46.898039 -38.925816,46.898039 C -38.847603,47.794771 -38.376224,47.369394 -38.122982,48.215235 C -42.942294,48.046898 -46.252916,49.195571 -49.441852,47.4154 z " - id="path5317" - sodipodi:nodetypes="cccccccc" - transform="matrix(-0.602064,0,0,0.572779,-9.767144,-4.737575)" /> - <path transform="matrix(0.660903,0,0,0.627207,-1.258953,-5.361383)" - style="opacity:0.31004363;fill:url(#linearGradient5310);fill-opacity:1;stroke:url(#linearGradient6512);stroke-width:1.55319395;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + style="opacity:0.5;fill:url(#linearGradient3114);fill-opacity:1.0;stroke:url(#linearGradient6512);stroke-width:1.55319395;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" d="M 15,14.0625 C 8.9877035,14.0625 4.0789961,19.13808 4.0625,25.46875 C 4.0624722,25.479427 4.0617033,25.489349 4.0625,25.5 C 4.0625,32.787473 3.9033639,38.26012 3.9033639,44.499878 C 5.8399452,44.499878 22.452275,44.470084 28.278248,44.470084 C 29.445455,44.470084 31.431654,44.974157 31.431654,43.509594 C 31.431654,43.287851 31.231903,42.870917 30.681654,42.353344 C 30.131405,41.835771 29.308414,41.280003 28.400404,40.728344 C 26.665321,39.858723 25.411769,39.090553 24.621247,37.290844 C 24.011242,36.47675 23.731303,35.519763 23.676839,34.478344 C 23.622375,33.436925 24.107721,32.319635 24.224561,31.259594 C 24.458241,29.139511 24.96875,30.28125 24.96875,30.28125 C 24.98374,30.216952 25.004663,30.154183 25.03125,30.09375 C 25.618731,28.692346 25.9375,27.131297 25.9375,25.5 C 25.9375,19.154404 21.022436,14.0625 15,14.0625 z " id="path5241" sodipodi:nodetypes="cscccssccsscssc" /> <path - transform="matrix(-0.861857,-0.809791,0.812609,-0.76352,-5.667036,37.33378)" - style="opacity:1;fill:#a46bb0;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1" - d="M 13.257119,24.626053 C 13.257119,26.227351 11.8279,27.316574 10.863875,27.316574 C 9.5428049,27.316574 8.4706318,26.01697 8.4706318,24.415672 C 8.4706318,23.024119 9.2055946,21.514771 10.526665,21.514771 C 11.847736,21.514771 13.257119,23.360971 13.257119,24.626053 z " - id="path5160" + style="fill:#a46bb0;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1" + d="M 3.072604,7.0864988 C 4.607952,5.4493238 7.105721,5.8854918 8.086061,6.9308478 C 9.4294869,8.3633698 9.273726,10.85472 7.738379,12.491894 C 6.404137,13.914624 4.209552,14.660821 2.866124,13.228299 C 1.522696,11.795776 1.859625,8.3799248 3.072604,7.0864988 z " + id="path3138" sodipodi:nodetypes="csssc" /> <path transform="matrix(1.010846,0,0,1.029732,-5.552971,-15.17001)" @@ -336,45 +540,7 @@ sodipodi:rx="1.2410715" sodipodi:ry="1.2946428" d="M 11.410714 24.3125 A 1.2410715 1.2946428 0 1 1 8.928571,24.3125 A 1.2410715 1.2946428 0 1 1 11.410714 24.3125 z" - transform="matrix(0.805757,0,0,0.772415,-3.184731,-8.820615)" /> - <path - transform="matrix(0.596326,-0.813274,-0.562251,-0.766804,22.42583,37.43862)" - style="opacity:1;fill:#975fa3;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1" - d="M 13.257119,24.626053 C 13.257119,26.227351 11.8279,27.316574 10.863875,27.316574 C 9.5428049,27.316574 8.4706318,26.01697 8.4706318,24.415672 C 8.4706318,23.024119 9.2055946,21.514771 10.526665,21.514771 C 11.847736,21.514771 13.257119,23.360971 13.257119,24.626053 z " - id="path5167" - sodipodi:nodetypes="csssc" /> - <path - transform="matrix(0.447398,-0.672135,-0.421833,-0.633728,21.07418,32.19024)" - style="opacity:1;fill:white;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1" - d="M 13.257119,24.626053 C 13.257119,26.227351 11.8279,27.316574 10.863875,27.316574 C 9.5428049,27.316574 8.4706318,26.01697 8.4706318,24.415672 C 8.4706318,23.024119 9.2055946,21.514771 10.526665,21.514771 C 11.847736,21.514771 13.257119,23.360971 13.257119,24.626053 z " - id="path5169" - sodipodi:nodetypes="csssc" /> - <path - sodipodi:type="arc" - style="opacity:1;fill:#5c3566;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="path5171" - sodipodi:cx="10.169642" - sodipodi:cy="24.3125" - sodipodi:rx="1.2410715" - sodipodi:ry="1.2946428" - d="M 11.410714 24.3125 A 1.2410715 1.2946428 0 1 1 8.928571,24.3125 A 1.2410715 1.2946428 0 1 1 11.410714 24.3125 z" - transform="matrix(0.805756,0,0,0.784291,6.815275,-9.124735)" /> - <rect - style="opacity:1;fill:#eeeeec;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="rect5215" - width="5.6071429" - height="2.1785715" - x="16" - y="27" - transform="matrix(0.724348,0,0,0.459012,-2.641559,0.565398)" - rx="0.87366539" - ry="1.0892857" /> - <path - transform="matrix(0.798987,0,0,0.495994,7.007995,-6.360384)" - style="fill:#f9751a;fill-opacity:1;stroke:none;stroke-width:1.0283047;stroke-miterlimit:4;stroke-opacity:1" - d="M -0.99929609,42.004237 C 2.9290204,42.117701 4.1278823,38.950282 4.9828709,38.950282 C 5.8260957,38.950282 7.1161651,42.240122 10.014606,42.007796 C 9.2074596,43.955072 6.7265914,47.014858 5.6807127,47.014858 C 4.6230593,47.014858 0.31231911,44.880662 -0.99929609,42.004237 z " - id="rect5187" - sodipodi:nodetypes="ccczc" /> + transform="matrix(1.208633,0,0,1.158621,-6.791366,-17.66897)" /> <path transform="matrix(0.670792,0,0,0.486348,-3.805943,-3.90166)" style="fill:#3b1941;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1" @@ -387,11 +553,53 @@ d="M 11.689238,9.8218679 C 13.591296,8.0161941 17.174576,11.994261 17.519594,13.650486 L 14.543472,12.891665 L 11.689238,9.8218679 z " id="rect5189" sodipodi:nodetypes="cccc" /> + <rect + style="opacity:0.23144106;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="rect3034" + width="36.000004" + height="2.9999979" + x="-84.444725" + y="32.42485" + rx="2.0412357" + ry="1.4999989" /> <path - transform="matrix(0.798987,0,0,0.495994,7.007995,-6.360384)" - style="fill:url(#linearGradient6823);fill-opacity:1;stroke:none;stroke-width:1.0283047;stroke-miterlimit:4;stroke-opacity:1" - d="M -0.99929609,42.004237 C 2.9290204,42.117701 4.1278823,38.950282 4.9828709,38.950282 C 5.8260957,38.950282 7.1161651,42.240122 10.014606,42.007796 C 9.2074596,43.955072 6.7265914,47.014858 5.6807127,47.014858 C 4.6230593,47.014858 0.31231911,44.880662 -0.99929609,42.004237 z " - id="path6815" - sodipodi:nodetypes="ccczc" /> + style="fill:#975fa3;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1" + d="M 16.371022,7.8148748 C 15.47069,6.586993 14.005993,6.9141191 13.43112,7.6981356 C 12.643332,8.7725276 12.734671,10.64104 13.635002,11.868921 C 14.417404,12.93597 15.704314,13.495617 16.492103,12.421225 C 17.279892,11.346833 17.082315,8.7849447 16.371022,7.8148748 z " + id="path3132" + sodipodi:nodetypes="csssc" /> + <path + style="fill:white;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1" + d="M 16.502957,8.5432477 C 15.827476,7.7246593 14.728576,7.9427464 14.297274,8.4654263 C 13.706229,9.1816906 13.774757,10.427368 14.450238,11.245957 C 15.037241,11.957323 16.002754,12.33042 16.593798,11.614156 C 17.184843,10.897891 17.03661,9.1899614 16.502957,8.5432477 z " + id="path3134" + sodipodi:nodetypes="csssc" /> + <path + sodipodi:type="arc" + style="fill:#5c3566;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="path3136" + sodipodi:cx="10.169642" + sodipodi:cy="24.3125" + sodipodi:rx="1.2410715" + sodipodi:ry="1.2946428" + d="M 11.410714 24.3125 A 1.2410715 1.2946428 0 1 1 8.928571,24.3125 A 1.2410715 1.2946428 0 1 1 11.410714 24.3125 z" + transform="matrix(1.153827,0,0,1.158621,3.593156,-17.66895)" /> + <rect + style="fill:#eeeeec;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="rect3140" + width="4.4400907" + height="1" + x="8.5358553" + y="13" + rx="0.69182354" + ry="0.5" /> + <path + style="fill:#fcaf3e;fill-opacity:1;stroke:none;stroke-width:1.0283047;stroke-miterlimit:4;stroke-opacity:1" + d="M 6,13.893438 C 11.088512,17.243015 10.655188,12 11.431469,12 C 12.197069,12 11.699301,17.201991 16,13.895644 C 15.267157,15.102946 13.014668,17 12.06507,17 C 11.104781,17 7.190872,15.676807 6,13.893438 z " + id="path3142" + sodipodi:nodetypes="czczc" /> + <path + style="fill:url(#linearGradient3146);fill-opacity:1;stroke:none;stroke-width:1.0283047;stroke-miterlimit:4;stroke-opacity:1" + d="M 6,13.893439 C 10.740404,18.171305 10.655188,12 11.431469,12 C 12.197069,12 11.641283,17.027939 16,13.895646 C 15.267157,15.102947 13.014668,17 12.06507,17 C 11.104781,17 7.190873,15.676809 6,13.893439 z " + id="path3144" + sodipodi:nodetypes="czczc" /> </g> </svg>
--- a/pidgin/pixmaps/icons/32/scalable/pidgin.svg Thu Jun 14 19:48:48 2007 +0000 +++ b/pidgin/pixmaps/icons/32/scalable/pidgin.svg Mon Jun 18 01:48:35 2007 +0000 @@ -14,9 +14,9 @@ id="svg4345" sodipodi:version="0.32" inkscape:version="0.44.1" - sodipodi:docbase="/home/hbons/code/pidgin-mtn/pidgin/pixmaps/icons/32/scalable" + sodipodi:docbase="/home/hbons/Desktop/2.0.2/pidgin/pixmaps/icons/32/scalable" sodipodi:docname="pidgin.svg" - inkscape:export-filename="/home/hbons/code/pidgin-mtn/pidgin/pixmaps/icons/32/pidgin.png" + inkscape:export-filename="/home/hbons/Desktop/pidgin32.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" version="1.0"> @@ -24,18 +24,131 @@ id="defs4347"> <linearGradient inkscape:collect="always" - id="linearGradient6817"> + id="linearGradient3976"> + <stop + style="stop-color:#3b1941;stop-opacity:1;" + offset="0" + id="stop3978" /> + <stop + style="stop-color:#3b1941;stop-opacity:0;" + offset="1" + id="stop3980" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient3968"> + <stop + style="stop-color:#82508e;stop-opacity:1;" + offset="0" + id="stop3970" /> + <stop + style="stop-color:#82508e;stop-opacity:0;" + offset="1" + id="stop3972" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient3958"> + <stop + style="stop-color:#eeeeec;stop-opacity:1;" + offset="0" + id="stop3960" /> <stop - style="stop-color:white;stop-opacity:1;" + style="stop-color:#eeeeec;stop-opacity:0;" + offset="1" + id="stop3962" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient2850"> + <stop + style="stop-color:#ce5c00;stop-opacity:1;" + offset="0" + id="stop2852" /> + <stop + style="stop-color:#ce5c00;stop-opacity:0;" + offset="1" + id="stop2854" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2850" + id="linearGradient2856" + x1="21.785719" + y1="28.142857" + x2="17.785713" + y2="30.07143" + gradientUnits="userSpaceOnUse" + gradientTransform="translate(-47,-15.99998)" /> + <linearGradient + inkscape:collect="always" + id="linearGradient2816"> + <stop + style="stop-color:#eeeeec;stop-opacity:1;" offset="0" - id="stop6819" /> + id="stop2818" /> + <stop + style="stop-color:#eeeeec;stop-opacity:0;" + offset="1" + id="stop2820" /> + </linearGradient> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient2816" + id="radialGradient2824" + cx="9.4288578" + cy="19.283415" + fx="9.4288578" + fy="19.283415" + r="16.390338" + gradientTransform="matrix(1.556432,0,0,1.618148,-52.04294,-30.39321)" + gradientUnits="userSpaceOnUse" /> + <linearGradient + inkscape:collect="always" + id="linearGradient2826"> + <stop + style="stop-color:#3b1941;stop-opacity:1;" + offset="0" + id="stop2828" /> <stop - style="stop-color:white;stop-opacity:0;" + style="stop-color:#3b1941;stop-opacity:0;" offset="1" - id="stop6821" /> + id="stop2830" /> </linearGradient> <linearGradient inkscape:collect="always" + xlink:href="#linearGradient2826" + id="linearGradient2832" + x1="13.191773" + y1="41.606163" + x2="13.191773" + y2="47.843258" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1,0,0,0.988192,-46.55265,-16.48621)" /> + <linearGradient + inkscape:collect="always" + id="linearGradient2834"> + <stop + style="stop-color:#82508e;stop-opacity:1;" + offset="0" + id="stop2836" /> + <stop + style="stop-color:#82508e;stop-opacity:0;" + offset="1" + id="stop2838" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2834" + id="linearGradient2840" + x1="11.373499" + y1="41.566242" + x2="11.373499" + y2="47.746658" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1,0,0,0.988192,-46.55265,-16.48621)" /> + <linearGradient + inkscape:collect="always" id="linearGradient6563"> <stop style="stop-color:white;stop-opacity:1;" @@ -71,30 +184,6 @@ id="stop6510" /> </linearGradient> <linearGradient - inkscape:collect="always" - id="linearGradient5304"> - <stop - style="stop-color:#2e3436;stop-opacity:1;" - offset="0" - id="stop5306" /> - <stop - style="stop-color:#2e3436;stop-opacity:0;" - offset="1" - id="stop5308" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - id="linearGradient5280"> - <stop - style="stop-color:#82508e;stop-opacity:1;" - offset="0" - id="stop5282" /> - <stop - style="stop-color:#82508e;stop-opacity:0;" - offset="1" - id="stop5284" /> - </linearGradient> - <linearGradient id="linearGradient2804"> <stop style="stop-color:black;stop-opacity:0;" @@ -165,34 +254,14 @@ offset="1.0000000" id="stop3804" /> </linearGradient> - <radialGradient - inkscape:collect="always" - xlink:href="#linearGradient5280" - id="radialGradient5286" - cx="15.004828" - cy="39.80859" - fx="15.004828" - fy="39.80859" - r="9.7225161" - gradientTransform="matrix(1,0,0,0.732283,0,10.65742)" - gradientUnits="userSpaceOnUse" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient5304" - id="linearGradient5310" - x1="12.606371" - y1="15.069461" - x2="12.606371" - y2="21.152372" - gradientUnits="userSpaceOnUse" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient6506" id="linearGradient6512" x1="15.645709" y1="39.743458" - x2="15.645709" - y2="53.502155" + x2="14.943421" + y2="50.079575" gradientUnits="userSpaceOnUse" /> <linearGradient inkscape:collect="always" @@ -214,13 +283,62 @@ gradientUnits="userSpaceOnUse" /> <linearGradient inkscape:collect="always" - xlink:href="#linearGradient6817" - id="linearGradient6823" - x1="0.23931108" - y1="38.950283" - x2="5.7089725" - y2="42.982571" + xlink:href="#linearGradient6537" + id="linearGradient3069" + gradientUnits="userSpaceOnUse" + x1="30.5" + y1="0.033532728" + x2="30.5" + y2="23.559282" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient6506" + id="linearGradient3071" + gradientUnits="userSpaceOnUse" + x1="15.645709" + y1="39.743458" + x2="15.645709" + y2="53.502155" + gradientTransform="translate(-47,-15)" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3958" + id="radialGradient3966" + cx="9.0640488" + cy="21.511742" + fx="9.0640488" + fy="21.511742" + r="16.663956" + gradientTransform="matrix(1.68884,0,0,1.716583,-6.243689,-15.89085)" gradientUnits="userSpaceOnUse" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3968" + id="linearGradient3974" + x1="16.13257" + y1="40.781811" + x2="16.13257" + y2="48.068741" + gradientUnits="userSpaceOnUse" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3976" + id="linearGradient3982" + x1="12.095973" + y1="40.907658" + x2="12.095973" + y2="46.463146" + gradientUnits="userSpaceOnUse" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2850" + id="linearGradient3991" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.769231,0,0,0.714287,-1.230773,-2.285726)" + x1="21.785719" + y1="28.142857" + x2="17.785713" + y2="30.07143" /> </defs> <sodipodi:namedview id="base" @@ -229,17 +347,17 @@ borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="21.220032" - inkscape:cx="25.558911" - inkscape:cy="16.91503" + inkscape:zoom="17.236022" + inkscape:cx="21.944662" + inkscape:cy="16.287609" inkscape:current-layer="layer1" showgrid="true" inkscape:grid-bbox="true" inkscape:document-units="px" - inkscape:window-width="1274" - inkscape:window-height="966" - inkscape:window-x="3" - inkscape:window-y="25" + inkscape:window-width="1434" + inkscape:window-height="840" + inkscape:window-x="0" + inkscape:window-y="0" showguides="true" inkscape:guide-bbox="true" inkscape:grid-points="false" @@ -261,16 +379,6 @@ id="layer1" inkscape:label="Layer 1" inkscape:groupmode="layer"> - <rect - style="opacity:0.23144106;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="rect6514" - width="5.0217423" - height="5.2252574" - x="42.978256" - y="44" - rx="0.28473777" - ry="2.6126287" - transform="matrix(4.779203,0,0,0.382753,-205.4017,13.15888)" /> <path sodipodi:type="inkscape:offset" inkscape:radius="-1.0057179" @@ -292,51 +400,28 @@ id="path6535" sodipodi:nodetypes="cccccccccccccc" /> <path - style="opacity:1;fill:#82508e;fill-opacity:1;stroke:#3b1941;stroke-width:1.51128328;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + style="opacity:1;fill:url(#linearGradient3974);fill-opacity:1.0;stroke:url(#linearGradient3982);stroke-width:1.51128328;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" d="M 15,13 C 8.3759979,13 3,18.600001 3,25.5 C 4.8460021,40.483064 0.49299658,38.484005 0.052646307,45.33795 C 0.052646307,47.422072 1.0380664,48.413461 3.1446965,48.413461 C 4.3321851,48.413461 29.360035,48.5596 32.051034,48.5596 C 34.165161,48.5596 34,46.5 34,46.5 C 34,43.834589 27.597902,41.598052 25.813453,39.641526 C 23.985035,37.640505 26,30.5 26,30.5 C 26.641306,28.9702 27,27.275084 27,25.5 C 27,18.600001 21.624002,13 15,13 z " id="path5176" sodipodi:nodetypes="cccccszcsc" transform="matrix(0.67692,0,0,0.646801,0.464358,-0.908413)" /> <path - sodipodi:type="arc" - style="opacity:1;fill:url(#radialGradient5286);fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="path5273" - sodipodi:cx="15.004828" - sodipodi:cy="39.80859" - sodipodi:rx="9.7225161" - sodipodi:ry="7.119638" - d="M 24.727345 39.80859 A 9.7225161 7.119638 0 1 1 5.2823124,39.80859 A 9.7225161 7.119638 0 1 1 24.727345 39.80859 z" - transform="matrix(0.661428,0,0,0.760624,1.662895e-2,-5.166292)" /> - <path - style="opacity:0.5152838;fill:#5c3466;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1" - d="M -42.833794,47.629347 C -42.833794,47.629347 -43.26687,44.687985 -40.223294,37.951005 C -40.223294,37.951005 -39.03087,40.509965 -38.631892,41.678764 C -39.153711,41.596001 -40.372039,41.685633 -40.372039,41.685633 C -40.038351,42.463101 -38.163796,45.952105 -36.121045,48.058218 C -37.780497,47.329365 -39.471111,47.196178 -39.471111,47.196178 C -39.009636,48.111847 -37.250115,48.69173 -36.943887,49.110993 C -36.943887,49.110993 -42.597127,49.864236 -42.833794,47.629347 z " - id="rect5312" - sodipodi:nodetypes="cccccccc" - transform="matrix(0.797045,0,0,0.733236,35.01127,-5.421684)" /> - <path - style="opacity:0.5152838;fill:#5c3466;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1" - d="M -49.441852,47.4154 C -48.364983,40.273995 -40.690447,44.765623 -40.961409,37.951005 C -40.961409,37.951005 -39.025024,40.280009 -38.974466,41.581367 C -39.496285,41.498604 -39.881988,41.516405 -39.881988,41.516405 C -39.5483,42.293873 -38.196948,45.748112 -36.154197,47.854225 C -37.813649,47.125372 -38.925816,46.898039 -38.925816,46.898039 C -38.847603,47.794771 -38.376224,47.369394 -38.122982,48.215235 C -42.942294,48.046898 -46.252916,49.195571 -49.441852,47.4154 z " - id="path5317" - sodipodi:nodetypes="cccccccc" - transform="matrix(-0.724368,0,0,0.660383,-12.52413,-1.979892)" /> - <path - transform="matrix(0.660903,0,0,0.627207,0.731515,-0.320103)" - style="opacity:0.31004363;fill:url(#linearGradient5310);fill-opacity:1;stroke:url(#linearGradient6512);stroke-width:1.55319357;stroke-miterlimit:4;stroke-opacity:1" + style="opacity:0.5;fill:url(#radialGradient3966);fill-opacity:1.0;stroke:url(#linearGradient6512);stroke-width:1.55319357;stroke-miterlimit:4;stroke-opacity:1" d="M 15,14.0625 C 8.9877035,14.0625 4.0789961,19.13808 4.0625,25.46875 C 4.0624722,25.479427 4.0625,25.489316 4.0625,25.5 C 4.9744187,33.020507 4.3062656,37.469969 2.59375,40.59375 C -0.19778709,46.24536 1.5610206,47.490284 3.9033639,47.490284 C 5.8399452,47.490284 23.958121,47.46049 29.784094,47.46049 C 30.951301,47.46049 32.9375,47.964563 32.9375,46.5 C 32.9375,46.278257 32.737749,45.861323 32.1875,45.34375 C 31.637251,44.826177 30.81426,44.270409 29.90625,43.71875 C 28.99824,43.167091 28.02821,42.609033 27.15625,42.0625 C 26.28429,41.515967 25.511654,41.005793 24.96875,40.28125 C 24.358745,39.467156 24.078806,38.510169 24.024342,37.46875 C 23.969878,36.427331 24.107721,35.310041 24.224561,34.25 C 24.458241,32.129917 24.96875,30.28125 24.96875,30.28125 C 24.98374,30.216952 25.004663,30.154183 25.03125,30.09375 C 25.618731,28.692346 25.9375,27.131297 25.9375,25.5 C 25.9375,19.154404 21.022436,14.0625 15,14.0625 z " id="path5241" - sodipodi:nodetypes="csscccssssssscssc" /> + sodipodi:nodetypes="csscccssssssscssc" + transform="matrix(0.660903,0,0,0.627207,0.731515,-0.320103)" /> <path - transform="matrix(-0.861857,-0.809791,0.812609,-0.76352,-3.676568,42.37505)" style="opacity:1;fill:#a46bb0;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1" - d="M 13.257119,24.626053 C 13.257119,26.227351 11.8279,27.316574 10.863875,27.316574 C 9.5428049,27.316574 8.4706318,26.01697 8.4706318,24.415672 C 8.4706318,23.024119 9.2055946,21.514771 10.526665,21.514771 C 11.847736,21.514771 13.257119,23.360971 13.257119,24.626053 z " + d="M 5.0726004,12.086499 C 6.6079483,10.449324 9.1057173,10.885492 10.086057,11.930848 C 11.429483,13.36337 11.273722,15.85472 9.7383746,17.491894 C 8.4041332,18.914624 6.2095475,19.660821 4.8661202,18.228299 C 3.5226923,16.795776 3.8596213,13.379925 5.0726004,12.086499 z " id="path5160" sodipodi:nodetypes="csssc" /> <path - transform="matrix(1.010846,0,0,1.029732,-3.562503,-10.12874)" style="opacity:1;fill:white;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1" d="M 13.257119,24.626053 C 13.257119,26.227351 11.8279,27.316574 10.863875,27.316574 C 9.5428049,27.316574 8.4706318,26.01697 8.4706318,24.415672 C 8.4706318,23.024119 9.2055946,21.514771 10.526665,21.514771 C 11.847736,21.514771 13.257119,23.360971 13.257119,24.626053 z " id="path5157" - sodipodi:nodetypes="csssc" /> + sodipodi:nodetypes="csssc" + transform="matrix(1.010846,0,0,1.029732,-3.562503,-10.12874)" /> <path sodipodi:type="arc" style="opacity:1;fill:#5c3566;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" @@ -346,7 +431,7 @@ sodipodi:rx="1.2410715" sodipodi:ry="1.2946428" d="M 11.410714 24.3125 A 1.2410715 1.2946428 0 1 1 8.928571,24.3125 A 1.2410715 1.2946428 0 1 1 11.410714 24.3125 z" - transform="matrix(0.805757,0,0,0.772415,-1.194263,-3.779337)" /> + transform="matrix(1.208633,0,0,1.158621,-4.791365,-12.66897)" /> <path transform="matrix(0.596326,-0.813274,-0.562251,-0.766804,24.4163,42.47989)" style="opacity:1;fill:#975fa3;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1" @@ -354,11 +439,11 @@ id="path5167" sodipodi:nodetypes="csssc" /> <path - transform="matrix(0.447398,-0.542185,-0.421833,-0.511203,23.06465,33.31996)" style="opacity:1;fill:white;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1" d="M 13.257119,24.626053 C 13.257119,26.227351 11.8279,27.316574 10.863875,27.316574 C 9.5428049,27.316574 8.4706318,26.01697 8.4706318,24.415672 C 8.4706318,23.024119 9.2055946,21.514771 10.526665,21.514771 C 11.847736,21.514771 13.257119,23.360971 13.257119,24.626053 z " id="path5169" - sodipodi:nodetypes="csssc" /> + sodipodi:nodetypes="csssc" + transform="matrix(0.447398,-0.542185,-0.421833,-0.511203,23.06465,33.31996)" /> <path sodipodi:type="arc" style="opacity:1;fill:#5c3566;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" @@ -368,23 +453,16 @@ sodipodi:rx="1.2410715" sodipodi:ry="1.2946428" d="M 11.410714 24.3125 A 1.2410715 1.2946428 0 1 1 8.928571,24.3125 A 1.2410715 1.2946428 0 1 1 11.410714 24.3125 z" - transform="matrix(0.805756,0,0,0.784291,8.805745,-4.083452)" /> + transform="matrix(1.208633,0,0,1.158621,5.208632,-12.66896)" /> <rect style="opacity:1;fill:#eeeeec;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" id="rect5215" - width="5.6071429" - height="2.1785715" - x="16" - y="27" - transform="matrix(0.724348,0,0,0.459012,-0.651091,5.606678)" - rx="0.87366539" - ry="1.0892857" /> - <path - transform="matrix(0.798987,0,0,0.495994,8.99846,-1.319104)" - style="fill:#f9751a;fill-opacity:1;stroke:none;stroke-width:1.0283047;stroke-miterlimit:4;stroke-opacity:1" - d="M -0.99929609,42.004237 C 2.9290204,42.117701 4.1278823,38.950282 4.9828709,38.950282 C 5.8260957,38.950282 7.1161651,42.240122 10.014606,42.007796 C 9.2074596,43.955072 6.7265914,47.014858 5.6807127,47.014858 C 4.6230593,47.014858 0.31231911,44.880662 -0.99929609,42.004237 z " - id="rect5187" - sodipodi:nodetypes="ccczc" /> + width="4.4400907" + height="1" + x="10.535856" + y="18" + rx="0.69182354" + ry="0.5" /> <path transform="matrix(0.670792,0,0,0.486348,-1.815475,1.13962)" style="fill:#3b1941;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1" @@ -398,10 +476,14 @@ id="rect5189" sodipodi:nodetypes="cccc" /> <path - transform="matrix(0.798987,0,0,0.495994,8.99846,-1.319104)" - style="fill:url(#linearGradient6823);fill-opacity:1.0;stroke:none;stroke-width:1.0283047;stroke-miterlimit:4;stroke-opacity:1" - d="M -0.99929609,42.004237 C 2.9290204,42.117701 4.1278823,38.950282 4.9828709,38.950282 C 5.8260957,38.950282 7.1161651,42.240122 10.014606,42.007796 C 9.2074596,43.955072 6.7265914,47.014858 5.6807127,47.014858 C 4.6230593,47.014858 0.31231911,44.880662 -0.99929609,42.004237 z " - id="path6815" - sodipodi:nodetypes="ccczc" /> + style="fill:#fcaf3e;fill-opacity:1;stroke:none;stroke-width:1.0283047;stroke-miterlimit:4;stroke-opacity:1" + d="M 8,18.893438 C 13.088512,22.243015 12.655188,17 13.431469,17 C 14.197069,17 13.699301,22.201991 18,18.895644 C 17.267157,20.102946 15.014668,22 14.06507,22 C 13.104781,22 9.1908718,20.676807 8,18.893438 z " + id="path3987" + sodipodi:nodetypes="czczc" /> + <path + style="fill:url(#linearGradient3991);fill-opacity:1;stroke:none;stroke-width:1.0283047;stroke-miterlimit:4;stroke-opacity:1" + d="M 8,18.893439 C 12.740404,23.171305 12.655188,17 13.431469,17 C 14.197069,17 13.641283,22.027939 18,18.895646 C 17.267157,20.102947 15.014668,22 14.06507,22 C 13.104781,22 9.1908731,20.676809 8,18.893439 z " + id="path3989" + sodipodi:nodetypes="czczc" /> </g> </svg>
--- a/pidgin/pixmaps/icons/48/scalable/pidgin.svg Thu Jun 14 19:48:48 2007 +0000 +++ b/pidgin/pixmaps/icons/48/scalable/pidgin.svg Mon Jun 18 01:48:35 2007 +0000 @@ -14,15 +14,63 @@ id="svg4345" sodipodi:version="0.32" inkscape:version="0.44.1" - sodipodi:docbase="/home/hbons/Desktop/icons/48/scalable" + sodipodi:docbase="/home/hbons/Desktop/2.0.2/pidgin/pixmaps/icons/48/scalable" sodipodi:docname="pidgin.svg" - inkscape:export-filename="/home/hbons/Desktop/pidgin.png" + inkscape:export-filename="/home/hbons/Desktop/pidgin48.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90"> <defs id="defs4347"> <linearGradient inkscape:collect="always" + id="linearGradient2850"> + <stop + style="stop-color:#ce5c00;stop-opacity:1;" + offset="0" + id="stop2852" /> + <stop + style="stop-color:#ce5c00;stop-opacity:0;" + offset="1" + id="stop2854" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient2834"> + <stop + style="stop-color:#82508e;stop-opacity:1;" + offset="0" + id="stop2836" /> + <stop + style="stop-color:#82508e;stop-opacity:0;" + offset="1" + id="stop2838" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient2826"> + <stop + style="stop-color:#3b1941;stop-opacity:1;" + offset="0" + id="stop2828" /> + <stop + style="stop-color:#3b1941;stop-opacity:0;" + offset="1" + id="stop2830" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient2816"> + <stop + style="stop-color:#eeeeec;stop-opacity:1;" + offset="0" + id="stop2818" /> + <stop + style="stop-color:#eeeeec;stop-opacity:0;" + offset="1" + id="stop2820" /> + </linearGradient> + <linearGradient + inkscape:collect="always" id="linearGradient6563"> <stop style="stop-color:white;stop-opacity:1;" @@ -71,18 +119,6 @@ </linearGradient> <linearGradient inkscape:collect="always" - id="linearGradient5304"> - <stop - style="stop-color:#2e3436;stop-opacity:1;" - offset="0" - id="stop5306" /> - <stop - style="stop-color:#2e3436;stop-opacity:0;" - offset="1" - id="stop5308" /> - </linearGradient> - <linearGradient - inkscape:collect="always" id="linearGradient5280"> <stop style="stop-color:#82508e;stop-opacity:1;" @@ -177,15 +213,6 @@ gradientUnits="userSpaceOnUse" /> <linearGradient inkscape:collect="always" - xlink:href="#linearGradient5304" - id="linearGradient5310" - x1="12.606371" - y1="15.069461" - x2="12.606371" - y2="23.043955" - gradientUnits="userSpaceOnUse" /> - <linearGradient - inkscape:collect="always" xlink:href="#linearGradient6493" id="linearGradient6499" x1="3.3105288" @@ -198,27 +225,19 @@ xlink:href="#linearGradient6506" id="linearGradient6512" x1="15.645709" - y1="39.743458" + y1="41.751736" x2="15.645709" - y2="53.502155" - gradientUnits="userSpaceOnUse" /> + y2="47.370037" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1,0,0,0.988192,0.5625,-1.39645)" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient6537" id="linearGradient6543" x1="30.5" - y1="0.033532728" + y1="5.7732024" x2="30.5" - y2="23.559282" - gradientUnits="userSpaceOnUse" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient6563" - id="linearGradient6569" - x1="-1.6841649" - y1="39.902092" - x2="5.5366187" - y2="44.272076" + y2="19.518673" gradientUnits="userSpaceOnUse" /> <linearGradient inkscape:collect="always" @@ -229,6 +248,45 @@ y1="38.950283" x2="5.5366187" y2="44.272076" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient2816" + id="radialGradient2824" + cx="9.4288578" + cy="19.283415" + fx="9.4288578" + fy="19.283415" + r="16.390338" + gradientTransform="matrix(1.556432,0,0,1.618148,-5.04294,-15.39321)" + gradientUnits="userSpaceOnUse" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2826" + id="linearGradient2832" + x1="13.191773" + y1="41.606163" + x2="13.191773" + y2="47.843258" + gradientUnits="userSpaceOnUse" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2834" + id="linearGradient2840" + x1="11.373499" + y1="41.566242" + x2="11.373499" + y2="47.746658" + gradientUnits="userSpaceOnUse" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2850" + id="linearGradient2856" + x1="21.785719" + y1="28.142857" + x2="17.785713" + y2="30.07143" + gradientUnits="userSpaceOnUse" + gradientTransform="translate(0,-0.999982)" /> </defs> <sodipodi:namedview id="base" @@ -237,17 +295,17 @@ borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="1.1545694" - inkscape:cx="31.681369" - inkscape:cy="18.601404" + inkscape:zoom="14" + inkscape:cx="34.459692" + inkscape:cy="22.220728" inkscape:current-layer="layer1" showgrid="true" inkscape:grid-bbox="true" inkscape:document-units="px" - inkscape:window-width="1274" - inkscape:window-height="966" - inkscape:window-x="3" - inkscape:window-y="25" + inkscape:window-width="1434" + inkscape:window-height="840" + inkscape:window-x="0" + inkscape:window-y="0" showguides="true" inkscape:guide-bbox="true" inkscape:grid-points="true" /> @@ -267,15 +325,14 @@ inkscape:label="Layer 1" inkscape:groupmode="layer"> <rect - style="opacity:0.23144105;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + style="opacity:0.23144106;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" id="rect6514" - width="5.0217423" - height="5.2252574" - x="42.978256" - y="44" - rx="0.28473777" - ry="2.6126287" - transform="matrix(7.168827,0,0,0.574134,-308.1037,19.73808)" /> + width="36.000004" + height="2.9999979" + x="-4.4446878" + y="57.424854" + rx="2.0412357" + ry="1.4999989" /> <path sodipodi:type="inkscape:offset" inkscape:radius="-1.0057179" @@ -296,43 +353,19 @@ id="path6535" d="M 20.53125,2.53125 C 17.841732,2.53125 15.53125,5.0973912 15.53125,8.46875 L 15.53125,20.53125 C 15.53125,23.902609 17.841732,26.46875 20.53125,26.46875 L 34.53125,26.46875 C 35.097743,26.476048 35.555202,26.933507 35.5625,27.5 L 35.5625,29 L 38.71875,26.65625 C 38.901723,26.528628 39.120742,26.462922 39.34375,26.46875 L 41.5,26.46875 C 43.235888,26.46875 44.009537,25.921608 44.59375,24.9375 C 45.177963,23.953392 45.46875,22.367968 45.46875,20.53125 L 45.46875,8.46875 C 45.46875,5.0973915 43.158268,2.53125 40.46875,2.53125 L 20.53125,2.53125 z " /> <path - style="opacity:1;fill:#82508e;fill-opacity:1;stroke:#3b1941;stroke-width:1.00595677;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + style="opacity:1;fill:url(#linearGradient2840);fill-opacity:1.0;stroke:url(#linearGradient2832);stroke-width:1.00595677;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" d="M 15,13 C 8.3759979,13 3,18.600001 3,25.5 C 4.8460021,40.483064 0.49299658,38.484005 0.052646307,45.33795 C 0.052646307,47.422072 1.0380664,48.413461 3.1446965,48.413461 C 4.3321851,48.413461 29.360035,48.5596 32.051034,48.5596 C 34.165161,48.5596 34,46.5 34,46.5 C 34,43.834589 27.597902,41.598052 25.813453,39.641526 C 23.985035,37.640505 26,30.5 26,30.5 C 26.641306,28.9702 27,27.275084 27,25.5 C 27,18.600001 21.624002,13 15,13 z " id="path5176" sodipodi:nodetypes="cccccszcsc" transform="matrix(1,0,0,0.988192,0.447354,-1.486208)" /> <path - sodipodi:type="arc" - style="opacity:1;fill:url(#radialGradient5286);fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="path5273" - sodipodi:cx="15.004828" - sodipodi:cy="39.80859" - sodipodi:rx="9.7225161" - sodipodi:ry="7.119638" - d="M 24.727345 39.80859 A 9.7225161 7.119638 0 1 1 5.2823124,39.80859 A 9.7225161 7.119638 0 1 1 24.727345 39.80859 z" - transform="matrix(0.977113,0,0,1.123653,-0.214066,-6.870732)" /> - <path - style="opacity:0.5152838;fill:#5c3466;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1" - d="M -42.833794,47.629347 C -42.833794,47.629347 -43.26687,44.687985 -40.223294,37.951005 C -40.223294,37.951005 -39.03087,40.509965 -38.631892,41.678764 C -39.153711,41.596001 -40.372039,41.685633 -40.372039,41.685633 C -40.038351,42.463101 -38.163796,45.952105 -36.121045,48.058218 C -37.780497,47.329365 -39.471111,47.196178 -39.471111,47.196178 C -39.009636,48.111847 -37.250115,48.69173 -36.943887,49.110993 C -36.943887,49.110993 -42.597127,49.864236 -42.833794,47.629347 z " - id="rect5312" - sodipodi:nodetypes="cccccccc" - transform="matrix(1.177457,0,0,1.083194,51.48278,-7.248017)" /> - <path - style="opacity:0.5152838;fill:#5c3466;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1" - d="M -49.441852,47.4154 C -48.364983,40.273995 -40.690447,44.765623 -40.961409,37.951005 C -40.961409,37.951005 -39.025024,40.280009 -38.974466,41.581367 C -39.496285,41.498604 -39.881988,41.516405 -39.881988,41.516405 C -39.5483,42.293873 -38.196948,45.748112 -36.154197,47.854225 C -37.813649,47.125372 -38.925816,46.898039 -38.925816,46.898039 C -38.847603,47.794771 -38.376224,47.369394 -38.122982,48.215235 C -42.942294,48.046898 -46.252916,49.195571 -49.441852,47.4154 z " - id="path5317" - sodipodi:nodetypes="cccccccc" - transform="matrix(-1.070093,0,0,1.114946,-18.74027,-7.453016)" /> - <path - transform="matrix(1,0,0,0.988192,0.40625,-1.486208)" - style="opacity:0.31004367;fill:url(#linearGradient5310);fill-opacity:1;stroke:url(#linearGradient6512);stroke-width:1.00595677;stroke-miterlimit:4;stroke-opacity:1" - d="M 15,14.0625 C 8.9877035,14.0625 4.0789961,19.13808 4.0625,25.46875 C 4.0624722,25.479427 4.0625,25.489316 4.0625,25.5 C 4.9744187,33.020507 4.3062656,37.469969 2.59375,40.59375 C -0.19778709,46.24536 1.5610206,47.490284 3.9033639,47.490284 C 5.8399452,47.490284 23.958121,47.46049 29.784094,47.46049 C 30.951301,47.46049 32.9375,47.964563 32.9375,46.5 C 32.9375,46.278257 32.737749,45.861323 32.1875,45.34375 C 31.637251,44.826177 30.81426,44.270409 29.90625,43.71875 C 28.99824,43.167091 28.02821,42.609033 27.15625,42.0625 C 26.28429,41.515967 25.511654,41.005793 24.96875,40.28125 C 24.358745,39.467156 24.078806,38.510169 24.024342,37.46875 C 23.969878,36.427331 24.107721,35.310041 24.224561,34.25 C 24.458241,32.129917 24.96875,30.28125 24.96875,30.28125 C 24.98374,30.216952 25.004663,30.154183 25.03125,30.09375 C 25.618731,28.692346 25.9375,27.131297 25.9375,25.5 C 25.9375,19.154404 21.022436,14.0625 15,14.0625 z " + style="opacity:0.5;fill:url(#radialGradient2824);fill-opacity:1;stroke:url(#linearGradient6512);stroke-width:0.99999994;stroke-miterlimit:4;stroke-opacity:1" + d="M 15.5625,12.5 C 9.550204,12.5 4.641496,17.515648 4.625,23.771565 C 4.624972,23.782116 4.625,23.791888 4.625,23.802446 C 5.536919,31.234151 4.868766,35.631074 3.15625,38.717969 C 0.36471303,44.302845 2.123521,45.533069 4.465864,45.533069 C 6.402445,45.533069 24.520621,45.503627 30.346594,45.503627 C 31.513801,45.503627 33.5,46.001748 33.5,44.554478 C 33.5,44.335354 33.300249,43.923343 32.75,43.411881 C 32.199751,42.90042 31.37676,42.351214 30.46875,41.806069 C 29.56074,41.260924 28.59071,40.709456 27.71875,40.169376 C 26.84679,39.629297 26.074154,39.125147 25.53125,38.409159 C 24.921245,37.604678 24.641306,36.658991 24.586842,35.629869 C 24.532378,34.600747 24.670221,33.49665 24.787061,32.449126 C 25.020741,30.354077 25.53125,28.527239 25.53125,28.527239 C 25.54624,28.4637 25.567163,28.401673 25.59375,28.341953 C 26.181231,26.957097 26.5,25.414481 26.5,23.802446 C 26.5,17.531779 21.584936,12.5 15.5625,12.5 z " id="path5241" sodipodi:nodetypes="csscccssssssscssc" /> <path - transform="matrix(-1.162197,-1.219912,1.095788,-1.150206,-4.404363,64.58016)" style="opacity:1;fill:#a46bb0;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1" - d="M 13.257119,24.626053 C 13.257119,26.227351 11.8279,27.316574 10.863875,27.316574 C 9.5428049,27.316574 8.4706318,26.01697 8.4706318,24.415672 C 8.4706318,23.024119 9.2055946,21.514771 10.526665,21.514771 C 11.847736,21.514771 13.257119,23.360971 13.257119,24.626053 z " + d="M 7.269301,19.503118 C 9.2717505,17.238166 12.529418,17.841584 13.808008,19.287784 C 15.560146,21.269611 15.356996,24.71627 13.354547,26.981222 C 11.614386,28.949501 8.7521391,29.981828 7,28 C 5.2478601,26.018172 5.6872953,21.292511 7.269301,19.503118 z " id="path5160" sodipodi:nodetypes="csssc" /> <path @@ -350,7 +383,7 @@ sodipodi:rx="1.2410715" sodipodi:ry="1.2946428" d="M 11.410714 24.3125 A 1.2410715 1.2946428 0 1 1 8.928571,24.3125 A 1.2410715 1.2946428 0 1 1 11.410714 24.3125 z" - transform="matrix(1.208632,0,0,1.158617,-1.844007,-4.808565)" /> + transform="matrix(1.208632,0,0,1.544828,-1.738701,-14.41893)" /> <path sodipodi:type="arc" style="opacity:1;fill:black;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" @@ -360,11 +393,10 @@ sodipodi:rx="1.2410715" sodipodi:ry="1.2946428" d="M 11.410714 24.3125 A 1.2410715 1.2946428 0 1 1 8.928571,24.3125 A 1.2410715 1.2946428 0 1 1 11.410714 24.3125 z" - transform="matrix(0.402878,0,0,0.386209,6.350228,13.9706)" /> + transform="matrix(0.402878,0,0,0.514947,6.455534,10.62004)" /> <path - transform="matrix(0.871648,-1.084366,-0.821841,-1.022405,36.71113,59.50016)" style="opacity:1;fill:#975fa3;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1" - d="M 13.257119,24.626053 C 13.257119,26.227351 11.8279,27.316574 10.863875,27.316574 C 9.5428049,27.316574 8.4706318,26.01697 8.4706318,24.415672 C 8.4706318,23.024119 9.2055946,21.514771 10.526665,21.514771 C 11.847736,21.514771 13.257119,23.360971 13.257119,24.626053 z " + d="M 27.88281,19.946791 C 26.359012,18.309616 23.880032,18.745786 22.907068,19.791141 C 21.573747,21.223665 21.728337,23.715015 23.252136,25.35219 C 24.576341,26.77492 26.754418,27.521117 28.087739,26.088593 C 29.42106,24.656068 29.086665,21.240217 27.88281,19.946791 z " id="path5167" sodipodi:nodetypes="csssc" /> <path @@ -382,7 +414,7 @@ sodipodi:rx="1.2410715" sodipodi:ry="1.2946428" d="M 11.410714 24.3125 A 1.2410715 1.2946428 0 1 1 8.928571,24.3125 A 1.2410715 1.2946428 0 1 1 11.410714 24.3125 z" - transform="matrix(1.208632,0,0,1.158617,13.15599,-4.808572)" /> + transform="matrix(1.208632,0,0,1.598777,13.20865,-15.80042)" /> <path sodipodi:type="arc" style="opacity:1;fill:black;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" @@ -392,21 +424,19 @@ sodipodi:rx="1.2410715" sodipodi:ry="1.2946428" d="M 11.410714 24.3125 A 1.2410715 1.2946428 0 1 1 8.928571,24.3125 A 1.2410715 1.2946428 0 1 1 11.410714 24.3125 z" - transform="matrix(0.402878,0,0,0.386209,21.35023,13.9706)" /> + transform="matrix(0.402878,0,0,0.53293,21.40289,10.11299)" /> <rect style="opacity:1;fill:#eeeeec;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" id="rect5215" - width="5.6071429" - height="2.1785715" - x="16" - y="27" - transform="matrix(1.070064,0,0,0.918028,-1.173674,3.073548)" - rx="1.0892857" - ry="1.0892857" /> + width="7" + height="1.8602936" + x="15" + y="27.000017" + rx="0.81387848" + ry="0.93014681" /> <path - transform="matrix(1.180326,0,0,0.867993,13.1795,-6.80859)" - style="fill:#f9751a;fill-opacity:1;stroke:none;stroke-width:1.0283047;stroke-miterlimit:4;stroke-opacity:1" - d="M -0.99929609,42.004237 C 3.5188333,45.348102 4.1278823,38.950282 4.9828709,38.950282 C 5.8260957,38.950282 6.1724645,45.375511 10.014606,42.007796 C 9.2074596,43.955072 6.7265914,47.014858 5.6807127,47.014858 C 4.6230593,47.014858 0.31231911,44.880662 -0.99929609,42.004237 z " + style="fill:#fcaf3e;fill-opacity:1;stroke:none;stroke-width:1.0283047;stroke-miterlimit:4;stroke-opacity:1" + d="M 12.000005,28.650812 C 17.33287,31.553263 18.051747,26 19.060912,26 C 20.056192,26 20.46502,31.577054 25,28.653901 C 24.047304,30.344123 21.119071,32.999996 19.884593,32.999996 C 18.636217,32.999996 13.548138,31.147528 12.000005,28.650812 z " id="rect5187" sodipodi:nodetypes="czczc" /> <path @@ -422,9 +452,8 @@ id="rect5189" sodipodi:nodetypes="cccc" /> <path - transform="matrix(1.180326,0,0,0.867993,13.1795,-6.80859)" - style="fill:url(#linearGradient6569);fill-opacity:1.0;stroke:none;stroke-width:1.0283047;stroke-miterlimit:4;stroke-opacity:1" - d="M -0.99929609,42.004237 C 3.5188333,45.348102 4.1278823,38.950282 4.9828709,38.950282 C 5.8260957,38.950282 6.1724645,45.375511 10.014606,42.007796 C 9.2074596,43.955072 6.7265914,47.014858 5.6807127,47.014858 C 4.6230593,47.014858 0.31231911,44.880662 -0.99929609,42.004237 z " + style="fill:url(#linearGradient2856);fill-opacity:1;stroke:none;stroke-width:1.0283047;stroke-miterlimit:4;stroke-opacity:1" + d="M 12.000005,28.650834 C 17.332871,31.553285 18.051747,26.000022 19.060912,26.000022 C 20.056192,26.000022 20.46502,31.577076 25,28.653923 C 24.047304,30.344145 21.119071,33.000018 19.884593,33.000018 C 18.636217,33.000018 13.548139,31.14755 12.000005,28.650834 z " id="path6561" sodipodi:nodetypes="czczc" /> </g>
--- a/pidgin/pixmaps/status/16/scalable/available.svg Thu Jun 14 19:48:48 2007 +0000 +++ b/pidgin/pixmaps/status/16/scalable/available.svg Mon Jun 18 01:48:35 2007 +0000 @@ -7,23 +7,53 @@ xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" - xmlns:sodipodi="http://inkscape.sourceforge.net/DTD/s odipodi-0.dtd" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="16" height="16" id="svg2" sodipodi:version="0.32" - inkscape:version="0.43" + inkscape:version="0.44.1" version="1.0" - inkscape:export-filename="/home/hbons/Desktop/Gaim Refresh/status/16/available16.png" + inkscape:export-filename="/home/hbons/GUI/Tango/Gaim Refresh/status/16/available.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" - sodipodi:docbase="/home/hbons/Desktop/Gaim Refresh/status/16/scalable" - sodipodi:docname="available16.svg"> + sodipodi:docbase="/home/hbons/Desktop/experiment/status/16/scalable" + sodipodi:docname="available.svg"> <defs id="defs4"> <linearGradient inkscape:collect="always" + id="linearGradient2898"> + <stop + style="stop-color:white;stop-opacity:1;" + offset="0" + id="stop2900" /> + <stop + style="stop-color:white;stop-opacity:0;" + offset="1" + id="stop2902" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2851" + id="linearGradient4738" + gradientUnits="userSpaceOnUse" + x1="6.878005" + y1="11.789385" + x2="12.233074" + y2="27.77807" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3149" + id="linearGradient4740" + gradientUnits="userSpaceOnUse" + x1="15.498499" + y1="9.4211226" + x2="24.240097" + y2="36.603138" /> + <linearGradient + inkscape:collect="always" xlink:href="#linearGradient3149" id="linearGradient2269" gradientUnits="userSpaceOnUse" @@ -86,6 +116,118 @@ x2="12.233074" y2="27.77807" gradientUnits="userSpaceOnUse" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient2898" + id="radialGradient2904" + cx="4.8470273" + cy="6.9473476" + fx="4.8470273" + fy="6.9473476" + r="0.8078171" + gradientTransform="matrix(3.018423,0.664359,-1.388844,4.257661,-0.134567,-26.02469)" + gradientUnits="userSpaceOnUse" /> + <radialGradient + gradientUnits="userSpaceOnUse" + r="8.6620579" + fy="19.008621" + fx="31.112698" + cy="19.008621" + cx="31.112698" + id="radialGradient2818" + xlink:href="#linearGradient2812" + inkscape:collect="always" /> + <linearGradient + gradientUnits="userSpaceOnUse" + y2="11.024895" + x2="10.623409" + y1="2.7991772" + x1="4.5264969" + id="linearGradient2810" + xlink:href="#linearGradient2804" + inkscape:collect="always" /> + <linearGradient + gradientUnits="userSpaceOnUse" + y2="27.77807" + x2="12.233074" + y1="11.789385" + x1="6.878005" + id="linearGradient2963" + xlink:href="#linearGradient2851" + inkscape:collect="always" /> + <linearGradient + id="linearGradient2951"> + <stop + id="stop2953" + offset="0" + style="stop-color:#73d216;stop-opacity:1;" /> + <stop + id="stop2955" + offset="1" + style="stop-color:#5ca911;stop-opacity:1;" /> + </linearGradient> + <linearGradient + y2="40.032413" + x2="17.890068" + y1="8.0617304" + x1="17.890068" + gradientUnits="userSpaceOnUse" + id="linearGradient2949" + xlink:href="#linearGradient3149" + inkscape:collect="always" /> + <linearGradient + id="linearGradient2804" + inkscape:collect="always"> + <stop + id="stop2806" + offset="0" + style="stop-color:white;stop-opacity:1;" /> + <stop + id="stop2808" + offset="1" + style="stop-color:white;stop-opacity:0;" /> + </linearGradient> + <linearGradient + id="linearGradient2812" + inkscape:collect="always"> + <stop + id="stop2814" + offset="0" + style="stop-color:#2e3436;stop-opacity:1;" /> + <stop + id="stop2816" + offset="1" + style="stop-color:#2e3436;stop-opacity:0;" /> + </linearGradient> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient2812" + id="radialGradient3005" + gradientUnits="userSpaceOnUse" + cx="31.112698" + cy="19.008621" + fx="31.112698" + fy="19.008621" + r="8.6620579" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2804" + id="linearGradient3007" + gradientUnits="userSpaceOnUse" + x1="4.5264969" + y1="2.7991772" + x2="10.623409" + y2="11.024895" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient2812" + id="radialGradient3025" + gradientUnits="userSpaceOnUse" + cx="31.112698" + cy="19.008621" + fx="31.112698" + fy="19.008621" + r="8.6620579" /> </defs> <sodipodi:namedview id="base" @@ -95,16 +237,16 @@ inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="25.992076" - inkscape:cx="16.806787" - inkscape:cy="8.1662141" + inkscape:cx="4.1907826" + inkscape:cy="8.6773979" inkscape:document-units="px" inkscape:current-layer="layer1" showgrid="true" fill="#eeeeec" - inkscape:window-width="1268" - inkscape:window-height="968" - inkscape:window-x="6" - inkscape:window-y="21" /> + inkscape:window-width="1274" + inkscape:window-height="844" + inkscape:window-x="3" + inkscape:window-y="0" /> <metadata id="metadata7"> <rdf:RDF> @@ -126,37 +268,19 @@ sodipodi:rx="8.6620579" sodipodi:cy="19.008621" sodipodi:cx="31.112698" - id="path4318" - style="opacity:0.7;color:#000000;fill:url(#radialGradient3822);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - sodipodi:type="arc" - transform="matrix(0.923568,0,0,0.288615,-20.73469,8.013827)" /> - <path + id="path2969" + style="color:black;fill:url(#radialGradient3025);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" sodipodi:type="arc" - style="opacity:1;fill:url(#linearGradient2857);fill-opacity:1;fill-rule:evenodd;stroke:#418203;stroke-width:1.85686159;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="path2245" - sodipodi:cx="17.890068" - sodipodi:cy="17.572527" - sodipodi:rx="13.932817" - sodipodi:ry="13.932817" - d="M 31.822886 17.572527 A 13.932817 13.932817 0 1 1 3.9572506,17.572527 A 13.932817 13.932817 0 1 1 31.822886 17.572527 z" - transform="matrix(0.538543,0,0,0.538542,-1.633369,-1.462358)" /> - <image - id="image1323" - height="64.794617" - width="64.794617" - sodipodi:absref="/home/hbons/Desktop/Gaim Refresh/Tango-Palette.png" - xlink:href="/home/hbons/Desktop/Gaim Refresh/Tango-Palette.png" - x="-74" - y="-17" /> + transform="matrix(0.923568,0,0,0.173169,-20.73469,11.2083)" /> <path - sodipodi:type="arc" - style="opacity:0.5;fill:url(#linearGradient2269);fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:2.14505577;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="path3145" - sodipodi:cx="17.890068" - sodipodi:cy="17.572527" - sodipodi:rx="13.932817" - sodipodi:ry="13.932817" - d="M 31.822886 17.572527 A 13.932817 13.932817 0 1 1 3.9572506,17.572527 A 13.932817 13.932817 0 1 1 31.822886 17.572527 z" - transform="matrix(0.466166,0,0,0.466212,-0.33531,-0.188412)" /> + transform="matrix(0.538297,0,0,0.538297,-1.630177,-1.459246)" + style="fill:url(#linearGradient4738);fill-opacity:1;fill-rule:evenodd;stroke:#306300;stroke-width:1.85770929;stroke-miterlimit:4;stroke-opacity:1" + d="M 31.822886,17.572527 C 31.822886,25.263442 25.580983,31.505344 17.890068,31.505344 C 10.199153,31.505344 3.9572506,25.263442 3.9572506,17.572527 C 3.9572506,9.8816117 10.199153,3.6397095 17.890068,3.6397095 C 25.580983,3.6397095 31.822886,9.8816117 31.822886,17.572527 z " + id="path4331" /> + <path + transform="matrix(0.466524,0,0,0.466525,-0.346154,-0.198015)" + style="opacity:0.6;fill:url(#linearGradient4740);fill-opacity:1;fill-rule:evenodd;stroke:white;stroke-width:2.14350748;stroke-miterlimit:4;stroke-opacity:1" + d="M 31.822886,17.572527 C 31.822886,25.263442 25.580983,31.505344 17.890068,31.505344 C 10.199153,31.505344 3.9572506,25.263442 3.9572506,17.572527 C 3.9572506,9.8816117 10.199153,3.6397095 17.890068,3.6397095 C 25.580983,3.6397095 31.822886,9.8816117 31.822886,17.572527 z " + id="path4333" /> </g> </svg>
--- a/pidgin/pixmaps/status/16/scalable/away.svg Thu Jun 14 19:48:48 2007 +0000 +++ b/pidgin/pixmaps/status/16/scalable/away.svg Mon Jun 18 01:48:35 2007 +0000 @@ -7,43 +7,45 @@ xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" - xmlns:sodipodi="http://inkscape.sourceforge.net/DTD/s odipodi-0.dtd" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="16" height="16" id="svg2" sodipodi:version="0.32" - inkscape:version="0.43" + inkscape:version="0.44.1" version="1.0" inkscape:export-filename="/home/hbons/Desktop/Gaim Refresh/status/16/available16.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" - sodipodi:docbase="/home/hbons/Desktop/Gaim Refresh/status/16/scalable" - sodipodi:docname="away16.svg"> + sodipodi:docbase="/home/hbons/Desktop/experiment/status/16/scalable" + sodipodi:docname="away.svg"> <defs id="defs4"> <linearGradient inkscape:collect="always" - id="linearGradient2239"> + id="linearGradient2812"> <stop - style="stop-color:#ffffff;stop-opacity:1;" + style="stop-color:#2e3436;stop-opacity:1;" offset="0" - id="stop2241" /> + id="stop2814" /> <stop - style="stop-color:#ffffff;stop-opacity:0;" + style="stop-color:#2e3436;stop-opacity:0;" offset="1" - id="stop2243" /> + id="stop2816" /> </linearGradient> <linearGradient inkscape:collect="always" - xlink:href="#linearGradient2239" - id="linearGradient2245" - x1="15.602553" - y1="1.5657365" - x2="15.522223" - y2="33.483475" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.482882,0,0,0.482874,0.269812,0.26982)" /> + id="linearGradient2804"> + <stop + style="stop-color:white;stop-opacity:1;" + offset="0" + id="stop2806" /> + <stop + style="stop-color:white;stop-opacity:0;" + offset="1" + id="stop2808" /> + </linearGradient> <linearGradient inkscape:collect="always" xlink:href="#linearGradient3149" @@ -78,29 +80,6 @@ </linearGradient> <linearGradient inkscape:collect="always" - id="linearGradient3816"> - <stop - style="stop-color:#000000;stop-opacity:1;" - offset="0" - id="stop3818" /> - <stop - style="stop-color:#000000;stop-opacity:0;" - offset="1" - id="stop3820" /> - </linearGradient> - <radialGradient - inkscape:collect="always" - xlink:href="#linearGradient3816" - id="radialGradient3822" - cx="31.112698" - cy="19.008621" - fx="31.112698" - fy="19.008621" - r="8.6620579" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.914124,-3.896132e-15,-2.475021e-18,1.631747,2.671799,-12.00863)" /> - <linearGradient - inkscape:collect="always" xlink:href="#linearGradient2851" id="linearGradient2857" x1="6.878005" @@ -108,6 +87,25 @@ x2="12.233074" y2="27.77807" gradientUnits="userSpaceOnUse" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2804" + id="linearGradient2810" + x1="4.5264969" + y1="2.7991772" + x2="10.623409" + y2="11.024895" + gradientUnits="userSpaceOnUse" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient2812" + id="radialGradient2818" + cx="31.112698" + cy="19.008621" + fx="31.112698" + fy="19.008621" + r="8.6620579" + gradientUnits="userSpaceOnUse" /> </defs> <sodipodi:namedview id="base" @@ -117,16 +115,20 @@ inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="25.992076" - inkscape:cx="16.806787" - inkscape:cy="8.1662141" + inkscape:cx="14.729231" + inkscape:cy="2.7799575" inkscape:document-units="px" inkscape:current-layer="layer1" showgrid="true" fill="#eeeeec" - inkscape:window-width="1268" - inkscape:window-height="968" - inkscape:window-x="6" - inkscape:window-y="21" /> + inkscape:window-width="1434" + inkscape:window-height="844" + inkscape:window-x="0" + inkscape:window-y="0" + inkscape:object-paths="false" + inkscape:grid-bbox="true" + inkscape:guide-bbox="false" + inkscape:grid-points="true" /> <metadata id="metadata7"> <rdf:RDF> @@ -149,20 +151,12 @@ sodipodi:cy="19.008621" sodipodi:cx="31.112698" id="path4318" - style="opacity:0.7;color:#000000;fill:url(#radialGradient3822);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" + style="opacity:1;color:black;fill:url(#radialGradient2818);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" sodipodi:type="arc" - transform="matrix(0.923568,0,0,0.288615,-20.73469,8.013827)" /> - <image - id="image1323" - height="64.794617" - width="64.794617" - sodipodi:absref="/home/hbons/Desktop/Gaim Refresh/Tango-Palette.png" - xlink:href="/home/hbons/Desktop/Gaim Refresh/Tango-Palette.png" - x="-74" - y="-17" /> + transform="matrix(0.923568,0,0,0.173169,-20.73469,11.2083)" /> <path sodipodi:type="arc" - style="opacity:1;color:#000000;fill:#729fcf;fill-opacity:1;fill-rule:evenodd;stroke:#204a87;stroke-width:1.91314828px;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" + style="opacity:1;color:#000000;fill:#729fcf;fill-opacity:1;fill-rule:evenodd;stroke:#173867;stroke-width:1.91314828px;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" id="path1339" sodipodi:cx="15.590227" sodipodi:cy="16.57217" @@ -172,47 +166,113 @@ transform="matrix(0.522697,0,0,0.522697,-0.148088,-0.661348)" /> <path sodipodi:type="arc" - style="opacity:1;color:#000000;fill:#eeeeec;fill-opacity:1;fill-rule:evenodd;stroke:#204a87;stroke-width:2.59300995px;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" + style="opacity:1;fill:#8ab0d7;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="path2788" + sodipodi:cx="-3.8088531" + sodipodi:cy="3.303823" + sodipodi:rx="3.1932809" + sodipodi:ry="3.3471739" + d="M -0.61557221 3.303823 A 3.1932809 3.3471739 0 1 1 -7.0021341,3.303823 A 3.1932809 3.3471739 0 1 1 -0.61557221 3.303823 z" + transform="matrix(2.192102,0,0,2.091316,16.34939,1.090661)" /> + <path + sodipodi:type="arc" + style="opacity:0.40340911;color:black;fill:#babdb6;fill-opacity:1;fill-rule:evenodd;stroke:#173867;stroke-width:2.60821199px;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" id="path1341" sodipodi:cx="15.590227" sodipodi:cy="16.57217" sodipodi:rx="14.345175" sodipodi:ry="14.345175" d="M 29.935402 16.57217 A 14.345175 14.345175 0 1 1 1.2450523,16.57217 A 14.345175 14.345175 0 1 1 29.935402 16.57217 z" - transform="matrix(0.385634,0,0,0.38567,1.998372,1.598697)" /> + transform="matrix(0.383404,0,0,0.383404,2.022641,1.646167)" /> + <path + sodipodi:type="arc" + style="opacity:1;fill:#dcdcd8;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="path2796" + sodipodi:cx="6.0403023" + sodipodi:cy="7.5551186" + sodipodi:rx="1.615877" + sodipodi:ry="1.3273276" + d="M 7.6561793 7.5551186 A 1.615877 1.3273276 0 1 1 4.4244252,7.5551186 A 1.615877 1.3273276 0 1 1 7.6561793 7.5551186 z" + transform="matrix(3.094296,0,0,3.766968,-10.69048,-20.45989)" /> <path sodipodi:type="arc" - style="opacity:1;color:#000000;fill:#eeeeec;fill-opacity:1;fill-rule:evenodd;stroke:#2e3436;stroke-width:9.63841057px;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - id="path2216" - sodipodi:cx="15.590227" - sodipodi:cy="16.57217" - sodipodi:rx="14.345175" - sodipodi:ry="14.345175" - d="M 29.935402 16.57217 A 14.345175 14.345175 0 1 1 1.2450523,16.57217 A 14.345175 14.345175 0 1 1 29.935402 16.57217 z" - transform="matrix(0.103753,0,0,0.103753,6.37887,6.27699)" /> - <path - style="opacity:0.5;color:#000000;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient2245);stroke-width:0.99999881px;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - d="M 14.509853,7.9958041 C 14.509853,11.591436 11.591612,14.50963 7.9959211,14.50963 C 4.4002314,14.50963 1.4819904,11.591436 1.4819904,7.9958041 C 1.4819904,4.4001725 4.4002314,1.4819783 7.9959211,1.4819783 C 11.591612,1.4819783 14.509853,4.4001725 14.509853,7.9958041 z " - id="path2220" /> + style="opacity:0.76704544;fill:none;fill-opacity:1;stroke:url(#linearGradient2810);stroke-width:0.80677563;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="path2802" + sodipodi:cx="7.5" + sodipodi:cy="7" + sodipodi:rx="5.5" + sodipodi:ry="5" + d="M 13 7 A 5.5 5 0 1 1 2,7 A 5.5 5 0 1 1 13 7 z" + transform="matrix(1.18182,0,0,1.3,-0.86365,-1.1)" /> + <rect + style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="rect2820" + width="1" + height="1" + x="5" + y="-11" + transform="matrix(0,1,-1,0,0,0)" /> + <rect + style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="rect2832" + width="1" + height="1" + x="7" + y="-9" + transform="matrix(0,1,-1,0,0,0)" /> <path sodipodi:type="arc" + style="opacity:1;fill:white;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="path2852" + sodipodi:cx="6.0403023" + sodipodi:cy="7.5551186" + sodipodi:rx="1.615877" + sodipodi:ry="1.3273276" + d="M 4.835244,8.4394021 A 1.615877,1.3273276 0 0 1 6.0776839,6.2281462 L 6.0403023,7.5551186 z" + transform="matrix(2.475436,0,0,3.013575,-6.952382,-14.76791)" + sodipodi:start="2.4124729" + sodipodi:end="4.735525" /> + <rect style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="path1588" - sodipodi:cx="20.264311" - sodipodi:cy="14.476474" - sodipodi:rx="2.9448855" - sodipodi:ry="0.78724658" - d="M 23.209196 14.476474 A 2.9448855 0.78724658 0 1 1 17.319425,14.476474 A 2.9448855 0.78724658 0 1 1 23.209196 14.476474 z" - transform="matrix(-1.244057e-16,-0.509358,1.270255,5.747542e-7,-10.38882,15.82177)" /> - <path - sodipodi:type="arc" + id="rect2838" + width="2" + height="2" + x="7" + y="-9" + rx="1" + ry="1" + transform="matrix(0,1,-1,0,0,0)" /> + <rect + style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="rect2840" + width="1" + height="1" + x="6" + y="-10" + transform="matrix(0,1,-1,0,0,0)" /> + <rect style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="path1314" - sodipodi:cx="20.264311" - sodipodi:cy="14.476474" - sodipodi:rx="2.9448855" - sodipodi:ry="0.78724658" - d="M 23.209196 14.476474 A 2.9448855 0.78724658 0 1 1 17.319425,14.476474 A 2.9448855 0.78724658 0 1 1 23.209196 14.476474 z" - transform="matrix(0.509355,-4.991037e-16,-5.747516e-7,1.270255,0.178284,-10.38882)" /> + id="rect2846" + width="1" + height="1" + x="-11" + y="-11" + transform="matrix(0,-1,-1,0,0,0)" /> + <rect + style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="rect2848" + width="1" + height="1" + x="-9" + y="-9" + transform="matrix(0,-1,-1,0,0,0)" /> + <rect + style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="rect2850" + width="1" + height="1" + x="-10" + y="-10" + transform="matrix(0,-1,-1,0,0,0)" /> </g> </svg>
--- a/pidgin/pixmaps/status/16/scalable/busy.svg Thu Jun 14 19:48:48 2007 +0000 +++ b/pidgin/pixmaps/status/16/scalable/busy.svg Mon Jun 18 01:48:35 2007 +0000 @@ -7,23 +7,68 @@ xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" - xmlns:sodipodi="http://inkscape.sourceforge.net/DTD/s odipodi-0.dtd" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="16" height="16" id="svg2" sodipodi:version="0.32" - inkscape:version="0.43" + inkscape:version="0.44.1" version="1.0" inkscape:export-filename="/home/hbons/Desktop/Gaim Refresh/status/16/available16.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" - sodipodi:docbase="/home/hbons/Desktop/Gaim Refresh/status/16/scalable" - sodipodi:docname="busy16.svg"> + sodipodi:docbase="/home/hbons/Desktop/experiment/status/16/scalable" + sodipodi:docname="busy.svg"> <defs id="defs4"> <linearGradient inkscape:collect="always" + id="linearGradient2898"> + <stop + style="stop-color:white;stop-opacity:1;" + offset="0" + id="stop2900" /> + <stop + style="stop-color:white;stop-opacity:0;" + offset="1" + id="stop2902" /> + </linearGradient> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient2898" + id="radialGradient2904" + cx="4.8470273" + cy="6.9473476" + fx="4.8470273" + fy="6.9473476" + r="0.8078171" + gradientTransform="matrix(3.018423,0.664359,-1.388844,4.257661,-0.134567,-26.02469)" + gradientUnits="userSpaceOnUse" /> + <linearGradient + id="linearGradient2812" + inkscape:collect="always"> + <stop + id="stop2814" + offset="0" + style="stop-color:#2e3436;stop-opacity:1;" /> + <stop + id="stop2816" + offset="1" + style="stop-color:#2e3436;stop-opacity:0;" /> + </linearGradient> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient2812" + id="radialGradient3025" + gradientUnits="userSpaceOnUse" + cx="31.112698" + cy="19.008621" + fx="31.112698" + fy="19.008621" + r="8.6620579" /> + <linearGradient + inkscape:collect="always" id="linearGradient2186"> <stop style="stop-color:#ffffff;stop-opacity:1;" @@ -38,8 +83,8 @@ inkscape:collect="always" xlink:href="#linearGradient2186" id="linearGradient2194" - x1="11.226587" - y1="-5.4832759" + x1="9.2594385" + y1="-1.5641226" x2="11.226587" y2="17.697369" gradientUnits="userSpaceOnUse" @@ -60,10 +105,10 @@ inkscape:collect="always" xlink:href="#linearGradient2239" id="linearGradient2245" - x1="15.602553" - y1="1.5657365" - x2="15.522223" - y2="33.483475" + x1="8.7505674" + y1="4.5934086" + x2="31.18539" + y2="39.834526" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.482882,0,0,0.482874,0.269812,0.26982)" /> <linearGradient @@ -139,16 +184,16 @@ inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="25.992076" - inkscape:cx="16.806787" - inkscape:cy="8.1662141" + inkscape:cx="8.3811422" + inkscape:cy="5.1075896" inkscape:document-units="px" inkscape:current-layer="layer1" showgrid="true" fill="#eeeeec" inkscape:window-width="1268" - inkscape:window-height="968" + inkscape:window-height="844" inkscape:window-x="6" - inkscape:window-y="21" /> + inkscape:window-y="0" /> <metadata id="metadata7"> <rdf:RDF> @@ -170,18 +215,10 @@ sodipodi:rx="8.6620579" sodipodi:cy="19.008621" sodipodi:cx="31.112698" - id="path4318" - style="opacity:0.7;color:#000000;fill:url(#radialGradient3822);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" + id="path2969" + style="color:black;fill:url(#radialGradient3025);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" sodipodi:type="arc" - transform="matrix(0.923568,0,0,0.288615,-20.73469,8.013827)" /> - <image - id="image1323" - height="64.794617" - width="64.794617" - sodipodi:absref="/home/hbons/Desktop/Gaim Refresh/Tango-Palette.png" - xlink:href="/home/hbons/Desktop/Gaim Refresh/Tango-Palette.png" - x="-74" - y="-17" /> + transform="matrix(0.923568,0,0,0.173169,-20.73469,11.2083)" /> <path sodipodi:type="arc" style="opacity:1;color:#000000;fill:#ef2929;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.36561811px;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" @@ -194,7 +231,7 @@ transform="matrix(0.468971,0,0,0.468971,0.730372,0.26987)" /> <path sodipodi:type="arc" - style="opacity:1;color:#000000;fill:#ef2929;fill-opacity:1;fill-rule:evenodd;stroke:#a40000;stroke-width:1.91298747px;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" + style="opacity:1;color:#000000;fill:#f24747;fill-opacity:1;fill-rule:evenodd;stroke:#820000;stroke-width:1.91298747px;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" id="path1339" sodipodi:cx="15.590227" sodipodi:cy="16.57217" @@ -206,10 +243,14 @@ style="opacity:0.6;color:#000000;fill:url(#linearGradient2194);fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient2245);stroke-width:1.00000012px;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" d="M 14.525974,7.9894993 C 14.525974,11.598577 11.608166,14.527685 8.0130095,14.527685 C 4.4178543,14.527685 1.500047,11.598577 1.500047,7.9894993 C 1.500047,4.3804219 4.4178543,1.4513155 8.0130095,1.4513155 C 11.608166,1.4513155 14.525974,4.3804219 14.525974,7.9894993 z " id="path2220" /> - <path - style="color:#000000;fill:#eeeeec;fill-opacity:1;fill-rule:evenodd;stroke:#a40000;stroke-width:0.99999833px;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - d="M 13.49379,7.9436678 C 13.49379,9.8082522 12.846021,9.4786261 7.9525684,9.4786261 C 3.1055026,9.4786261 2.5041877,9.7778545 2.5041877,8.0257093 C 2.5041877,6.2462172 3.8951545,6.5604085 7.9989886,6.5604085 C 12.072197,6.5604085 13.49379,6.0517387 13.49379,7.9436678 z " - id="path1341" - sodipodi:nodetypes="czzzz" /> + <rect + style="opacity:1;fill:#eeeeec;fill-opacity:1;stroke:#a40000;stroke-width:1.00000024;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="rect3207" + width="11.000004" + height="2.9999959" + x="2.500001" + y="6.5000038" + rx="0.96183157" + ry="0.96183157" /> </g> </svg>
--- a/pidgin/pixmaps/status/16/scalable/offline.svg Thu Jun 14 19:48:48 2007 +0000 +++ b/pidgin/pixmaps/status/16/scalable/offline.svg Mon Jun 18 01:48:35 2007 +0000 @@ -15,10 +15,10 @@ sodipodi:version="0.32" inkscape:version="0.44.1" version="1.0" - inkscape:export-filename="/home/hbons/GUI/Tango/Gaim Refresh/status/16/offline.png" + inkscape:export-filename="/home/hbons/Desktop/offline.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" - sodipodi:docbase="/home/hbons/GUI/Tango/Gaim Refresh/status/16/scalable" + sodipodi:docbase="/home/hbons/Desktop/experiment/status/16/scalable" sodipodi:docname="offline.svg"> <defs id="defs4"> @@ -160,16 +160,16 @@ inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="25.992076" - inkscape:cx="16.806787" - inkscape:cy="8.1469775" + inkscape:cx="26.27121" + inkscape:cy="5.5692688" inkscape:document-units="px" inkscape:current-layer="layer1" showgrid="true" fill="#eeeeec" - inkscape:window-width="1268" - inkscape:window-height="968" - inkscape:window-x="6" - inkscape:window-y="23" /> + inkscape:window-width="1434" + inkscape:window-height="844" + inkscape:window-x="0" + inkscape:window-y="0" /> <metadata id="metadata7"> <rdf:RDF> @@ -195,14 +195,6 @@ style="opacity:0.7;color:#000000;fill:url(#radialGradient3822);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" sodipodi:type="arc" transform="matrix(0.923568,0,0,0.288615,-20.73469,8.013827)" /> - <image - id="image1323" - height="64.794617" - width="64.794617" - sodipodi:absref="/home/hbons/Desktop/Gaim Refresh/Tango-Palette.png" - xlink:href="/home/hbons/Desktop/Gaim Refresh/Tango-Palette.png" - x="-74" - y="-17" /> <path style="fill:#888a85;fill-opacity:1;stroke:#2e3436;stroke-width:0.99999827;stroke-miterlimit:4;stroke-opacity:1" d="M 13.307074,13.307079 C 10.376958,16.237198 5.6213214,16.237693 2.6918157,13.308187 C -0.23769028,10.378679 -0.23719421,5.623042 2.692923,2.6929237 C 5.62304,-0.23719442 10.378675,-0.23769056 13.308181,2.6918165 C 16.237687,5.6213234 16.237192,10.376962 13.307074,13.307079 z " @@ -218,9 +210,9 @@ d="M 8,1.5 C 6.3326173,1.5001739 4.674966,2.1375335 3.40625,3.40625 C 0.86479124,5.9477097 0.86538373,10.052882 3.40625,12.59375 C 5.9471154,15.134616 10.052293,15.135209 12.59375,12.59375 C 15.135209,10.052292 15.134616,5.9471167 12.59375,3.40625 C 11.325315,2.1378146 9.6669929,1.4998261 8,1.5 z " transform="matrix(1.000056,0,0,1.000028,-4.353349e-4,-2.926381e-5)" /> <path - style="opacity:1;fill:#eeeeec;fill-opacity:1;stroke:#555753;stroke-width:0.99999946;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - d="M 10.018233,3.7131793 L 8,5.8786797 L 5.9817663,3.727906 L 3.7131793,5.9817663 L 5.8786797,8 L 3.7131793,10.03296 L 5.9964929,12.316274 L 8,10.12132 L 10.018233,12.301548 L 12.301548,10.018233 L 10.12132,8 L 12.286821,5.9964929 L 10.018233,3.7131793 z " - id="rect1322" - sodipodi:nodetypes="ccccccccccccc" /> + style="opacity:1;fill:#eeeeec;fill-opacity:1;stroke:#555753;stroke-width:1.00000036;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="M 11.54182,4.2658182 C 10.931116,3.6551131 10.447965,3.347327 9.8372602,3.9580321 L 8.0000001,5.7952921 L 6.1627401,3.9580321 C 5.5520351,3.3473271 4.9919392,3.7705329 4.381234,4.381238 C 3.770529,4.991943 3.347323,5.5520393 3.9580281,6.1627441 L 5.7952881,8.0000041 L 3.9580281,9.8372641 C 3.3473229,10.447969 3.6935827,10.969592 4.3042875,11.580298 C 4.9149927,12.191002 5.5520349,12.652681 6.1627401,12.041977 L 8.0000001,10.204716 L 9.8372602,12.041977 C 10.447965,12.652681 11.046535,12.306422 11.657239,11.695718 C 12.267944,11.085012 12.652677,10.447969 12.041972,9.8372641 L 10.204713,8.0000041 L 12.041972,6.1627441 C 12.652677,5.552039 12.152526,4.8765236 11.54182,4.2658182 z " + id="rect2920" + sodipodi:nodetypes="ccccscccscccscccc" /> </g> </svg>
--- a/pidgin/pixmaps/status/22/scalable/available.svg Thu Jun 14 19:48:48 2007 +0000 +++ b/pidgin/pixmaps/status/22/scalable/available.svg Mon Jun 18 01:48:35 2007 +0000 @@ -7,19 +7,19 @@ xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" - xmlns:sodipodi="http://inkscape.sourceforge.net/DTD/s odipodi-0.dtd" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="24" height="24" id="svg2" sodipodi:version="0.32" - inkscape:version="0.43" + inkscape:version="0.44.1" version="1.0" - inkscape:export-filename="/home/hbons/Desktop/Gaim Refresh/status/22/available22.png" + inkscape:export-filename="/home/hbons/Desktop/Gaim Refresh/status/32/available32.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" - sodipodi:docbase="/home/hbons/Desktop/Gaim Refresh/status/22" - sodipodi:docname="available22.svg"> + sodipodi:docbase="/home/hbons/Desktop/experiment/22/scalable" + sodipodi:docname="available.svg"> <defs id="defs4"> <linearGradient @@ -72,14 +72,316 @@ xlink:href="#linearGradient3149" id="linearGradient3155" x1="17.890068" - y1="2.197206" + y1="8.3091545" x2="17.890068" - y2="18.507565" + y2="36.574547" + gradientUnits="userSpaceOnUse" /> + <radialGradient + r="8.6620579" + fy="19.008621" + fx="31.112698" + cy="19.008621" + cx="31.112698" + gradientUnits="userSpaceOnUse" + id="radialGradient3025" + xlink:href="#linearGradient2812" + inkscape:collect="always" /> + <linearGradient + y2="11.024895" + x2="10.623409" + y1="2.7991772" + x1="4.5264969" + gradientUnits="userSpaceOnUse" + id="linearGradient3007" + xlink:href="#linearGradient2804" + inkscape:collect="always" /> + <radialGradient + r="8.6620579" + fy="19.008621" + fx="31.112698" + cy="19.008621" + cx="31.112698" + gradientUnits="userSpaceOnUse" + id="radialGradient3005" + xlink:href="#linearGradient2812" + inkscape:collect="always" /> + <linearGradient + inkscape:collect="always" + id="linearGradient2812"> + <stop + style="stop-color:#2e3436;stop-opacity:1;" + offset="0" + id="stop2814" /> + <stop + style="stop-color:#2e3436;stop-opacity:0;" + offset="1" + id="stop2816" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient2804"> + <stop + style="stop-color:white;stop-opacity:1;" + offset="0" + id="stop2806" /> + <stop + style="stop-color:white;stop-opacity:0;" + offset="1" + id="stop2808" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3149" + id="linearGradient2949" + gradientUnits="userSpaceOnUse" + x1="17.890068" + y1="8.0617304" + x2="17.890068" + y2="40.032413" /> + <linearGradient + id="linearGradient2951"> + <stop + style="stop-color:#73d216;stop-opacity:1;" + offset="0" + id="stop2953" /> + <stop + style="stop-color:#5ca911;stop-opacity:1;" + offset="1" + id="stop2955" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2851" + id="linearGradient2963" + x1="6.878005" + y1="11.789385" + x2="12.233074" + y2="27.77807" gradientUnits="userSpaceOnUse" /> <linearGradient inkscape:collect="always" + xlink:href="#linearGradient2804" + id="linearGradient2810" + x1="4.5264969" + y1="2.7991772" + x2="10.623409" + y2="11.024895" + gradientUnits="userSpaceOnUse" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient2812" + id="radialGradient2818" + cx="31.112698" + cy="19.008621" + fx="31.112698" + fy="19.008621" + r="8.6620579" + gradientUnits="userSpaceOnUse" /> + <radialGradient + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(3.018423,0.664359,-1.388844,4.257661,-0.134567,-26.02469)" + r="0.8078171" + fy="6.9473476" + fx="4.8470273" + cy="6.9473476" + cx="4.8470273" + id="radialGradient2904" + xlink:href="#linearGradient2898" + inkscape:collect="always" /> + <linearGradient + gradientUnits="userSpaceOnUse" + y2="27.77807" + x2="12.233074" + y1="11.789385" + x1="6.878005" + id="linearGradient1955" xlink:href="#linearGradient2851" - id="linearGradient2857" + inkscape:collect="always" /> + <radialGradient + gradientTransform="matrix(0.914124,0,0,1.631747,2.671799,-12.00863)" + gradientUnits="userSpaceOnUse" + r="8.6620579" + fy="19.008621" + fx="31.112698" + cy="19.008621" + cx="31.112698" + id="radialGradient1953" + xlink:href="#linearGradient3816" + inkscape:collect="always" /> + <linearGradient + id="linearGradient1935"> + <stop + id="stop1937" + offset="0" + style="stop-color:#73d216;stop-opacity:1;" /> + <stop + id="stop1939" + offset="1" + style="stop-color:#5ca911;stop-opacity:1;" /> + </linearGradient> + <linearGradient + y2="40.032413" + x2="17.890068" + y1="8.0617304" + x1="17.890068" + gradientUnits="userSpaceOnUse" + id="linearGradient2269" + xlink:href="#linearGradient3149" + inkscape:collect="always" /> + <linearGradient + y2="36.603138" + x2="24.240097" + y1="9.4211226" + x1="15.498499" + gradientUnits="userSpaceOnUse" + id="linearGradient4740" + xlink:href="#linearGradient3149" + inkscape:collect="always" /> + <linearGradient + y2="27.77807" + x2="12.233074" + y1="11.789385" + x1="6.878005" + gradientUnits="userSpaceOnUse" + id="linearGradient4738" + xlink:href="#linearGradient2851" + inkscape:collect="always" /> + <linearGradient + id="linearGradient2898" + inkscape:collect="always"> + <stop + id="stop2900" + offset="0" + style="stop-color:white;stop-opacity:1;" /> + <stop + id="stop2902" + offset="1" + style="stop-color:white;stop-opacity:0;" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3149" + id="linearGradient1983" + gradientUnits="userSpaceOnUse" + x1="15.498499" + y1="9.4211226" + x2="24.240097" + y2="36.603138" + gradientTransform="matrix(1.004822,0,0,1.004822,-2.476351,-2.157242)" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2851" + id="linearGradient1986" + gradientUnits="userSpaceOnUse" + x1="6.878005" + y1="11.789385" + x2="12.233074" + y2="27.77807" + gradientTransform="matrix(1.076595,0,0,1.076595,-3.760351,-3.418494)" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient2898" + id="radialGradient1990" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(3.018423,0.664359,-1.388844,4.257661,-0.134567,-26.02469)" + cx="4.8470273" + cy="6.9473476" + fx="4.8470273" + fy="6.9473476" + r="0.8078171" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient2812" + id="radialGradient1992" + gradientUnits="userSpaceOnUse" + cx="31.112698" + cy="19.008621" + fx="31.112698" + fy="19.008621" + r="8.6620579" /> + <linearGradient + y2="21.045444" + x2="15.602553" + y1="1.5657365" + x1="15.602553" + gradientTransform="matrix(0.705322,0,0,0.705327,8.71963,7.710084)" + gradientUnits="userSpaceOnUse" + id="linearGradient2073" + xlink:href="#linearGradient2239" + inkscape:collect="always" /> + <radialGradient + r="8.6620579" + fy="19.008621" + fx="31.112698" + cy="19.008621" + cx="31.112698" + gradientUnits="userSpaceOnUse" + id="radialGradient2057" + xlink:href="#linearGradient3816" + inkscape:collect="always" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3816" + id="radialGradient2032" + cx="31.112698" + cy="19.008621" + fx="31.112698" + fy="19.008621" + r="8.6620579" + gradientUnits="userSpaceOnUse" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2239" + id="linearGradient2040" + x1="15.602553" + y1="1.5657365" + x2="15.522223" + y2="33.483475" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.999824,0,0,0.999281,2.209264e-4,5.644055e-4)" /> + <radialGradient + r="8.6620579" + fy="19.008621" + fx="31.112698" + cy="19.008621" + cx="31.112698" + gradientUnits="userSpaceOnUse" + id="radialGradient1985" + xlink:href="#linearGradient2812" + inkscape:collect="always" /> + <linearGradient + y2="11.024895" + x2="10.623409" + y1="2.7991772" + x1="4.5264969" + gradientUnits="userSpaceOnUse" + id="linearGradient2100" + xlink:href="#linearGradient2804" + inkscape:collect="always" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3149" + id="linearGradient2086" + gradientUnits="userSpaceOnUse" + x1="17.890068" + y1="8.0617304" + x2="17.890068" + y2="40.032413" /> + <linearGradient + id="linearGradient2080"> + <stop + style="stop-color:#73d216;stop-opacity:1;" + offset="0" + id="stop2082" /> + <stop + style="stop-color:#5ca911;stop-opacity:1;" + offset="1" + id="stop2084" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2851" + id="linearGradient2072" x1="6.878005" y1="11.789385" x2="12.233074" @@ -87,13 +389,386 @@ gradientUnits="userSpaceOnUse" /> <linearGradient inkscape:collect="always" + xlink:href="#linearGradient2804" + id="linearGradient2070" + x1="4.5264969" + y1="2.7991772" + x2="10.623409" + y2="11.024895" + gradientUnits="userSpaceOnUse" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient2812" + id="radialGradient2068" + cx="31.112698" + cy="19.008621" + fx="31.112698" + fy="19.008621" + r="8.6620579" + gradientUnits="userSpaceOnUse" /> + <radialGradient + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1,0,0,0.493392,0,4.185903)" + r="5.7619157" + fy="5.3375292" + fx="10.99079" + cy="5.3375292" + cx="10.99079" + id="radialGradient5135" + xlink:href="#linearGradient5129" + inkscape:collect="always" /> + <linearGradient + id="linearGradient2239" + inkscape:collect="always"> + <stop + id="stop2241" + offset="0" + style="stop-color:#ffffff;stop-opacity:1;" /> + <stop + id="stop2243" + offset="1" + style="stop-color:#ffffff;stop-opacity:0;" /> + </linearGradient> + <radialGradient + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(-0.842757,0,0,-0.35721,19.80716,14.19321)" + r="6.6449099" + fy="10.457643" + fx="10.748654" + cy="10.457643" + cx="10.748654" + id="radialGradient3156" + xlink:href="#linearGradient3150" + inkscape:collect="always" /> + <linearGradient + id="linearGradient3150" + inkscape:collect="always"> + <stop + id="stop3152" + offset="0" + style="stop-color:#2e3436;stop-opacity:1;" /> + <stop + id="stop3154" + offset="1" + style="stop-color:#2e3436;stop-opacity:0;" /> + </linearGradient> + <linearGradient + id="linearGradient5129" + inkscape:collect="always"> + <stop + id="stop5131" + offset="0" + style="stop-color:white;stop-opacity:1;" /> + <stop + id="stop5133" + offset="1" + style="stop-color:white;stop-opacity:0;" /> + </linearGradient> + <linearGradient + inkscape:collect="always" xlink:href="#linearGradient3149" - id="linearGradient2269" + id="linearGradient2126" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.466524,0,0,0.466525,38.65385,10.80199)" + x1="15.498499" + y1="9.4211226" + x2="24.240097" + y2="36.603138" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2239" + id="linearGradient2132" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.705322,0,0,0.705327,-58.76363,3.243275)" + x1="15.602553" + y1="1.5657365" + x2="15.602553" + y2="21.045444" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3149" + id="linearGradient2146" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.466524,0,0,0.466525,38.65385,10.80199)" + x1="15.498499" + y1="9.4211226" + x2="24.240097" + y2="36.603138" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient2812" + id="radialGradient2148" + gradientUnits="userSpaceOnUse" + cx="31.112698" + cy="19.008621" + fx="31.112698" + fy="19.008621" + r="8.6620579" /> + <linearGradient + y2="34.774117" + x2="17.890068" + y1="0.6668244" + x1="17.890068" + gradientUnits="userSpaceOnUse" + id="linearGradient1999" + xlink:href="#linearGradient3149" + inkscape:collect="always" /> + <linearGradient + gradientUnits="userSpaceOnUse" + y2="27.77807" + x2="12.233074" + y1="11.789385" + x1="6.878005" + id="linearGradient2857" + xlink:href="#linearGradient2851" + inkscape:collect="always" /> + <linearGradient + gradientUnits="userSpaceOnUse" + y2="18.507565" + x2="17.890068" + y1="2.197206" + x1="17.890068" + id="linearGradient1996" + xlink:href="#linearGradient3149" + inkscape:collect="always" /> + <radialGradient + gradientUnits="userSpaceOnUse" + r="8.6620579" + fy="19.008621" + fx="31.112698" + cy="19.008621" + cx="31.112698" + id="radialGradient1994" + xlink:href="#linearGradient3816" + inkscape:collect="always" /> + <linearGradient + id="linearGradient1976"> + <stop + id="stop1978" + offset="0" + style="stop-color:#73d216;stop-opacity:1;" /> + <stop + id="stop1980" + offset="1" + style="stop-color:#5ca911;stop-opacity:1;" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3149" + id="linearGradient2011" gradientUnits="userSpaceOnUse" x1="17.890068" - y1="0.6668244" + y1="8.0617304" + x2="17.890068" + y2="40.032413" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2851" + id="linearGradient2013" + gradientUnits="userSpaceOnUse" + x1="6.878005" + y1="11.789385" + x2="12.233074" + y2="27.77807" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3816" + id="radialGradient2015" + gradientUnits="userSpaceOnUse" + cx="31.112698" + cy="19.008621" + fx="31.112698" + fy="19.008621" + r="8.6620579" /> + <linearGradient + y2="21.045444" + x2="15.602553" + y1="1.5657365" + x1="15.602553" + gradientTransform="matrix(0.705322,0,0,0.705327,-24.28038,0.710083)" + gradientUnits="userSpaceOnUse" + id="linearGradient2059" + xlink:href="#linearGradient2239" + inkscape:collect="always" /> + <radialGradient + r="8.6620579" + fy="19.008621" + fx="31.112698" + cy="19.008621" + cx="31.112698" + gradientUnits="userSpaceOnUse" + id="radialGradient2147" + xlink:href="#linearGradient3816" + inkscape:collect="always" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3816" + id="radialGradient2145" + cx="31.112698" + cy="19.008621" + fx="31.112698" + fy="19.008621" + r="8.6620579" + gradientUnits="userSpaceOnUse" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2239" + id="linearGradient2143" + x1="15.602553" + y1="1.5657365" + x2="15.522223" + y2="33.483475" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.999824,0,0,0.999281,2.209264e-4,5.644055e-4)" /> + <radialGradient + r="8.6620579" + fy="19.008621" + fx="31.112698" + cy="19.008621" + cx="31.112698" + gradientUnits="userSpaceOnUse" + id="radialGradient2141" + xlink:href="#linearGradient2812" + inkscape:collect="always" /> + <linearGradient + y2="11.024895" + x2="10.623409" + y1="2.7991772" + x1="4.5264969" + gradientUnits="userSpaceOnUse" + id="linearGradient2139" + xlink:href="#linearGradient2804" + inkscape:collect="always" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3149" + id="linearGradient2124" + gradientUnits="userSpaceOnUse" + x1="17.890068" + y1="8.0617304" x2="17.890068" - y2="34.774117" /> + y2="40.032413" /> + <linearGradient + id="linearGradient2118"> + <stop + style="stop-color:#73d216;stop-opacity:1;" + offset="0" + id="stop2120" /> + <stop + style="stop-color:#5ca911;stop-opacity:1;" + offset="1" + id="stop2122" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2851" + id="linearGradient2110" + x1="6.878005" + y1="11.789385" + x2="12.233074" + y2="27.77807" + gradientUnits="userSpaceOnUse" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2804" + id="linearGradient2108" + x1="4.5264969" + y1="2.7991772" + x2="10.623409" + y2="11.024895" + gradientUnits="userSpaceOnUse" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient2812" + id="radialGradient2106" + cx="31.112698" + cy="19.008621" + fx="31.112698" + fy="19.008621" + r="8.6620579" + gradientUnits="userSpaceOnUse" /> + <radialGradient + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1,0,0,0.493392,0,4.185903)" + r="5.7619157" + fy="5.3375292" + fx="10.99079" + cy="5.3375292" + cx="10.99079" + id="radialGradient2104" + xlink:href="#linearGradient5129" + inkscape:collect="always" /> + <linearGradient + gradientTransform="matrix(0.705322,0,0,0.705327,-24.28038,0.710083)" + gradientUnits="userSpaceOnUse" + y2="21.045444" + x2="15.602553" + y1="1.5657365" + x1="15.602553" + id="linearGradient2245" + xlink:href="#linearGradient2239" + inkscape:collect="always" /> + <radialGradient + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(-0.842757,0,0,-0.35721,19.80716,14.19321)" + r="6.6449099" + fy="10.457643" + fx="10.748654" + cy="10.457643" + cx="10.748654" + id="radialGradient2095" + xlink:href="#linearGradient3150" + inkscape:collect="always" /> + <radialGradient + gradientUnits="userSpaceOnUse" + r="8.6620579" + fy="19.008621" + fx="31.112698" + cy="19.008621" + cx="31.112698" + id="radialGradient2087" + xlink:href="#linearGradient3816" + inkscape:collect="always" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3149" + id="linearGradient2167" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1.004822,0,0,1.004822,-2.476351,-2.157242)" + x1="15.498499" + y1="9.4211226" + x2="24.240097" + y2="36.603138" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient2812" + id="radialGradient2184" + gradientUnits="userSpaceOnUse" + cx="31.112698" + cy="19.008621" + fx="31.112698" + fy="19.008621" + r="8.6620579" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2851" + id="linearGradient2189" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.789503,0,0,0.789503,-2.624255,-2.373563)" + x1="6.878005" + y1="11.789385" + x2="12.233074" + y2="27.77807" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3149" + id="linearGradient2191" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.717731,0,0,0.71773,-1.34025,-1.112314)" + x1="15.498499" + y1="9.4211226" + x2="24.240097" + y2="36.603138" /> </defs> <sodipodi:namedview id="base" @@ -102,17 +777,19 @@ borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="25.992076" - inkscape:cx="20.3848" - inkscape:cy="9.8287529" + inkscape:zoom="14.928527" + inkscape:cx="26.286595" + inkscape:cy="13.181001" inkscape:document-units="px" inkscape:current-layer="layer1" showgrid="true" fill="#eeeeec" - inkscape:window-width="1268" - inkscape:window-height="968" - inkscape:window-x="6" - inkscape:window-y="21" /> + inkscape:window-width="1434" + inkscape:window-height="844" + inkscape:window-x="0" + inkscape:window-y="0" + height="24px" + width="24px" /> <metadata id="metadata7"> <rdf:RDF> @@ -134,37 +811,17 @@ sodipodi:rx="8.6620579" sodipodi:cy="19.008621" sodipodi:cx="31.112698" - id="path4318" - style="opacity:0.7;color:#000000;fill:url(#radialGradient3822);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - sodipodi:type="arc" - transform="matrix(1.385352,0,0,0.634953,-31.10204,6.430418)" /> - <path + id="path1948" + style="color:black;fill:url(#radialGradient2184);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" sodipodi:type="arc" - style="opacity:1;fill:url(#linearGradient2857);fill-opacity:1;fill-rule:evenodd;stroke:#418203;stroke-width:1.32699585;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="path2245" - sodipodi:cx="17.890068" - sodipodi:cy="17.572527" - sodipodi:rx="13.932817" - sodipodi:ry="13.932817" - d="M 31.822886 17.572527 A 13.932817 13.932817 0 1 1 3.9572506,17.572527 A 13.932817 13.932817 0 1 1 31.822886 17.572527 z" - transform="matrix(0.75357,0,0,0.753592,-1.481423,-1.2422)" /> - <image - id="image1323" - height="64.794617" - width="64.794617" - sodipodi:absref="/home/hbons/Desktop/Gaim Refresh/Tango-Palette.png" - xlink:href="/home/hbons/Desktop/Gaim Refresh/Tango-Palette.png" - x="-74" - y="-17" /> + transform="matrix(1.269906,0,0,0.346338,-27.5102,14.41659)" /> <path - sodipodi:type="arc" - style="opacity:0.5;fill:url(#linearGradient2269);fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.46676958;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="path3145" - sodipodi:cx="17.890068" - sodipodi:cy="17.572527" - sodipodi:rx="13.932817" - sodipodi:ry="13.932817" - d="M 31.822886 17.572527 A 13.932817 13.932817 0 1 1 3.9572506,17.572527 A 13.932817 13.932817 0 1 1 31.822886 17.572527 z" - transform="matrix(0.681795,0,0,0.681747,-0.197796,2.041858e-2)" /> + style="fill:url(#linearGradient2189);fill-opacity:1;fill-rule:evenodd;stroke:#306300;stroke-width:0.99999911;stroke-miterlimit:4;stroke-opacity:1" + d="M 22.500011,11.499997 C 22.500011,17.571995 17.57201,22.499994 11.500011,22.499994 C 5.428011,22.499994 0.50001162,17.571995 0.50001162,11.499997 C 0.50001162,5.4279975 5.428011,0.4999987 11.500011,0.4999987 C 17.57201,0.4999987 22.500011,5.4279975 22.500011,11.499997 z " + id="path4331" /> + <path + style="opacity:0.6;fill:url(#linearGradient2191);fill-opacity:1;fill-rule:evenodd;stroke:white;stroke-width:0.99999809;stroke-miterlimit:4;stroke-opacity:1" + d="M 21.500009,11.499995 C 21.500009,17.019992 17.020007,21.499992 11.500005,21.499992 C 5.9800027,21.499992 1.4999988,17.019992 1.4999988,11.499995 C 1.4999988,5.9799971 5.9800027,1.4999992 11.500005,1.4999992 C 17.020007,1.4999992 21.500009,5.9799971 21.500009,11.499995 z " + id="path4333" /> </g> </svg>
--- a/pidgin/pixmaps/status/22/scalable/away.svg Thu Jun 14 19:48:48 2007 +0000 +++ b/pidgin/pixmaps/status/22/scalable/away.svg Mon Jun 18 01:48:35 2007 +0000 @@ -7,23 +7,47 @@ xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" - xmlns:sodipodi="http://inkscape.sourceforge.net/DTD/s odipodi-0.dtd" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="24" height="24" id="svg1331" sodipodi:version="0.32" - inkscape:version="0.43" + inkscape:version="0.44.1" version="1.0" - inkscape:export-filename="/home/hbons/Desktop/Gaim Refresh/status/away.png" + inkscape:export-filename="/home/hbons/Desktop/away.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" - sodipodi:docbase="/home/hbons/Desktop/Gaim Refresh/status/22/scalable" - sodipodi:docname="away22.svg"> + sodipodi:docbase="/home/hbons/Desktop/experiment/status/22/scalable" + sodipodi:docname="away.svg"> <defs id="defs1333"> <linearGradient inkscape:collect="always" + id="linearGradient2811"> + <stop + style="stop-color:white;stop-opacity:1;" + offset="0" + id="stop2813" /> + <stop + style="stop-color:white;stop-opacity:0;" + offset="1" + id="stop2815" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient5129"> + <stop + style="stop-color:white;stop-opacity:1;" + offset="0" + id="stop5131" /> + <stop + style="stop-color:white;stop-opacity:0;" + offset="1" + id="stop5133" /> + </linearGradient> + <linearGradient + inkscape:collect="always" id="linearGradient3816"> <stop style="stop-color:#000000;stop-opacity:1;" @@ -85,10 +109,175 @@ id="linearGradient2245" x1="15.602553" y1="1.5657365" - x2="15.522223" + x2="15.602553" + y2="21.045444" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.705322,0,0,0.705327,-24.28038,0.710083)" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient5129" + id="radialGradient5135" + cx="10.99079" + cy="5.3375292" + fx="10.99079" + fy="5.3375292" + r="5.7619157" + gradientTransform="matrix(1,0,0,0.493392,0,4.185903)" + gradientUnits="userSpaceOnUse" /> + <radialGradient + gradientUnits="userSpaceOnUse" + r="8.6620579" + fy="19.008621" + fx="31.112698" + cy="19.008621" + cx="31.112698" + id="radialGradient2818" + xlink:href="#linearGradient2812" + inkscape:collect="always" /> + <linearGradient + gradientUnits="userSpaceOnUse" + y2="11.024895" + x2="10.623409" + y1="2.7991772" + x1="4.5264969" + id="linearGradient2810" + xlink:href="#linearGradient2804" + inkscape:collect="always" /> + <linearGradient + gradientUnits="userSpaceOnUse" + y2="27.77807" + x2="12.233074" + y1="11.789385" + x1="6.878005" + id="linearGradient2857" + xlink:href="#linearGradient2851" + inkscape:collect="always" /> + <linearGradient + id="linearGradient3149" + inkscape:collect="always"> + <stop + id="stop3151" + offset="0" + style="stop-color:#eeeeec;stop-opacity:1;" /> + <stop + id="stop3153" + offset="1" + style="stop-color:#eeeeec;stop-opacity:0;" /> + </linearGradient> + <linearGradient + id="linearGradient2851"> + <stop + id="stop2853" + offset="0" + style="stop-color:#73d216;stop-opacity:1;" /> + <stop + id="stop2855" + offset="1" + style="stop-color:#5ca911;stop-opacity:1;" /> + </linearGradient> + <linearGradient + y2="40.032413" + x2="17.890068" + y1="8.0617304" + x1="17.890068" + gradientUnits="userSpaceOnUse" + id="linearGradient2269" + xlink:href="#linearGradient3149" + inkscape:collect="always" /> + <linearGradient + id="linearGradient2804" + inkscape:collect="always"> + <stop + id="stop2806" + offset="0" + style="stop-color:white;stop-opacity:1;" /> + <stop + id="stop2808" + offset="1" + style="stop-color:white;stop-opacity:0;" /> + </linearGradient> + <linearGradient + id="linearGradient2812" + inkscape:collect="always"> + <stop + id="stop2814" + offset="0" + style="stop-color:#2e3436;stop-opacity:1;" /> + <stop + id="stop2816" + offset="1" + style="stop-color:#2e3436;stop-opacity:0;" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2804" + id="linearGradient1983" + gradientUnits="userSpaceOnUse" + x1="4.5264969" + y1="2.7991772" + x2="10.623409" + y2="11.024895" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient2812" + id="radialGradient1985" + gradientUnits="userSpaceOnUse" + cx="31.112698" + cy="19.008621" + fx="31.112698" + fy="19.008621" + r="8.6620579" /> + <linearGradient + gradientTransform="matrix(0.999824,0,0,0.999281,2.209264e-4,5.644055e-4)" + gradientUnits="userSpaceOnUse" y2="33.483475" + x2="15.522223" + y1="1.5657365" + x1="15.602553" + id="linearGradient2040" + xlink:href="#linearGradient2239" + inkscape:collect="always" /> + <radialGradient gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.705322,0,0,0.705327,0.719621,0.710083)" /> + r="8.6620579" + fy="19.008621" + fx="31.112698" + cy="19.008621" + cx="31.112698" + id="radialGradient2032" + xlink:href="#linearGradient3816" + inkscape:collect="always" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3816" + id="radialGradient2057" + gradientUnits="userSpaceOnUse" + cx="31.112698" + cy="19.008621" + fx="31.112698" + fy="19.008621" + r="8.6620579" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2239" + id="linearGradient2059" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.705322,0,0,0.705327,-24.28038,0.710083)" + x1="15.602553" + y1="1.5657365" + x2="15.602553" + y2="21.045444" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient2811" + id="radialGradient2817" + cx="5.2511673" + cy="7.3335675" + fx="5.2511673" + fy="7.3335675" + r="0.82651663" + gradientTransform="matrix(1,0,0,1.337946,0,-2.478349)" + gradientUnits="userSpaceOnUse" /> </defs> <sodipodi:namedview id="base" @@ -97,18 +286,18 @@ borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="19.69831" - inkscape:cx="17.254293" - inkscape:cy="10.464226" + inkscape:zoom="13.928809" + inkscape:cx="38.913091" + inkscape:cy="9.6136547" inkscape:current-layer="layer1" showgrid="true" inkscape:grid-bbox="true" inkscape:document-units="px" fill="#729fcf" - inkscape:window-width="1268" - inkscape:window-height="972" - inkscape:window-x="6" - inkscape:window-y="21" /> + inkscape:window-width="1434" + inkscape:window-height="844" + inkscape:window-x="0" + inkscape:window-y="0" /> <metadata id="metadata1336"> <rdf:RDF> @@ -130,63 +319,162 @@ sodipodi:rx="8.6620579" sodipodi:cy="19.008621" sodipodi:cx="31.112698" - id="path4318" - style="opacity:0.7;color:#000000;fill:url(#radialGradient3822);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" + id="path1948" + style="color:black;fill:url(#radialGradient1985);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" sodipodi:type="arc" - transform="matrix(1.385352,0,0,0.634953,-31.10204,6.430418)" /> + transform="matrix(1.269906,0,0,0.346338,-27.5102,14.41659)" /> <path sodipodi:type="arc" - style="opacity:1;color:#000000;fill:#729fcf;fill-opacity:1;fill-rule:evenodd;stroke:#204a87;stroke-width:1.36561811px;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - id="path1339" + style="color:black;fill:#729fcf;fill-opacity:1;fill-rule:evenodd;stroke:#173867;stroke-width:1.3043046px;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" + id="path1951" sodipodi:cx="15.590227" sodipodi:cy="16.57217" sodipodi:rx="14.345175" sodipodi:ry="14.345175" d="M 29.935402 16.57217 A 14.345175 14.345175 0 1 1 1.2450523,16.57217 A 14.345175 14.345175 0 1 1 29.935402 16.57217 z" - transform="matrix(0.732268,0,0,0.732268,0.582335,-0.13671)" /> + transform="matrix(0.766665,0,0,0.766715,-0.450429,-1.204777)" /> <path sodipodi:type="arc" - style="opacity:1;color:#000000;fill:#eeeeec;fill-opacity:1;fill-rule:evenodd;stroke:#204a87;stroke-width:1.68800032px;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - id="path1341" + style="fill:#8ab0d7;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="path2788" + sodipodi:cx="-3.8088531" + sodipodi:cy="3.303823" + sodipodi:rx="3.1932809" + sodipodi:ry="3.3471739" + d="M -0.61557221 3.303823 A 3.1932809 3.3471739 0 1 1 -7.0021341,3.303823 A 3.1932809 3.3471739 0 1 1 -0.61557221 3.303823 z" + transform="matrix(3.246937,0,0,3.097864,23.99872,1.396119)" /> + <path + sodipodi:type="arc" + style="opacity:0.40340911;color:black;fill:#babdb6;fill-opacity:1;fill-rule:evenodd;stroke:#173867;stroke-width:1.59390604px;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" + id="path1954" sodipodi:cx="15.590227" sodipodi:cy="16.57217" sodipodi:rx="14.345175" sodipodi:ry="14.345175" d="M 29.935402 16.57217 A 14.345175 14.345175 0 1 1 1.2450523,16.57217 A 14.345175 14.345175 0 1 1 29.935402 16.57217 z" - transform="matrix(0.592417,0,0,0.592416,2.763254,2.183203)" /> + transform="matrix(0.627389,0,0,0.627389,1.718859,1.102807)" /> <path sodipodi:type="arc" - style="opacity:1;color:#000000;fill:#eeeeec;fill-opacity:1;fill-rule:evenodd;stroke:#2e3436;stroke-width:7.84294748px;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - id="path2216" - sodipodi:cx="15.590227" - sodipodi:cy="16.57217" - sodipodi:rx="14.345175" - sodipodi:ry="14.345175" - d="M 29.935402 16.57217 A 14.345175 14.345175 0 1 1 1.2450523,16.57217 A 14.345175 14.345175 0 1 1 29.935402 16.57217 z" - transform="matrix(0.127505,0,0,0.127505,10.01337,9.888169)" /> + style="fill:#dcdcd8;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="path2796" + sodipodi:cx="6.0403023" + sodipodi:cy="7.5551186" + sodipodi:rx="1.615877" + sodipodi:ry="1.3273276" + d="M 7.6561793 7.5551186 A 1.615877 1.3273276 0 1 1 4.4244252,7.5551186 A 1.615877 1.3273276 0 1 1 7.6561793 7.5551186 z" + transform="matrix(5.2603,0,0,6.403843,-20.2738,-36.88179)" /> <path - style="opacity:0.5;color:#000000;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient2245);stroke-width:0.99999976px;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - d="M 21.51933,11.9953 C 21.51933,17.24738 17.256803,21.509937 12.004759,21.509937 C 6.7527164,21.509937 2.4901888,17.24738 2.4901888,11.9953 C 2.4901888,6.7432209 6.7527164,2.4806637 12.004759,2.4806637 C 17.256803,2.4806637 21.51933,6.7432209 21.51933,11.9953 z " - id="path2220" /> + sodipodi:type="arc" + style="opacity:0.76704544;fill:none;fill-opacity:1;stroke:url(#linearGradient1983);stroke-width:0.52440464;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="path2802" + sodipodi:cx="7.5" + sodipodi:cy="7" + sodipodi:rx="5.5" + sodipodi:ry="5" + d="M 13 7 A 5.5 5 0 1 1 2,7 A 5.5 5 0 1 1 13 7 z" + transform="matrix(1.818182,0,0,2,-2.136362,-2.499999)" /> <path sodipodi:type="arc" - style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="path1588" - sodipodi:cx="20.264311" - sodipodi:cy="14.476474" - sodipodi:rx="2.9448855" - sodipodi:ry="0.78724658" - d="M 23.209196 14.476474 A 2.9448855 0.78724658 0 1 1 17.319425,14.476474 A 2.9448855 0.78724658 0 1 1 23.209196 14.476474 z" - transform="matrix(0.624124,-0.624126,1.00058,1.000585,-12.1323,7.162558)" /> - <path - sodipodi:type="arc" - style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="path2476" - sodipodi:cx="20.264311" - sodipodi:cy="14.476474" - sodipodi:rx="2.9448855" - sodipodi:ry="0.78724658" - d="M 23.209196 14.476474 A 2.9448855 0.78724658 0 1 1 17.319425,14.476474 A 2.9448855 0.78724658 0 1 1 23.209196 14.476474 z" - transform="matrix(0.624125,0.624124,1.000581,-1.00058,-12.13234,16.83743)" /> + style="fill:url(#radialGradient2817);fill-opacity:1.0;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="path2852" + sodipodi:cx="6.0403023" + sodipodi:cy="7.5551186" + sodipodi:rx="1.615877" + sodipodi:ry="1.3273276" + d="M 4.835244,8.4394021 A 1.615877,1.3273276 0 0 1 6.0776839,6.2281462 L 6.0403023,7.5551186 z" + transform="matrix(3.941577,0,0,4.521472,-12.44011,-23.15852)" + sodipodi:start="2.4124729" + sodipodi:end="4.735525" /> + <rect + style="fill:#888a85;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="rect1926" + width="1" + height="1" + x="10" + y="-13" + transform="matrix(0,1,-1,0,0,0)" /> + <rect + style="fill:#888a85;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="rect1928" + width="1" + height="1" + x="12" + y="-13" + transform="matrix(0,1,-1,0,0,0)" /> + <rect + style="fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="rect2838" + width="3" + height="3" + x="10" + y="-13" + rx="1.5" + ry="1.5" + transform="matrix(0,1,-1,0,0,0)" /> + <rect + style="fill:#eeeeec;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="rect1987" + width="1" + height="1" + x="11" + y="-12" + rx="0.5" + ry="0.5" + transform="matrix(0,1,-1,0,0,0)" /> + <rect + style="fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="rect1991" + width="1" + height="1" + x="9" + y="-14" + transform="matrix(0,1,-1,0,0,0)" /> + <rect + style="fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="rect1993" + width="1" + height="1" + x="8" + y="-15" + transform="matrix(0,1,-1,0,0,0)" /> + <rect + style="fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="rect1995" + width="1" + height="1" + x="7" + y="-16" + transform="matrix(0,1,-1,0,0,0)" /> + <rect + style="fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="rect1999" + width="1" + height="1" + x="-13.953762" + y="-14" + transform="matrix(0,-1,-1,0,0,0)" /> + <rect + style="fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="rect2001" + width="1" + height="1" + x="-14.953762" + y="-15" + transform="matrix(0,-1,-1,0,0,0)" /> + <rect + style="fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="rect2003" + width="1" + height="1" + x="-15.953762" + y="-16" + transform="matrix(0,-1,-1,0,0,0)" /> + <rect + style="opacity:1;fill:#eeeeec;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="rect1932" + width="1" + height="1.0102224" + x="11" + y="10.989778" /> </g> </svg>
--- a/pidgin/pixmaps/status/22/scalable/offline.svg Thu Jun 14 19:48:48 2007 +0000 +++ b/pidgin/pixmaps/status/22/scalable/offline.svg Mon Jun 18 01:48:35 2007 +0000 @@ -7,16 +7,16 @@ xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" - xmlns:sodipodi="http://inkscape.sourceforge.net/DTD/s odipodi-0.dtd" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="24" height="24" id="svg2" sodipodi:version="0.32" - inkscape:version="0.43" + inkscape:version="0.44.1" version="1.0" - sodipodi:docbase="/home/hbons/Desktop/Gaim Refresh/status/22/scalable" - sodipodi:docname="offline22.svg" + sodipodi:docbase="/home/hbons/Desktop/experiment/status/22/scalable" + sodipodi:docname="offline.svg" inkscape:export-filename="/home/hbons/Desktop/Gaim Refresh/status/offline.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90"> @@ -24,6 +24,30 @@ id="defs4"> <linearGradient inkscape:collect="always" + id="linearGradient3034"> + <stop + style="stop-color:#babdb6;stop-opacity:1" + offset="0" + id="stop3036" /> + <stop + style="stop-color:#d3d7cf;stop-opacity:0;" + offset="1" + id="stop3038" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient2784"> + <stop + style="stop-color:#babdb6;stop-opacity:1;" + offset="0" + id="stop2786" /> + <stop + style="stop-color:#babdb6;stop-opacity:0;" + offset="1" + id="stop2788" /> + </linearGradient> + <linearGradient + inkscape:collect="always" id="linearGradient3816"> <stop style="stop-color:#000000;stop-opacity:1;" @@ -108,7 +132,1189 @@ x1="12.00096" y1="18.000015" x2="12.00096" - y2="12.421011" /> + y2="12.421011" + gradientTransform="translate(-14.51828,-0.483273)" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2784" + id="linearGradient2790" + x1="11.999999" + y1="17.358862" + x2="11.999999" + y2="11.173834" + gradientUnits="userSpaceOnUse" /> + <radialGradient + r="8.6620579" + fy="19.008621" + fx="31.112698" + cy="19.008621" + cx="31.112698" + gradientUnits="userSpaceOnUse" + id="radialGradient3286" + xlink:href="#linearGradient2812" + inkscape:collect="always" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3816" + id="radialGradient3002" + cx="31.112698" + cy="19.008621" + fx="31.112698" + fy="19.008621" + r="8.6620579" + gradientUnits="userSpaceOnUse" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3150" + id="radialGradient3201" + cx="10.748654" + cy="10.457643" + fx="10.748654" + fy="10.457643" + r="6.6449099" + gradientTransform="matrix(-0.842757,5.698892e-16,-4.565819e-9,-0.35721,19.80716,14.19321)" + gradientUnits="userSpaceOnUse" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2239" + id="linearGradient2245" + x1="15.602553" + y1="1.5657365" + x2="15.602553" + y2="21.045444" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.705322,0,0,0.705327,-24.28038,0.710083)" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient5129" + id="radialGradient3210" + cx="10.99079" + cy="5.3375292" + fx="10.99079" + fy="5.3375292" + r="5.7619157" + gradientTransform="matrix(1,0,0,0.493392,0,4.185903)" + gradientUnits="userSpaceOnUse" /> + <radialGradient + gradientUnits="userSpaceOnUse" + r="8.6620579" + fy="19.008621" + fx="31.112698" + cy="19.008621" + cx="31.112698" + id="radialGradient3212" + xlink:href="#linearGradient2812" + inkscape:collect="always" /> + <linearGradient + gradientUnits="userSpaceOnUse" + y2="11.024895" + x2="10.623409" + y1="2.7991772" + x1="4.5264969" + id="linearGradient3214" + xlink:href="#linearGradient2804" + inkscape:collect="always" /> + <linearGradient + gradientUnits="userSpaceOnUse" + y2="27.77807" + x2="12.233074" + y1="11.789385" + x1="6.878005" + id="linearGradient3216" + xlink:href="#linearGradient2851" + inkscape:collect="always" /> + <linearGradient + id="linearGradient3224"> + <stop + id="stop3226" + offset="0" + style="stop-color:#73d216;stop-opacity:1;" /> + <stop + id="stop3228" + offset="1" + style="stop-color:#5ca911;stop-opacity:1;" /> + </linearGradient> + <linearGradient + y2="40.032413" + x2="17.890068" + y1="8.0617304" + x1="17.890068" + gradientUnits="userSpaceOnUse" + id="linearGradient3230" + xlink:href="#linearGradient3149" + inkscape:collect="always" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2804" + id="linearGradient1983" + gradientUnits="userSpaceOnUse" + x1="4.5264969" + y1="2.7991772" + x2="10.623409" + y2="11.024895" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient2812" + id="radialGradient3245" + gradientUnits="userSpaceOnUse" + cx="31.112698" + cy="19.008621" + fx="31.112698" + fy="19.008621" + r="8.6620579" /> + <linearGradient + gradientTransform="matrix(0.999824,0,0,0.999281,2.209264e-4,5.644055e-4)" + gradientUnits="userSpaceOnUse" + y2="33.483475" + x2="15.522223" + y1="1.5657365" + x1="15.602553" + id="linearGradient3247" + xlink:href="#linearGradient2239" + inkscape:collect="always" /> + <radialGradient + gradientUnits="userSpaceOnUse" + r="8.6620579" + fy="19.008621" + fx="31.112698" + cy="19.008621" + cx="31.112698" + id="radialGradient3249" + xlink:href="#linearGradient3816" + inkscape:collect="always" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3816" + id="radialGradient3251" + gradientUnits="userSpaceOnUse" + cx="31.112698" + cy="19.008621" + fx="31.112698" + fy="19.008621" + r="8.6620579" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2239" + id="linearGradient2059" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.705322,0,0,0.705327,-24.28038,0.710083)" + x1="15.602553" + y1="1.5657365" + x2="15.602553" + y2="21.045444" /> + <linearGradient + y2="32.896225" + x2="11.507221" + y1="4.5275822" + x1="6.6158633" + gradientTransform="matrix(1.535977,0,0,1.528473,-0.804927,-0.69647)" + gradientUnits="userSpaceOnUse" + id="linearGradient2210" + xlink:href="#linearGradient2239" + inkscape:collect="always" /> + <linearGradient + y2="10.792614" + x2="9.0812168" + y1="-0.76356995" + x1="3.3119085" + gradientTransform="matrix(2.177693,0,0,2.167044,-2.372032,-2.235246)" + gradientUnits="userSpaceOnUse" + id="linearGradient2208" + xlink:href="#linearGradient2186" + inkscape:collect="always" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient2898" + id="radialGradient2141" + cx="4.8470273" + cy="6.9473476" + fx="4.8470273" + fy="6.9473476" + r="0.8078171" + gradientTransform="matrix(3.018423,0.664359,-1.388844,4.257661,-0.134567,-26.02469)" + gradientUnits="userSpaceOnUse" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient2812" + id="radialGradient2149" + gradientUnits="userSpaceOnUse" + cx="31.112698" + cy="19.008621" + fx="31.112698" + fy="19.008621" + r="8.6620579" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2186" + id="linearGradient2157" + x1="9.2594385" + y1="-1.5641226" + x2="11.226587" + y2="17.697369" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.684526,0,0,0.687171,-0.20455,-0.253325)" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2239" + id="linearGradient2165" + x1="8.7505674" + y1="4.5934086" + x2="31.18539" + y2="39.834526" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.482882,0,0,0.482874,0.269812,0.26982)" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3149" + id="linearGradient2167" + gradientUnits="userSpaceOnUse" + x1="17.890068" + y1="8.0617304" + x2="17.890068" + y2="40.032413" /> + <linearGradient + id="linearGradient2169"> + <stop + style="stop-color:#73d216;stop-opacity:1;" + offset="0" + id="stop2171" /> + <stop + style="stop-color:#5ca911;stop-opacity:1;" + offset="1" + id="stop2173" /> + </linearGradient> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3816" + id="radialGradient2187" + cx="31.112698" + cy="19.008621" + fx="31.112698" + fy="19.008621" + r="8.6620579" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.914124,0,0,1.631747,2.671799,-12.00863)" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2851" + id="linearGradient2857" + x1="6.878005" + y1="11.789385" + x2="12.233074" + y2="27.77807" + gradientUnits="userSpaceOnUse" /> + <linearGradient + id="linearGradient2851"> + <stop + style="stop-color:#73d216;stop-opacity:1;" + offset="0" + id="stop2853" /> + <stop + style="stop-color:#5ca911;stop-opacity:1;" + offset="1" + id="stop2855" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient3149"> + <stop + style="stop-color:#eeeeec;stop-opacity:1;" + offset="0" + id="stop3151" /> + <stop + style="stop-color:#eeeeec;stop-opacity:0;" + offset="1" + id="stop3153" /> + </linearGradient> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3816" + id="radialGradient1988" + cx="31.112698" + cy="19.008621" + fx="31.112698" + fy="19.008621" + r="8.6620579" + gradientUnits="userSpaceOnUse" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3149" + id="linearGradient3155" + x1="17.890068" + y1="8.3091545" + x2="17.890068" + y2="36.574547" + gradientUnits="userSpaceOnUse" /> + <linearGradient + y2="11.024895" + x2="10.623409" + y1="2.7991772" + x1="4.5264969" + gradientUnits="userSpaceOnUse" + id="linearGradient3007" + xlink:href="#linearGradient2804" + inkscape:collect="always" /> + <radialGradient + r="8.6620579" + fy="19.008621" + fx="31.112698" + cy="19.008621" + cx="31.112698" + gradientUnits="userSpaceOnUse" + id="radialGradient3005" + xlink:href="#linearGradient2812" + inkscape:collect="always" /> + <linearGradient + inkscape:collect="always" + id="linearGradient2812"> + <stop + style="stop-color:#2e3436;stop-opacity:1;" + offset="0" + id="stop2814" /> + <stop + style="stop-color:#2e3436;stop-opacity:0;" + offset="1" + id="stop2816" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient2804"> + <stop + style="stop-color:white;stop-opacity:1;" + offset="0" + id="stop2806" /> + <stop + style="stop-color:white;stop-opacity:0;" + offset="1" + id="stop2808" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3149" + id="linearGradient2949" + gradientUnits="userSpaceOnUse" + x1="17.890068" + y1="8.0617304" + x2="17.890068" + y2="40.032413" /> + <linearGradient + id="linearGradient2951"> + <stop + style="stop-color:#73d216;stop-opacity:1;" + offset="0" + id="stop2953" /> + <stop + style="stop-color:#5ca911;stop-opacity:1;" + offset="1" + id="stop2955" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2851" + id="linearGradient2963" + x1="6.878005" + y1="11.789385" + x2="12.233074" + y2="27.77807" + gradientUnits="userSpaceOnUse" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2804" + id="linearGradient2810" + x1="4.5264969" + y1="2.7991772" + x2="10.623409" + y2="11.024895" + gradientUnits="userSpaceOnUse" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient2812" + id="radialGradient2818" + cx="31.112698" + cy="19.008621" + fx="31.112698" + fy="19.008621" + r="8.6620579" + gradientUnits="userSpaceOnUse" /> + <linearGradient + gradientUnits="userSpaceOnUse" + y2="27.77807" + x2="12.233074" + y1="11.789385" + x1="6.878005" + id="linearGradient1955" + xlink:href="#linearGradient2851" + inkscape:collect="always" /> + <radialGradient + gradientTransform="matrix(0.914124,0,0,1.631747,2.671799,-12.00863)" + gradientUnits="userSpaceOnUse" + r="8.6620579" + fy="19.008621" + fx="31.112698" + cy="19.008621" + cx="31.112698" + id="radialGradient1953" + xlink:href="#linearGradient3816" + inkscape:collect="always" /> + <linearGradient + id="linearGradient1935"> + <stop + id="stop1937" + offset="0" + style="stop-color:#73d216;stop-opacity:1;" /> + <stop + id="stop1939" + offset="1" + style="stop-color:#5ca911;stop-opacity:1;" /> + </linearGradient> + <linearGradient + y2="40.032413" + x2="17.890068" + y1="8.0617304" + x1="17.890068" + gradientUnits="userSpaceOnUse" + id="linearGradient2269" + xlink:href="#linearGradient3149" + inkscape:collect="always" /> + <linearGradient + y2="36.603138" + x2="24.240097" + y1="9.4211226" + x1="15.498499" + gradientUnits="userSpaceOnUse" + id="linearGradient4740" + xlink:href="#linearGradient3149" + inkscape:collect="always" /> + <linearGradient + y2="27.77807" + x2="12.233074" + y1="11.789385" + x1="6.878005" + gradientUnits="userSpaceOnUse" + id="linearGradient4738" + xlink:href="#linearGradient2851" + inkscape:collect="always" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient2898" + id="radialGradient1990" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(3.018423,0.664359,-1.388844,4.257661,-0.134567,-26.02469)" + cx="4.8470273" + cy="6.9473476" + fx="4.8470273" + fy="6.9473476" + r="0.8078171" /> + <linearGradient + y2="21.045444" + x2="15.602553" + y1="1.5657365" + x1="15.602553" + gradientTransform="matrix(0.705322,0,0,0.705327,8.71963,7.710084)" + gradientUnits="userSpaceOnUse" + id="linearGradient2073" + xlink:href="#linearGradient2239" + inkscape:collect="always" /> + <radialGradient + r="8.6620579" + fy="19.008621" + fx="31.112698" + cy="19.008621" + cx="31.112698" + gradientUnits="userSpaceOnUse" + id="radialGradient2057" + xlink:href="#linearGradient3816" + inkscape:collect="always" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3816" + id="radialGradient2032" + cx="31.112698" + cy="19.008621" + fx="31.112698" + fy="19.008621" + r="8.6620579" + gradientUnits="userSpaceOnUse" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2239" + id="linearGradient2040" + x1="15.602553" + y1="1.5657365" + x2="15.522223" + y2="33.483475" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.999824,0,0,0.999281,2.209264e-4,5.644055e-4)" /> + <linearGradient + y2="11.024895" + x2="10.623409" + y1="2.7991772" + x1="4.5264969" + gradientUnits="userSpaceOnUse" + id="linearGradient2100" + xlink:href="#linearGradient2804" + inkscape:collect="always" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3149" + id="linearGradient2086" + gradientUnits="userSpaceOnUse" + x1="17.890068" + y1="8.0617304" + x2="17.890068" + y2="40.032413" /> + <linearGradient + id="linearGradient2080"> + <stop + style="stop-color:#73d216;stop-opacity:1;" + offset="0" + id="stop2082" /> + <stop + style="stop-color:#5ca911;stop-opacity:1;" + offset="1" + id="stop2084" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2851" + id="linearGradient2072" + x1="6.878005" + y1="11.789385" + x2="12.233074" + y2="27.77807" + gradientUnits="userSpaceOnUse" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2804" + id="linearGradient2070" + x1="4.5264969" + y1="2.7991772" + x2="10.623409" + y2="11.024895" + gradientUnits="userSpaceOnUse" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient2812" + id="radialGradient2068" + cx="31.112698" + cy="19.008621" + fx="31.112698" + fy="19.008621" + r="8.6620579" + gradientUnits="userSpaceOnUse" /> + <radialGradient + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1,0,0,0.493392,0,4.185903)" + r="5.7619157" + fy="5.3375292" + fx="10.99079" + cy="5.3375292" + cx="10.99079" + id="radialGradient5135" + xlink:href="#linearGradient5129" + inkscape:collect="always" /> + <radialGradient + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(-0.842757,0,0,-0.35721,19.80716,14.19321)" + r="6.6449099" + fy="10.457643" + fx="10.748654" + cy="10.457643" + cx="10.748654" + id="radialGradient2921" + xlink:href="#linearGradient3150" + inkscape:collect="always" /> + <linearGradient + id="linearGradient5129" + inkscape:collect="always"> + <stop + id="stop5131" + offset="0" + style="stop-color:white;stop-opacity:1;" /> + <stop + id="stop5133" + offset="1" + style="stop-color:white;stop-opacity:0;" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3149" + id="linearGradient2126" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.466524,0,0,0.466525,38.65385,10.80199)" + x1="15.498499" + y1="9.4211226" + x2="24.240097" + y2="36.603138" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2239" + id="linearGradient2132" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.705322,0,0,0.705327,-58.76363,3.243275)" + x1="15.602553" + y1="1.5657365" + x2="15.602553" + y2="21.045444" /> + <linearGradient + id="linearGradient2239" + inkscape:collect="always"> + <stop + id="stop2241" + offset="0" + style="stop-color:#ffffff;stop-opacity:1;" /> + <stop + id="stop2243" + offset="1" + style="stop-color:#ffffff;stop-opacity:0;" /> + </linearGradient> + <linearGradient + id="linearGradient2186" + inkscape:collect="always"> + <stop + id="stop2188" + offset="0" + style="stop-color:#ffffff;stop-opacity:1;" /> + <stop + id="stop2190" + offset="1" + style="stop-color:#ffffff;stop-opacity:0;" /> + </linearGradient> + <linearGradient + id="linearGradient2898" + inkscape:collect="always"> + <stop + id="stop2900" + offset="0" + style="stop-color:#000000;stop-opacity:1;" /> + <stop + id="stop2902" + offset="1" + style="stop-color:#000000;stop-opacity:0;" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2186" + id="linearGradient3014" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(2.177693,0,0,2.167044,21.62797,-2.235244)" + x1="3.3119085" + y1="-0.76356995" + x2="9.0812168" + y2="10.792614" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2239" + id="linearGradient3016" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1.535977,0,0,1.528473,23.19507,-0.696468)" + x1="6.6158633" + y1="4.5275822" + x2="11.507221" + y2="32.896225" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient2812" + id="radialGradient3021" + gradientUnits="userSpaceOnUse" + cx="31.112698" + cy="19.008621" + fx="31.112698" + fy="19.008621" + r="8.6620579" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3034" + id="linearGradient3040" + x1="11.500003" + y1="19.000008" + x2="11.500003" + y2="9.3821249" + gradientUnits="userSpaceOnUse" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3034" + id="linearGradient3044" + gradientUnits="userSpaceOnUse" + x1="11.500003" + y1="19.000008" + x2="11.500003" + y2="9.3821249" + gradientTransform="matrix(0.857143,0,0,0.857143,1.642855,1.64286)" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3034" + id="linearGradient3048" + gradientUnits="userSpaceOnUse" + x1="11.500003" + y1="19.000008" + x2="11.500003" + y2="9.3821249" /> + <radialGradient + r="8.6620579" + fy="19.008621" + fx="31.112698" + cy="19.008621" + cx="31.112698" + gradientUnits="userSpaceOnUse" + id="radialGradient2062" + xlink:href="#linearGradient2812" + inkscape:collect="always" /> + <linearGradient + y2="27.77807" + x2="12.233074" + y1="11.789385" + x1="6.878005" + gradientTransform="matrix(1.076595,0,0,1.076595,-34.76035,-3.418494)" + gradientUnits="userSpaceOnUse" + id="linearGradient2253" + xlink:href="#linearGradient2851" + inkscape:collect="always" /> + <linearGradient + y2="36.603138" + x2="24.240097" + y1="9.4211226" + x1="15.498499" + gradientTransform="matrix(1.004822,0,0,1.004822,-33.47635,-2.157242)" + gradientUnits="userSpaceOnUse" + id="linearGradient2056" + xlink:href="#linearGradient3149" + inkscape:collect="always" /> + <linearGradient + id="linearGradient2246"> + <stop + style="stop-color:#73d216;stop-opacity:1;" + offset="0" + id="stop2248" /> + <stop + style="stop-color:#5ca911;stop-opacity:1;" + offset="1" + id="stop2250" /> + </linearGradient> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3816" + id="radialGradient1983" + cx="31.112698" + cy="19.008621" + fx="31.112698" + fy="19.008621" + r="8.6620579" + gradientUnits="userSpaceOnUse" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3149" + id="linearGradient2236" + x1="17.890068" + y1="8.3091545" + x2="17.890068" + y2="36.574547" + gradientUnits="userSpaceOnUse" /> + <radialGradient + r="8.6620579" + fy="19.008621" + fx="31.112698" + cy="19.008621" + cx="31.112698" + gradientUnits="userSpaceOnUse" + id="radialGradient3025" + xlink:href="#linearGradient2812" + inkscape:collect="always" /> + <linearGradient + y2="11.024895" + x2="10.623409" + y1="2.7991772" + x1="4.5264969" + gradientUnits="userSpaceOnUse" + id="linearGradient2232" + xlink:href="#linearGradient2804" + inkscape:collect="always" /> + <radialGradient + r="8.6620579" + fy="19.008621" + fx="31.112698" + cy="19.008621" + cx="31.112698" + gradientUnits="userSpaceOnUse" + id="radialGradient2230" + xlink:href="#linearGradient2812" + inkscape:collect="always" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3149" + id="linearGradient2215" + gradientUnits="userSpaceOnUse" + x1="17.890068" + y1="8.0617304" + x2="17.890068" + y2="40.032413" /> + <linearGradient + id="linearGradient2209"> + <stop + style="stop-color:#73d216;stop-opacity:1;" + offset="0" + id="stop2211" /> + <stop + style="stop-color:#5ca911;stop-opacity:1;" + offset="1" + id="stop2213" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2851" + id="linearGradient2206" + x1="6.878005" + y1="11.789385" + x2="12.233074" + y2="27.77807" + gradientUnits="userSpaceOnUse" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2804" + id="linearGradient2204" + x1="4.5264969" + y1="2.7991772" + x2="10.623409" + y2="11.024895" + gradientUnits="userSpaceOnUse" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient2812" + id="radialGradient2202" + cx="31.112698" + cy="19.008621" + fx="31.112698" + fy="19.008621" + r="8.6620579" + gradientUnits="userSpaceOnUse" /> + <radialGradient + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(3.018423,0.664359,-1.388844,4.257661,-0.134567,-26.02469)" + r="0.8078171" + fy="6.9473476" + fx="4.8470273" + cy="6.9473476" + cx="4.8470273" + id="radialGradient2904" + xlink:href="#linearGradient2898" + inkscape:collect="always" /> + <linearGradient + gradientUnits="userSpaceOnUse" + y2="27.77807" + x2="12.233074" + y1="11.789385" + x1="6.878005" + id="linearGradient2199" + xlink:href="#linearGradient2851" + inkscape:collect="always" /> + <radialGradient + gradientTransform="matrix(0.914124,-3.896132e-15,-2.475021e-18,1.631747,2.671799,-12.00863)" + gradientUnits="userSpaceOnUse" + r="8.6620579" + fy="19.008621" + fx="31.112698" + cy="19.008621" + cx="31.112698" + id="radialGradient2197" + xlink:href="#linearGradient3816" + inkscape:collect="always" /> + <linearGradient + id="linearGradient2191"> + <stop + id="stop2193" + offset="0" + style="stop-color:#73d216;stop-opacity:1;" /> + <stop + id="stop2195" + offset="1" + style="stop-color:#5ca911;stop-opacity:1;" /> + </linearGradient> + <linearGradient + y2="40.032413" + x2="17.890068" + y1="8.0617304" + x1="17.890068" + gradientUnits="userSpaceOnUse" + id="linearGradient2189" + xlink:href="#linearGradient3149" + inkscape:collect="always" /> + <linearGradient + y2="36.603138" + x2="24.240097" + y1="9.4211226" + x1="15.498499" + gradientUnits="userSpaceOnUse" + id="linearGradient2187" + xlink:href="#linearGradient3149" + inkscape:collect="always" /> + <linearGradient + y2="27.77807" + x2="12.233074" + y1="11.789385" + x1="6.878005" + gradientUnits="userSpaceOnUse" + id="linearGradient2184" + xlink:href="#linearGradient2851" + inkscape:collect="always" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3149" + id="linearGradient2176" + gradientUnits="userSpaceOnUse" + x1="15.498499" + y1="9.4211226" + x2="24.240097" + y2="36.603138" + gradientTransform="matrix(1.004822,0,0,1.004822,-2.476351,-2.157242)" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2851" + id="linearGradient1986" + gradientUnits="userSpaceOnUse" + x1="6.878005" + y1="11.789385" + x2="12.233074" + y2="27.77807" + gradientTransform="matrix(1.076595,0,0,1.076595,-3.760351,-3.418494)" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient2898" + id="radialGradient2173" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(3.018423,0.664359,-1.388844,4.257661,-0.134567,-26.02469)" + cx="4.8470273" + cy="6.9473476" + fx="4.8470273" + fy="6.9473476" + r="0.8078171" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient2812" + id="radialGradient1992" + gradientUnits="userSpaceOnUse" + cx="31.112698" + cy="19.008621" + fx="31.112698" + fy="19.008621" + r="8.6620579" /> + <linearGradient + y2="21.045444" + x2="15.602553" + y1="1.5657365" + x1="15.602553" + gradientTransform="matrix(0.705322,0,0,0.705327,8.71963,7.710084)" + gradientUnits="userSpaceOnUse" + id="linearGradient2170" + xlink:href="#linearGradient2239" + inkscape:collect="always" /> + <radialGradient + r="8.6620579" + fy="19.008621" + fx="31.112698" + cy="19.008621" + cx="31.112698" + gradientUnits="userSpaceOnUse" + id="radialGradient2167" + xlink:href="#linearGradient3816" + inkscape:collect="always" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3816" + id="radialGradient2165" + cx="31.112698" + cy="19.008621" + fx="31.112698" + fy="19.008621" + r="8.6620579" + gradientUnits="userSpaceOnUse" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2239" + id="linearGradient2163" + x1="15.602553" + y1="1.5657365" + x2="15.522223" + y2="33.483475" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.999824,0,0,0.999281,2.209264e-4,5.644055e-4)" /> + <radialGradient + r="8.6620579" + fy="19.008621" + fx="31.112698" + cy="19.008621" + cx="31.112698" + gradientUnits="userSpaceOnUse" + id="radialGradient1985" + xlink:href="#linearGradient2812" + inkscape:collect="always" /> + <linearGradient + y2="11.024895" + x2="10.623409" + y1="2.7991772" + x1="4.5264969" + gradientUnits="userSpaceOnUse" + id="linearGradient2160" + xlink:href="#linearGradient2804" + inkscape:collect="always" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3149" + id="linearGradient2158" + gradientUnits="userSpaceOnUse" + x1="17.890068" + y1="8.0617304" + x2="17.890068" + y2="40.032413" /> + <linearGradient + id="linearGradient2151"> + <stop + style="stop-color:#73d216;stop-opacity:1;" + offset="0" + id="stop2153" /> + <stop + style="stop-color:#5ca911;stop-opacity:1;" + offset="1" + id="stop2155" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2851" + id="linearGradient2149" + x1="6.878005" + y1="11.789385" + x2="12.233074" + y2="27.77807" + gradientUnits="userSpaceOnUse" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2804" + id="linearGradient2147" + x1="4.5264969" + y1="2.7991772" + x2="10.623409" + y2="11.024895" + gradientUnits="userSpaceOnUse" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient2812" + id="radialGradient2144" + cx="31.112698" + cy="19.008621" + fx="31.112698" + fy="19.008621" + r="8.6620579" + gradientUnits="userSpaceOnUse" /> + <radialGradient + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1,0,0,0.493392,0,4.185903)" + r="5.7619157" + fy="5.3375292" + fx="10.99079" + cy="5.3375292" + cx="10.99079" + id="radialGradient2142" + xlink:href="#linearGradient5129" + inkscape:collect="always" /> + <radialGradient + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(-0.842757,0,0,-0.35721,19.80716,14.19321)" + r="6.6449099" + fy="10.457643" + fx="10.748654" + cy="10.457643" + cx="10.748654" + id="radialGradient2035" + xlink:href="#linearGradient3150" + inkscape:collect="always" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3149" + id="linearGradient2127" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.466524,0,0,0.466525,38.65385,10.80199)" + x1="15.498499" + y1="9.4211226" + x2="24.240097" + y2="36.603138" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2239" + id="linearGradient2125" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.705322,0,0,0.705327,-58.76363,3.243275)" + x1="15.602553" + y1="1.5657365" + x2="15.602553" + y2="21.045444" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3149" + id="linearGradient2146" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.466524,0,0,0.466525,38.65385,10.80199)" + x1="15.498499" + y1="9.4211226" + x2="24.240097" + y2="36.603138" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient2812" + id="radialGradient2148" + gradientUnits="userSpaceOnUse" + cx="31.112698" + cy="19.008621" + fx="31.112698" + fy="19.008621" + r="8.6620579" /> + <linearGradient + gradientTransform="matrix(1.40375,0,0,1.403934,-1.668488,-1.296374)" + y2="9.1482677" + x2="12.00096" + y1="17.203793" + x1="12.00096" + gradientUnits="userSpaceOnUse" + id="linearGradient2121" + xlink:href="#linearGradient2235" + inkscape:collect="always" /> + <linearGradient + gradientUnits="userSpaceOnUse" + y2="14.895812" + x2="11.802028" + y1="1.9986149" + x1="11.802028" + id="linearGradient2119" + xlink:href="#linearGradient2225" + inkscape:collect="always" /> + <radialGradient + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(-0.842757,5.698892e-16,-4.565819e-9,-0.35721,19.80716,14.19321)" + r="6.6449099" + fy="10.457643" + fx="10.748654" + cy="10.457643" + cx="10.748654" + id="radialGradient2105" + xlink:href="#linearGradient3150" + inkscape:collect="always" /> + <radialGradient + gradientUnits="userSpaceOnUse" + r="8.6620579" + fy="19.008621" + fx="31.112698" + cy="19.008621" + cx="31.112698" + id="radialGradient2097" + xlink:href="#linearGradient3816" + inkscape:collect="always" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2225" + id="linearGradient2268" + gradientUnits="userSpaceOnUse" + x1="11.802028" + y1="1.9986149" + x2="11.802028" + y2="14.895812" /> </defs> <sodipodi:namedview id="base" @@ -118,16 +1324,18 @@ inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="20.899939" - inkscape:cx="21.212814" - inkscape:cy="11.149734" + inkscape:cx="22.169755" + inkscape:cy="10.589231" inkscape:document-units="px" inkscape:current-layer="layer1" showgrid="true" fill="#888a85" - inkscape:window-width="1268" - inkscape:window-height="971" - inkscape:window-x="6" - inkscape:window-y="21" /> + inkscape:window-width="1434" + inkscape:window-height="844" + inkscape:window-x="0" + inkscape:window-y="0" + showguides="true" + inkscape:guide-bbox="true" /> <metadata id="metadata7"> <rdf:RDF> @@ -149,39 +1357,29 @@ sodipodi:rx="8.6620579" sodipodi:cy="19.008621" sodipodi:cx="31.112698" - id="path4318" - style="opacity:0.7;color:#000000;fill:url(#radialGradient3822);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" + id="path1948" + style="color:black;fill:url(#radialGradient3021);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" sodipodi:type="arc" - transform="matrix(1.385352,0,0,0.634953,-31.10204,6.430418)" /> + transform="matrix(1.269906,0,0,0.346338,-27.5102,14.41659)" /> <path - style="fill:#888a85;fill-opacity:1;stroke:#555753;stroke-width:0.99999809;stroke-miterlimit:4;stroke-opacity:1" - d="M 19.424962,19.424965 C 15.325526,23.524403 8.6720624,23.525096 4.5734814,19.426514 C 0.47490009,15.327931 0.47559413,8.6744652 4.5750306,4.5750271 C 8.6744668,0.4755893 15.32793,0.47489516 19.426511,4.573478 C 23.525092,8.6720606 23.524399,15.325527 19.424962,19.424965 z " + style="fill:#888a85;fill-opacity:1;stroke:#2e3436;stroke-width:0.99999821;stroke-miterlimit:4;stroke-opacity:1" + d="M 19.27853,19.278538 C 14.983883,23.573188 8.0135883,23.573914 3.719837,19.280161 C -0.57391464,14.986408 -0.57318755,8.0161106 3.72146,3.7214613 C 8.0161072,-0.57318761 14.986402,-0.57391481 19.280153,3.7198384 C 23.573904,8.0135915 23.573178,14.983889 19.27853,19.278538 z " id="path2187" /> <path - sodipodi:type="inkscape:offset" - inkscape:radius="-1.0137641" - inkscape:original="M 12 1.5 C 9.311882 1.5002804 6.612218 2.5127812 4.5625 4.5625 C 0.46306353 8.6619381 0.46391853 15.338917 4.5625 19.4375 C 8.661081 23.536082 15.338065 23.536938 19.4375 19.4375 C 23.536937 15.338062 23.53608 8.6610824 19.4375 4.5625 C 17.388209 2.5132086 14.688118 1.4997196 12 1.5 z " - xlink:href="#path2187" - style="fill:url(#linearGradient2231);fill-opacity:1.0;stroke:#ffffff;stroke-width:0.99999809;stroke-miterlimit:4;stroke-opacity:1;opacity:0.4" - id="path2215" - inkscape:href="#path2187" - d="M 12,2.5 C 9.5663798,2.5002539 7.1342728,3.4282024 5.28125,5.28125 C 1.5710546,8.9914951 1.5718911,15.009341 5.28125,18.71875 C 8.9905967,22.428146 15.008567,22.428982 18.71875,18.71875 C 22.428945,15.008505 22.428107,8.990658 18.71875,5.28125 C 16.86613,3.4286052 14.43323,2.4997462 12,2.5 z " /> + style="opacity:0.4;fill:url(#linearGradient2231);fill-opacity:1;stroke:white;stroke-width:0.99999809;stroke-miterlimit:4;stroke-opacity:1" + d="M 11.5,1.5 C 8.9408673,1.500267 6.3904601,2.4845389 4.4375,4.4375 C 0.53092837,8.3440732 0.53180564,14.656804 4.4375,18.5625 C 8.3431938,22.468195 14.655929,22.469073 18.5625,18.5625 C 22.469072,14.655927 22.468194,8.3431958 18.5625,4.4375 C 16.609962,2.4849619 14.058743,1.4997331 11.5,1.5 z " + id="path2215" /> <path - style="opacity:1;fill:#eeeeec;fill-opacity:1;stroke:none;stroke-width:1.00000036;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - d="M 15.713272,5.1062978 L 12.00096,8.8186095 L 8.2886482,5.1062978 L 5.0182784,8.3766676 L 8.7305901,12.088979 L 5.1066667,15.712903 L 8.3770366,18.983273 L 12.00096,15.359349 L 15.602786,18.961176 L 18.873156,15.690806 L 15.27133,12.088979 L 18.983642,8.3766676 L 15.713272,5.1062978 z " - id="path2233" /> + style="opacity:1;fill:#eeeeec;fill-opacity:1;stroke:none;stroke-width:1.00000024;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="M 15.527292,4.7878577 C 15.153659,4.4142246 14.558496,4.4142246 14.184863,4.7878577 L 11.500003,7.4727164 L 8.7941693,4.7668822 C 8.4383282,4.4110411 7.849532,4.4110411 7.4936909,4.7668822 L 4.7668812,7.4936919 C 4.4110402,7.8495329 4.4110401,8.4383292 4.7668812,8.7941703 L 7.4727154,11.500004 L 4.7878567,14.184864 C 4.4142238,14.558497 4.4142236,15.15366 4.7878567,15.527293 L 7.4727154,18.212151 C 7.8463484,18.585784 8.4415118,18.585784 8.8151448,18.212151 L 11.500003,15.527293 L 14.205838,18.233126 C 14.561679,18.588967 15.150475,18.588967 15.506317,18.233126 L 18.233125,15.506318 C 18.588966,15.150476 18.588965,14.56168 18.233125,14.205839 L 15.527292,11.500004 L 18.21215,8.8151458 C 18.585783,8.4415126 18.585784,7.84635 18.21215,7.4727164 L 15.527292,4.7878577 z " + id="path3032" /> <path - style="opacity:1;fill:url(#linearGradient2270);fill-opacity:1;stroke:#555753;stroke-width:1.00000036;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - d="M 15.713272,5.1062978 L 12.00096,8.8186095 L 8.2886482,5.1062978 L 5.0182784,8.3766676 L 8.7305901,12.088979 L 5.1066667,15.712903 L 8.3770366,18.983273 L 12.00096,15.359349 L 15.602786,18.961176 L 18.873156,15.690806 L 15.27133,12.088979 L 18.983642,8.3766676 L 15.713272,5.1062978 z " - id="rect2204" /> + style="opacity:1;fill:url(#linearGradient3040);fill-opacity:1.0;stroke:#555753;stroke-width:1.00000024;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="M 15.527292,4.7878577 C 15.153659,4.4142246 14.558496,4.4142246 14.184863,4.7878577 L 11.500003,7.4727164 L 8.7941693,4.7668822 C 8.4383282,4.4110411 7.849532,4.4110411 7.4936909,4.7668822 L 4.7668812,7.4936919 C 4.4110402,7.8495329 4.4110401,8.4383292 4.7668812,8.7941703 L 7.4727154,11.500004 L 4.7878567,14.184864 C 4.4142238,14.558497 4.4142236,15.15366 4.7878567,15.527293 L 7.4727154,18.212151 C 7.8463484,18.585784 8.4415118,18.585784 8.8151448,18.212151 L 11.500003,15.527293 L 14.205838,18.233126 C 14.561679,18.588967 15.150475,18.588967 15.506317,18.233126 L 18.233125,15.506318 C 18.588966,15.150476 18.588965,14.56168 18.233125,14.205839 L 15.527292,11.500004 L 18.21215,8.8151458 C 18.585783,8.4415126 18.585784,7.84635 18.21215,7.4727164 L 15.527292,4.7878577 z " + id="rect3024" /> <path - sodipodi:type="inkscape:offset" - inkscape:radius="-1.0009557" - inkscape:original="M 8.28125 5.09375 L 5.03125 8.375 L 8.71875 12.09375 L 5.09375 15.71875 L 8.375 18.96875 L 12 15.34375 L 15.59375 18.96875 L 18.875 15.6875 L 15.28125 12.09375 L 18.96875 8.375 L 15.71875 5.09375 L 12 8.8125 L 8.28125 5.09375 z " - xlink:href="#rect2204" - style="opacity:1;fill:none;fill-opacity:1;stroke:#e1e1e1;stroke-width:1.00000036;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="path2268" - inkscape:href="#rect2204" - d="M 8.28125,6.53125 L 6.46875,8.375 L 9.4375,11.375 C 9.6319915,11.563548 9.7417695,11.822867 9.7417695,12.09375 C 9.7417695,12.364633 9.6319915,12.623952 9.4375,12.8125 L 6.53125,15.71875 L 8.375,17.53125 L 11.28125,14.625 C 11.469798,14.430508 11.729117,14.320731 12,14.320731 C 12.270883,14.320731 12.530202,14.430508 12.71875,14.625 L 15.59375,17.53125 L 17.4375,15.6875 L 14.5625,12.8125 C 14.368008,12.623952 14.258231,12.364633 14.258231,12.09375 C 14.258231,11.822867 14.368008,11.563548 14.5625,11.375 L 17.53125,8.375 L 15.71875,6.53125 L 12.71875,9.53125 C 12.530202,9.7257415 12.270883,9.8355195 12,9.8355195 C 11.729117,9.8355195 11.469798,9.7257415 11.28125,9.53125 L 8.28125,6.53125 z " /> + style="fill:none;fill-opacity:1;stroke:white;stroke-width:1.00000024;stroke-miterlimit:4;stroke-opacity:1" + d="M 8.15625,5.625 L 5.625,8.15625 L 8.21875,10.78125 C 8.6216689,11.187934 8.6216689,11.843316 8.21875,12.25 L 5.625,14.875 L 8.125,17.375 L 10.75,14.78125 C 11.156684,14.378331 11.812066,14.378331 12.21875,14.78125 L 14.84375,17.375 L 17.375,14.84375 L 14.78125,12.21875 C 14.378331,11.812066 14.378331,11.156684 14.78125,10.75 L 17.375,8.125 L 14.875,5.625 L 12.25,8.21875 C 11.843316,8.6216689 11.187934,8.6216689 10.78125,8.21875 L 8.15625,5.625 z " + id="path3050" /> </g> </svg>
--- a/pidgin/pixmaps/status/32/scalable/available.svg Thu Jun 14 19:48:48 2007 +0000 +++ b/pidgin/pixmaps/status/32/scalable/available.svg Mon Jun 18 01:48:35 2007 +0000 @@ -7,19 +7,19 @@ xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" - xmlns:sodipodi="http://inkscape.sourceforge.net/DTD/s odipodi-0.dtd" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="32" height="32" id="svg2" sodipodi:version="0.32" - inkscape:version="0.43" + inkscape:version="0.44.1" version="1.0" inkscape:export-filename="/home/hbons/Desktop/Gaim Refresh/status/32/available32.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" - sodipodi:docbase="/home/hbons/Desktop/Gaim Refresh/status/32/scalable" - sodipodi:docname="available32.svg"> + sodipodi:docbase="/home/hbons/Desktop/experiment/status/32/scalable" + sodipodi:docname="available.svg"> <defs id="defs4"> <linearGradient @@ -76,15 +76,434 @@ x2="17.890068" y2="36.574547" gradientUnits="userSpaceOnUse" /> + <radialGradient + r="8.6620579" + fy="19.008621" + fx="31.112698" + cy="19.008621" + cx="31.112698" + gradientUnits="userSpaceOnUse" + id="radialGradient3025" + xlink:href="#linearGradient2812" + inkscape:collect="always" /> + <linearGradient + y2="11.024895" + x2="10.623409" + y1="2.7991772" + x1="4.5264969" + gradientUnits="userSpaceOnUse" + id="linearGradient3007" + xlink:href="#linearGradient2804" + inkscape:collect="always" /> + <radialGradient + r="8.6620579" + fy="19.008621" + fx="31.112698" + cy="19.008621" + cx="31.112698" + gradientUnits="userSpaceOnUse" + id="radialGradient3005" + xlink:href="#linearGradient2812" + inkscape:collect="always" /> + <linearGradient + inkscape:collect="always" + id="linearGradient2812"> + <stop + style="stop-color:#2e3436;stop-opacity:1;" + offset="0" + id="stop2814" /> + <stop + style="stop-color:#2e3436;stop-opacity:0;" + offset="1" + id="stop2816" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient2804"> + <stop + style="stop-color:white;stop-opacity:1;" + offset="0" + id="stop2806" /> + <stop + style="stop-color:white;stop-opacity:0;" + offset="1" + id="stop2808" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3149" + id="linearGradient2949" + gradientUnits="userSpaceOnUse" + x1="17.890068" + y1="8.0617304" + x2="17.890068" + y2="40.032413" /> + <linearGradient + id="linearGradient2951"> + <stop + style="stop-color:#73d216;stop-opacity:1;" + offset="0" + id="stop2953" /> + <stop + style="stop-color:#5ca911;stop-opacity:1;" + offset="1" + id="stop2955" /> + </linearGradient> <linearGradient inkscape:collect="always" xlink:href="#linearGradient2851" - id="linearGradient2857" + id="linearGradient2963" x1="6.878005" y1="11.789385" x2="12.233074" y2="27.77807" gradientUnits="userSpaceOnUse" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2804" + id="linearGradient2810" + x1="4.5264969" + y1="2.7991772" + x2="10.623409" + y2="11.024895" + gradientUnits="userSpaceOnUse" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient2812" + id="radialGradient2818" + cx="31.112698" + cy="19.008621" + fx="31.112698" + fy="19.008621" + r="8.6620579" + gradientUnits="userSpaceOnUse" /> + <radialGradient + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(3.018423,0.664359,-1.388844,4.257661,-0.134567,-26.02469)" + r="0.8078171" + fy="6.9473476" + fx="4.8470273" + cy="6.9473476" + cx="4.8470273" + id="radialGradient2904" + xlink:href="#linearGradient2898" + inkscape:collect="always" /> + <linearGradient + gradientUnits="userSpaceOnUse" + y2="27.77807" + x2="12.233074" + y1="11.789385" + x1="6.878005" + id="linearGradient1955" + xlink:href="#linearGradient2851" + inkscape:collect="always" /> + <radialGradient + gradientTransform="matrix(0.914124,-3.896132e-15,-2.475021e-18,1.631747,2.671799,-12.00863)" + gradientUnits="userSpaceOnUse" + r="8.6620579" + fy="19.008621" + fx="31.112698" + cy="19.008621" + cx="31.112698" + id="radialGradient1953" + xlink:href="#linearGradient3816" + inkscape:collect="always" /> + <linearGradient + id="linearGradient1935"> + <stop + id="stop1937" + offset="0" + style="stop-color:#73d216;stop-opacity:1;" /> + <stop + id="stop1939" + offset="1" + style="stop-color:#5ca911;stop-opacity:1;" /> + </linearGradient> + <linearGradient + y2="40.032413" + x2="17.890068" + y1="8.0617304" + x1="17.890068" + gradientUnits="userSpaceOnUse" + id="linearGradient2269" + xlink:href="#linearGradient3149" + inkscape:collect="always" /> + <linearGradient + y2="36.603138" + x2="24.240097" + y1="9.4211226" + x1="15.498499" + gradientUnits="userSpaceOnUse" + id="linearGradient4740" + xlink:href="#linearGradient3149" + inkscape:collect="always" /> + <linearGradient + y2="27.77807" + x2="12.233074" + y1="11.789385" + x1="6.878005" + gradientUnits="userSpaceOnUse" + id="linearGradient4738" + xlink:href="#linearGradient2851" + inkscape:collect="always" /> + <linearGradient + id="linearGradient2898" + inkscape:collect="always"> + <stop + id="stop2900" + offset="0" + style="stop-color:white;stop-opacity:1;" /> + <stop + id="stop2902" + offset="1" + style="stop-color:white;stop-opacity:0;" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3149" + id="linearGradient1983" + gradientUnits="userSpaceOnUse" + x1="15.498499" + y1="9.4211226" + x2="24.240097" + y2="36.603138" + gradientTransform="matrix(1.004822,0,0,1.004822,-2.476351,-2.157242)" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2851" + id="linearGradient1986" + gradientUnits="userSpaceOnUse" + x1="6.878005" + y1="11.789385" + x2="12.233074" + y2="27.77807" + gradientTransform="matrix(1.076595,0,0,1.076595,-3.760351,-3.418494)" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient2898" + id="radialGradient1990" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(3.018423,0.664359,-1.388844,4.257661,-0.134567,-26.02469)" + cx="4.8470273" + cy="6.9473476" + fx="4.8470273" + fy="6.9473476" + r="0.8078171" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient2812" + id="radialGradient1992" + gradientUnits="userSpaceOnUse" + cx="31.112698" + cy="19.008621" + fx="31.112698" + fy="19.008621" + r="8.6620579" /> + <linearGradient + y2="21.045444" + x2="15.602553" + y1="1.5657365" + x1="15.602553" + gradientTransform="matrix(0.705322,0,0,0.705327,8.71963,7.710084)" + gradientUnits="userSpaceOnUse" + id="linearGradient2073" + xlink:href="#linearGradient2239" + inkscape:collect="always" /> + <radialGradient + r="8.6620579" + fy="19.008621" + fx="31.112698" + cy="19.008621" + cx="31.112698" + gradientUnits="userSpaceOnUse" + id="radialGradient2057" + xlink:href="#linearGradient3816" + inkscape:collect="always" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3816" + id="radialGradient2032" + cx="31.112698" + cy="19.008621" + fx="31.112698" + fy="19.008621" + r="8.6620579" + gradientUnits="userSpaceOnUse" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2239" + id="linearGradient2040" + x1="15.602553" + y1="1.5657365" + x2="15.522223" + y2="33.483475" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.999824,0,0,0.999281,2.209264e-4,5.644055e-4)" /> + <radialGradient + r="8.6620579" + fy="19.008621" + fx="31.112698" + cy="19.008621" + cx="31.112698" + gradientUnits="userSpaceOnUse" + id="radialGradient1985" + xlink:href="#linearGradient2812" + inkscape:collect="always" /> + <linearGradient + y2="11.024895" + x2="10.623409" + y1="2.7991772" + x1="4.5264969" + gradientUnits="userSpaceOnUse" + id="linearGradient2100" + xlink:href="#linearGradient2804" + inkscape:collect="always" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3149" + id="linearGradient2086" + gradientUnits="userSpaceOnUse" + x1="17.890068" + y1="8.0617304" + x2="17.890068" + y2="40.032413" /> + <linearGradient + id="linearGradient2080"> + <stop + style="stop-color:#73d216;stop-opacity:1;" + offset="0" + id="stop2082" /> + <stop + style="stop-color:#5ca911;stop-opacity:1;" + offset="1" + id="stop2084" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2851" + id="linearGradient2072" + x1="6.878005" + y1="11.789385" + x2="12.233074" + y2="27.77807" + gradientUnits="userSpaceOnUse" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2804" + id="linearGradient2070" + x1="4.5264969" + y1="2.7991772" + x2="10.623409" + y2="11.024895" + gradientUnits="userSpaceOnUse" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient2812" + id="radialGradient2068" + cx="31.112698" + cy="19.008621" + fx="31.112698" + fy="19.008621" + r="8.6620579" + gradientUnits="userSpaceOnUse" /> + <radialGradient + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1,0,0,0.493392,0,4.185903)" + r="5.7619157" + fy="5.3375292" + fx="10.99079" + cy="5.3375292" + cx="10.99079" + id="radialGradient5135" + xlink:href="#linearGradient5129" + inkscape:collect="always" /> + <linearGradient + id="linearGradient2239" + inkscape:collect="always"> + <stop + id="stop2241" + offset="0" + style="stop-color:#ffffff;stop-opacity:1;" /> + <stop + id="stop2243" + offset="1" + style="stop-color:#ffffff;stop-opacity:0;" /> + </linearGradient> + <radialGradient + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(-0.842757,0,0,-0.35721,19.80716,14.19321)" + r="6.6449099" + fy="10.457643" + fx="10.748654" + cy="10.457643" + cx="10.748654" + id="radialGradient3156" + xlink:href="#linearGradient3150" + inkscape:collect="always" /> + <linearGradient + id="linearGradient3150" + inkscape:collect="always"> + <stop + id="stop3152" + offset="0" + style="stop-color:#2e3436;stop-opacity:1;" /> + <stop + id="stop3154" + offset="1" + style="stop-color:#2e3436;stop-opacity:0;" /> + </linearGradient> + <linearGradient + id="linearGradient5129" + inkscape:collect="always"> + <stop + id="stop5131" + offset="0" + style="stop-color:white;stop-opacity:1;" /> + <stop + id="stop5133" + offset="1" + style="stop-color:white;stop-opacity:0;" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3149" + id="linearGradient2126" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.466524,0,0,0.466525,38.65385,10.80199)" + x1="15.498499" + y1="9.4211226" + x2="24.240097" + y2="36.603138" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2239" + id="linearGradient2132" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.705322,0,0,0.705327,-58.76363,3.243275)" + x1="15.602553" + y1="1.5657365" + x2="15.602553" + y2="21.045444" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3149" + id="linearGradient2146" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.466524,0,0,0.466525,38.65385,10.80199)" + x1="15.498499" + y1="9.4211226" + x2="24.240097" + y2="36.603138" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient2812" + id="radialGradient2148" + gradientUnits="userSpaceOnUse" + cx="31.112698" + cy="19.008621" + fx="31.112698" + fy="19.008621" + r="8.6620579" /> </defs> <sodipodi:namedview id="base" @@ -94,16 +513,16 @@ inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="14.928527" - inkscape:cx="21.066059" - inkscape:cy="16.155598" + inkscape:cx="1.0834072" + inkscape:cy="19.47767" inkscape:document-units="px" inkscape:current-layer="layer1" showgrid="true" fill="#eeeeec" - inkscape:window-width="1268" - inkscape:window-height="968" - inkscape:window-x="6" - inkscape:window-y="21" /> + inkscape:window-width="1434" + inkscape:window-height="844" + inkscape:window-x="0" + inkscape:window-y="0" /> <metadata id="metadata7"> <rdf:RDF> @@ -120,42 +539,22 @@ inkscape:groupmode="layer" id="layer1"> <path - d="M 39.774755 19.008621 A 8.6620579 8.6620579 0 1 1 22.45064,19.008621 A 8.6620579 8.6620579 0 1 1 39.774755 19.008621 z" - sodipodi:ry="8.6620579" - sodipodi:rx="8.6620579" - sodipodi:cy="19.008621" - sodipodi:cx="31.112698" - id="path4318" - style="opacity:1;color:black;fill:url(#radialGradient3822);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - sodipodi:type="arc" - transform="matrix(1.847136,0,0,0.865845,-41.46939,8.04148)" /> - <path + transform="matrix(1.731691,0,0,0.461784,-37.88165,19.22212)" sodipodi:type="arc" - style="opacity:1;fill:url(#linearGradient2857);fill-opacity:1;fill-rule:evenodd;stroke:#418203;stroke-width:0.96092743;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="path2245" - sodipodi:cx="17.890068" - sodipodi:cy="17.572527" - sodipodi:rx="13.932817" - sodipodi:ry="13.932817" - d="M 31.822886 17.572527 A 13.932817 13.932817 0 1 1 3.9572506,17.572527 A 13.932817 13.932817 0 1 1 31.822886 17.572527 z" - transform="matrix(1.040661,0,0,1.040661,-2.617502,-2.287049)" /> + style="color:black;fill:url(#radialGradient2148);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" + id="path2173" + sodipodi:cx="31.112698" + sodipodi:cy="19.008621" + sodipodi:rx="8.6620579" + sodipodi:ry="8.6620579" + d="M 39.774755 19.008621 A 8.6620579 8.6620579 0 1 1 22.45064,19.008621 A 8.6620579 8.6620579 0 1 1 39.774755 19.008621 z" /> <path - sodipodi:type="arc" - style="opacity:0.5;fill:url(#linearGradient3155);fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.03206742;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="path3145" - sodipodi:cx="17.890068" - sodipodi:cy="17.572527" - sodipodi:rx="13.932817" - sodipodi:ry="13.932817" - d="M 31.822886 17.572527 A 13.932817 13.932817 0 1 1 3.9572506,17.572527 A 13.932817 13.932817 0 1 1 31.822886 17.572527 z" - transform="matrix(0.968935,0,0,0.968925,-1.334307,-1.026606)" /> - <image - id="image1323" - height="64.794617" - width="64.794617" - sodipodi:absref="/home/hbons/Desktop/Gaim Refresh/Tango-Palette.png" - xlink:href="/home/hbons/Desktop/Gaim Refresh/Tango-Palette.png" - x="-74" - y="-17" /> + style="fill:url(#linearGradient1986);fill-opacity:1;fill-rule:evenodd;stroke:#306300;stroke-width:0.99999946;stroke-miterlimit:4;stroke-opacity:1" + d="M 30.500005,15.500002 C 30.500005,23.780003 23.780005,30.500004 15.500008,30.500004 C 7.2200097,30.500004 0.50001191,23.780003 0.50001191,15.500002 C 0.50001191,7.2200001 7.2200097,0.49999934 15.500008,0.49999934 C 23.780005,0.49999934 30.500005,7.2200001 30.500005,15.500002 z " + id="path4331" /> + <path + style="opacity:0.6;fill:url(#linearGradient1983);fill-opacity:1;fill-rule:evenodd;stroke:white;stroke-width:0.99999863;stroke-miterlimit:4;stroke-opacity:1" + d="M 29.499996,15.5 C 29.499996,23.227999 23.227996,29.500002 15.499996,29.500002 C 7.7719974,29.500002 1.4999949,23.227999 1.4999949,15.5 C 1.4999949,7.7719992 7.7719974,1.4999993 15.499996,1.4999993 C 23.227996,1.4999993 29.499996,7.7719992 29.499996,15.5 z " + id="path4333" /> </g> </svg>
--- a/pidgin/pixmaps/status/32/scalable/away.svg Thu Jun 14 19:48:48 2007 +0000 +++ b/pidgin/pixmaps/status/32/scalable/away.svg Mon Jun 18 01:48:35 2007 +0000 @@ -7,23 +7,47 @@ xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" - xmlns:sodipodi="http://inkscape.sourceforge.net/DTD/s odipodi-0.dtd" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="32" height="32" id="svg1331" sodipodi:version="0.32" - inkscape:version="0.43" + inkscape:version="0.44.1" version="1.0" - inkscape:export-filename="/home/hbons/Desktop/Gaim Refresh/status/32/away32.png" + inkscape:export-filename="/home/hbons/GUI/Tango/Gaim Refresh/status/22/away.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" - sodipodi:docbase="/home/hbons/Desktop/Gaim Refresh/status/32/scalable" - sodipodi:docname="away32.svg"> + sodipodi:docbase="/home/hbons/Desktop/experiment/status/32/scalable" + sodipodi:docname="away.svg"> <defs id="defs1333"> <linearGradient inkscape:collect="always" + id="linearGradient2808"> + <stop + style="stop-color:white;stop-opacity:1;" + offset="0" + id="stop2810" /> + <stop + style="stop-color:white;stop-opacity:0;" + offset="1" + id="stop2812" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient5129"> + <stop + style="stop-color:white;stop-opacity:1;" + offset="0" + id="stop5131" /> + <stop + style="stop-color:white;stop-opacity:0;" + offset="1" + id="stop5133" /> + </linearGradient> + <linearGradient + inkscape:collect="always" id="linearGradient3816"> <stop style="stop-color:#000000;stop-opacity:1;" @@ -34,15 +58,28 @@ offset="1" id="stop3820" /> </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient3150"> + <stop + style="stop-color:#2e3436;stop-opacity:1;" + offset="0" + id="stop3152" /> + <stop + style="stop-color:#2e3436;stop-opacity:0;" + offset="1" + id="stop3154" /> + </linearGradient> <radialGradient inkscape:collect="always" - xlink:href="#linearGradient3816" - id="radialGradient3822" - cx="31.112698" - cy="19.008621" - fx="31.112698" - fy="19.008621" - r="8.6620579" + xlink:href="#linearGradient3150" + id="radialGradient3156" + cx="10.748654" + cy="10.457643" + fx="10.748654" + fy="10.457643" + r="6.6449099" + gradientTransform="matrix(-0.842757,0,0,-0.35721,19.80716,14.19321)" gradientUnits="userSpaceOnUse" /> <linearGradient inkscape:collect="always" @@ -56,16 +93,171 @@ offset="1" id="stop2243" /> </linearGradient> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient5129" + id="radialGradient5135" + cx="10.99079" + cy="5.3375292" + fx="10.99079" + fy="5.3375292" + r="5.7619157" + gradientTransform="matrix(1,0,0,0.493392,0,4.185903)" + gradientUnits="userSpaceOnUse" /> + <radialGradient + gradientUnits="userSpaceOnUse" + r="8.6620579" + fy="19.008621" + fx="31.112698" + cy="19.008621" + cx="31.112698" + id="radialGradient2818" + xlink:href="#linearGradient2812" + inkscape:collect="always" /> + <linearGradient + gradientUnits="userSpaceOnUse" + y2="11.024895" + x2="10.623409" + y1="2.7991772" + x1="4.5264969" + id="linearGradient2810" + xlink:href="#linearGradient2804" + inkscape:collect="always" /> + <linearGradient + gradientUnits="userSpaceOnUse" + y2="27.77807" + x2="12.233074" + y1="11.789385" + x1="6.878005" + id="linearGradient2857" + xlink:href="#linearGradient2851" + inkscape:collect="always" /> + <linearGradient + id="linearGradient3149" + inkscape:collect="always"> + <stop + id="stop3151" + offset="0" + style="stop-color:#eeeeec;stop-opacity:1;" /> + <stop + id="stop3153" + offset="1" + style="stop-color:#eeeeec;stop-opacity:0;" /> + </linearGradient> + <linearGradient + id="linearGradient2851"> + <stop + id="stop2853" + offset="0" + style="stop-color:#73d216;stop-opacity:1;" /> + <stop + id="stop2855" + offset="1" + style="stop-color:#5ca911;stop-opacity:1;" /> + </linearGradient> + <linearGradient + y2="40.032413" + x2="17.890068" + y1="8.0617304" + x1="17.890068" + gradientUnits="userSpaceOnUse" + id="linearGradient2269" + xlink:href="#linearGradient3149" + inkscape:collect="always" /> + <linearGradient + id="linearGradient2804" + inkscape:collect="always"> + <stop + id="stop2806" + offset="0" + style="stop-color:white;stop-opacity:1;" /> + <stop + id="stop2808" + offset="1" + style="stop-color:white;stop-opacity:0;" /> + </linearGradient> + <linearGradient + id="linearGradient2812" + inkscape:collect="always"> + <stop + id="stop2814" + offset="0" + style="stop-color:#2e3436;stop-opacity:1;" /> + <stop + id="stop2816" + offset="1" + style="stop-color:#2e3436;stop-opacity:0;" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2804" + id="linearGradient1983" + gradientUnits="userSpaceOnUse" + x1="4.5264969" + y1="2.7991772" + x2="10.623409" + y2="11.024895" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient2812" + id="radialGradient1985" + gradientUnits="userSpaceOnUse" + cx="31.112698" + cy="19.008621" + fx="31.112698" + fy="19.008621" + r="8.6620579" /> + <linearGradient + gradientTransform="matrix(0.999824,0,0,0.999281,2.209264e-4,5.644055e-4)" + gradientUnits="userSpaceOnUse" + y2="33.483475" + x2="15.522223" + y1="1.5657365" + x1="15.602553" + id="linearGradient2040" + xlink:href="#linearGradient2239" + inkscape:collect="always" /> + <radialGradient + gradientUnits="userSpaceOnUse" + r="8.6620579" + fy="19.008621" + fx="31.112698" + cy="19.008621" + cx="31.112698" + id="radialGradient2032" + xlink:href="#linearGradient3816" + inkscape:collect="always" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3816" + id="radialGradient2057" + gradientUnits="userSpaceOnUse" + cx="31.112698" + cy="19.008621" + fx="31.112698" + fy="19.008621" + r="8.6620579" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient2239" - id="linearGradient2245" + id="linearGradient2073" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.705322,0,0,0.705327,8.71963,7.710084)" x1="15.602553" y1="1.5657365" - x2="15.522223" - y2="33.483475" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.999824,0,0,0.999281,2.209264e-4,5.644055e-4)" /> + x2="15.602553" + y2="21.045444" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient2808" + id="radialGradient2814" + cx="5.2511673" + cy="7.3335675" + fx="5.2511673" + fy="7.3335675" + r="0.82651663" + gradientTransform="matrix(1,0,0,1.337946,0,-2.478349)" + gradientUnits="userSpaceOnUse" /> </defs> <sodipodi:namedview id="base" @@ -74,20 +266,20 @@ borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="19.69831" - inkscape:cx="23.600016" - inkscape:cy="15.388506" + inkscape:zoom="13.928809" + inkscape:cx="28.28763" + inkscape:cy="14.998178" inkscape:current-layer="layer1" showgrid="true" inkscape:grid-bbox="true" inkscape:document-units="px" fill="#729fcf" - inkscape:window-width="1268" - inkscape:window-height="972" - inkscape:window-x="6" - inkscape:window-y="21" - showguides="true" - inkscape:guide-bbox="true" /> + inkscape:window-width="1434" + inkscape:window-height="844" + inkscape:window-x="0" + inkscape:window-y="0" + width="32px" + height="32px" /> <metadata id="metadata1336"> <rdf:RDF> @@ -109,63 +301,101 @@ sodipodi:rx="8.6620579" sodipodi:cy="19.008621" sodipodi:cx="31.112698" - id="path4318" - style="opacity:1;color:#000000;fill:url(#radialGradient3822);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" + id="path1948" + style="color:black;fill:url(#radialGradient1985);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" sodipodi:type="arc" - transform="matrix(1.847136,0,0,0.865845,-41.46939,8.04148)" /> + transform="matrix(1.731691,0,0,0.461784,-37.87757,19.22211)" /> <path sodipodi:type="arc" - style="opacity:1;color:#000000;fill:#729fcf;fill-opacity:1;fill-rule:evenodd;stroke:#204a87;stroke-width:0.98932087px;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - id="path1339" + style="color:black;fill:#729fcf;fill-opacity:1;fill-rule:evenodd;stroke:#173867;stroke-width:0.95645106px;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" + id="path1951" sodipodi:cx="15.590227" sodipodi:cy="16.57217" sodipodi:rx="14.345175" sodipodi:ry="14.345175" d="M 29.935402 16.57217 A 14.345175 14.345175 0 1 1 1.2450523,16.57217 A 14.345175 14.345175 0 1 1 29.935402 16.57217 z" - transform="matrix(1.010793,0,0,1.010792,0.241509,-0.751017)" /> + transform="matrix(1.045505,0,0,1.045554,-0.797598,-1.825749)" /> <path sodipodi:type="arc" - style="opacity:1;color:#000000;fill:#eeeeec;fill-opacity:1;fill-rule:evenodd;stroke:#204a87;stroke-width:1.24782109px;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - id="path1341" + style="fill:#8ab0d7;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="path2788" + sodipodi:cx="-3.8088531" + sodipodi:cy="3.303823" + sodipodi:rx="3.1932809" + sodipodi:ry="3.3471739" + d="M -0.61557221 3.303823 A 3.1932809 3.3471739 0 1 1 -7.0021341,3.303823 A 3.1932809 3.3471739 0 1 1 -0.61557221 3.303823 z" + transform="matrix(4.414832,0,0,4.210029,32.44953,1.716868)" /> + <path + sodipodi:type="arc" + style="opacity:0.40340911;color:black;fill:#babdb6;fill-opacity:1;fill-rule:evenodd;stroke:#173867;stroke-width:1.19542968px;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" + id="path1954" sodipodi:cx="15.590227" sodipodi:cy="16.57217" sodipodi:rx="14.345175" sodipodi:ry="14.345175" d="M 29.935402 16.57217 A 14.345175 14.345175 0 1 1 1.2450523,16.57217 A 14.345175 14.345175 0 1 1 29.935402 16.57217 z" - transform="matrix(0.80139,0,0,0.801405,3.511281,2.723938)" /> + transform="matrix(0.836518,0,0,0.836518,2.458491,1.637077)" /> + <path + sodipodi:type="arc" + style="fill:#dcdcd8;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="path2796" + sodipodi:cx="6.0403023" + sodipodi:cy="7.5551186" + sodipodi:rx="1.615877" + sodipodi:ry="1.3273276" + d="M 7.6561793 7.5551186 A 1.615877 1.3273276 0 1 1 4.4244252,7.5551186 A 1.615877 1.3273276 0 1 1 7.6561793 7.5551186 z" + transform="matrix(7.116878,0,0,8.664024,-27.4881,-49.95773)" /> <path sodipodi:type="arc" - style="opacity:1;color:#000000;fill:#eeeeec;fill-opacity:1;fill-rule:evenodd;stroke:#2e3436;stroke-width:5.84032869px;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - id="path2216" + style="opacity:0.76704544;fill:none;fill-opacity:1;stroke:url(#linearGradient1983);stroke-width:0.37457478;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="path2802" + sodipodi:cx="7.5" + sodipodi:cy="7" + sodipodi:rx="5.5" + sodipodi:ry="5" + d="M 13 7 A 5.5 5 0 1 1 2,7 A 5.5 5 0 1 1 13 7 z" + transform="matrix(2.545454,0,0,2.8,-3.590908,-4.100001)" /> + <path + sodipodi:type="arc" + style="fill:url(#radialGradient2814);fill-opacity:1.0;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="path2852" + sodipodi:cx="6.0403023" + sodipodi:cy="7.5551186" + sodipodi:rx="1.615877" + sodipodi:ry="1.3273276" + d="M 4.835244,8.4394021 A 1.615877,1.3273276 0 0 1 6.0776839,6.2281462 L 6.0403023,7.5551186 z" + transform="matrix(5.732654,0,0,7.234355,-19.36499,-39.05363)" + sodipodi:start="2.4124729" + sodipodi:end="4.735525" /> + <path + sodipodi:type="arc" + style="color:black;fill:#eeeeec;fill-opacity:1;fill-rule:evenodd;stroke:#2e3436;stroke-width:7.17263222px;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" + id="path2051" sodipodi:cx="15.590227" sodipodi:cy="16.57217" sodipodi:rx="14.345175" sodipodi:ry="14.345175" d="M 29.935402 16.57217 A 14.345175 14.345175 0 1 1 1.2450523,16.57217 A 14.345175 14.345175 0 1 1 29.935402 16.57217 z" - transform="matrix(0.171225,0,0,0.171225,13.33055,13.16244)" /> - <path - style="opacity:0.5;color:#000000;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient2245);stroke-width:0.99999946px;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - d="M 29.484663,15.989048 C 29.484663,23.430003 23.442356,29.46904 15.997368,29.46904 C 8.5523815,29.46904 2.5100737,23.430003 2.5100737,15.989048 C 2.5100737,8.5480941 8.5523815,2.5090586 15.997368,2.5090586 C 23.442356,2.5090586 29.484663,8.5480941 29.484663,15.989048 z " - id="path2220" /> - <path - sodipodi:type="arc" - style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="path1342" - sodipodi:cx="19.747887" - sodipodi:cy="9.4599953" - sodipodi:rx="1.4722075" - sodipodi:ry="2.6398203" - d="M 21.220094 9.4599953 A 1.4722075 2.6398203 0 1 1 18.275679,9.4599953 A 1.4722075 2.6398203 0 1 1 21.220094 9.4599953 z" - transform="matrix(0.882374,0.509439,-0.56822,0.984187,6.966287,-8.07548)" /> - <path - sodipodi:type="arc" - style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="path1344" - sodipodi:cx="19.747887" - sodipodi:cy="9.4599953" - sodipodi:rx="1.4722075" - sodipodi:ry="2.6398203" - d="M 21.220094 9.4599953 A 1.4722075 2.6398203 0 1 1 18.275679,9.4599953 A 1.4722075 2.6398203 0 1 1 21.220094 9.4599953 z" - transform="matrix(0.882374,-0.509439,-0.56822,-0.984187,6.966287,40.07548)" /> + transform="matrix(0.13942,0,0,0.139419,13.32641,13.18954)" /> + <rect + style="fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:4.86999989;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="rect4234" + width="2.0651035" + height="6.1953154" + x="20.887754" + y="-8.7545109" + transform="matrix(0.707107,0.707107,-0.707107,0.707107,0,0)" + rx="1.0325518" + ry="1.0027943" /> + <rect + style="fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:4.86999989;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="rect2080" + width="2.065105" + height="6.1953192" + x="-1.0325458" + y="-30.674829" + transform="matrix(0.707107,-0.707107,-0.707107,-0.707107,0,0)" + rx="1.0325525" + ry="1.002795" /> </g> </svg>
--- a/pidgin/pixmaps/status/32/scalable/busy.svg Thu Jun 14 19:48:48 2007 +0000 +++ b/pidgin/pixmaps/status/32/scalable/busy.svg Mon Jun 18 01:48:35 2007 +0000 @@ -7,19 +7,19 @@ xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" - xmlns:sodipodi="http://inkscape.sourceforge.net/DTD/s odipodi-0.dtd" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="32" height="32" id="svg1331" sodipodi:version="0.32" - inkscape:version="0.43" + inkscape:version="0.44.1" version="1.0" inkscape:export-filename="/home/hbons/Desktop/Gaim Refresh/status/32/busy32.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" - sodipodi:docbase="/home/hbons/Desktop/Gaim Refresh/status/32/scalable" - sodipodi:docname="busy32.svg"> + sodipodi:docbase="/home/hbons/Desktop/experiment/32/scalable" + sodipodi:docname="busy.svg"> <defs id="defs1333"> <linearGradient @@ -34,16 +34,6 @@ offset="1" id="stop3820" /> </linearGradient> - <radialGradient - inkscape:collect="always" - xlink:href="#linearGradient3816" - id="radialGradient3822" - cx="31.112698" - cy="19.008621" - fx="31.112698" - fy="19.008621" - r="8.6620579" - gradientUnits="userSpaceOnUse" /> <linearGradient inkscape:collect="always" id="linearGradient2186"> @@ -68,26 +58,554 @@ offset="1" id="stop2243" /> </linearGradient> + <radialGradient + r="8.6620579" + fy="19.008621" + fx="31.112698" + cy="19.008621" + cx="31.112698" + gradientUnits="userSpaceOnUse" + id="radialGradient2148" + xlink:href="#linearGradient2812" + inkscape:collect="always" /> + <linearGradient + y2="36.603138" + x2="24.240097" + y1="9.4211226" + x1="15.498499" + gradientTransform="matrix(0.466524,0,0,0.466525,38.65385,10.80199)" + gradientUnits="userSpaceOnUse" + id="linearGradient2146" + xlink:href="#linearGradient3149" + inkscape:collect="always" /> + <linearGradient + y2="21.045444" + x2="15.602553" + y1="1.5657365" + x1="15.602553" + gradientTransform="matrix(0.705322,0,0,0.705327,-58.76363,3.243275)" + gradientUnits="userSpaceOnUse" + id="linearGradient2132" + xlink:href="#linearGradient2239" + inkscape:collect="always" /> + <linearGradient + y2="36.603138" + x2="24.240097" + y1="9.4211226" + x1="15.498499" + gradientTransform="matrix(0.466524,0,0,0.466525,38.65385,10.80199)" + gradientUnits="userSpaceOnUse" + id="linearGradient2126" + xlink:href="#linearGradient3149" + inkscape:collect="always" /> + <linearGradient + inkscape:collect="always" + id="linearGradient5129"> + <stop + style="stop-color:white;stop-opacity:1;" + offset="0" + id="stop5131" /> + <stop + style="stop-color:white;stop-opacity:0;" + offset="1" + id="stop5133" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient3150"> + <stop + style="stop-color:#2e3436;stop-opacity:1;" + offset="0" + id="stop3152" /> + <stop + style="stop-color:#2e3436;stop-opacity:0;" + offset="1" + id="stop3154" /> + </linearGradient> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3150" + id="radialGradient3156" + cx="10.748654" + cy="10.457643" + fx="10.748654" + fy="10.457643" + r="6.6449099" + gradientTransform="matrix(-0.842757,0,0,-0.35721,19.80716,14.19321)" + gradientUnits="userSpaceOnUse" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient5129" + id="radialGradient5135" + cx="10.99079" + cy="5.3375292" + fx="10.99079" + fy="5.3375292" + r="5.7619157" + gradientTransform="matrix(1,0,0,0.493392,0,4.185903)" + gradientUnits="userSpaceOnUse" /> + <radialGradient + gradientUnits="userSpaceOnUse" + r="8.6620579" + fy="19.008621" + fx="31.112698" + cy="19.008621" + cx="31.112698" + id="radialGradient2068" + xlink:href="#linearGradient2812" + inkscape:collect="always" /> + <linearGradient + gradientUnits="userSpaceOnUse" + y2="11.024895" + x2="10.623409" + y1="2.7991772" + x1="4.5264969" + id="linearGradient2070" + xlink:href="#linearGradient2804" + inkscape:collect="always" /> + <linearGradient + gradientUnits="userSpaceOnUse" + y2="27.77807" + x2="12.233074" + y1="11.789385" + x1="6.878005" + id="linearGradient2072" + xlink:href="#linearGradient2851" + inkscape:collect="always" /> + <linearGradient + id="linearGradient2080"> + <stop + id="stop2082" + offset="0" + style="stop-color:#73d216;stop-opacity:1;" /> + <stop + id="stop2084" + offset="1" + style="stop-color:#5ca911;stop-opacity:1;" /> + </linearGradient> + <linearGradient + y2="40.032413" + x2="17.890068" + y1="8.0617304" + x1="17.890068" + gradientUnits="userSpaceOnUse" + id="linearGradient2086" + xlink:href="#linearGradient3149" + inkscape:collect="always" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2804" + id="linearGradient2100" + gradientUnits="userSpaceOnUse" + x1="4.5264969" + y1="2.7991772" + x2="10.623409" + y2="11.024895" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient2812" + id="radialGradient1985" + gradientUnits="userSpaceOnUse" + cx="31.112698" + cy="19.008621" + fx="31.112698" + fy="19.008621" + r="8.6620579" /> + <linearGradient + gradientTransform="matrix(0.999824,0,0,0.999281,2.209264e-4,5.644055e-4)" + gradientUnits="userSpaceOnUse" + y2="33.483475" + x2="15.522223" + y1="1.5657365" + x1="15.602553" + id="linearGradient2040" + xlink:href="#linearGradient2239" + inkscape:collect="always" /> + <radialGradient + gradientUnits="userSpaceOnUse" + r="8.6620579" + fy="19.008621" + fx="31.112698" + cy="19.008621" + cx="31.112698" + id="radialGradient2032" + xlink:href="#linearGradient3816" + inkscape:collect="always" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3816" + id="radialGradient2057" + gradientUnits="userSpaceOnUse" + cx="31.112698" + cy="19.008621" + fx="31.112698" + fy="19.008621" + r="8.6620579" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient2239" - id="linearGradient2245" - x1="15.535398" - y1="1.8014067" - x2="15.535398" - y2="48.674999" + id="linearGradient2073" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.705322,0,0,0.705327,8.71963,7.710084)" + x1="15.602553" + y1="1.5657365" + x2="15.602553" + y2="21.045444" /> + <radialGradient + r="0.8078171" + fy="6.9473476" + fx="4.8470273" + cy="6.9473476" + cx="4.8470273" + gradientTransform="matrix(3.018423,0.664359,-1.388844,4.257661,-0.134567,-26.02469)" + gradientUnits="userSpaceOnUse" + id="radialGradient1990" + xlink:href="#linearGradient2898" + inkscape:collect="always" /> + <linearGradient + inkscape:collect="always" + id="linearGradient2898"> + <stop + style="stop-color:white;stop-opacity:1;" + offset="0" + id="stop2900" /> + <stop + style="stop-color:white;stop-opacity:0;" + offset="1" + id="stop2902" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2851" + id="linearGradient4738" + gradientUnits="userSpaceOnUse" + x1="6.878005" + y1="11.789385" + x2="12.233074" + y2="27.77807" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3149" + id="linearGradient4740" + gradientUnits="userSpaceOnUse" + x1="15.498499" + y1="9.4211226" + x2="24.240097" + y2="36.603138" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3149" + id="linearGradient2269" + gradientUnits="userSpaceOnUse" + x1="17.890068" + y1="8.0617304" + x2="17.890068" + y2="40.032413" /> + <linearGradient + id="linearGradient1935"> + <stop + style="stop-color:#73d216;stop-opacity:1;" + offset="0" + id="stop1937" /> + <stop + style="stop-color:#5ca911;stop-opacity:1;" + offset="1" + id="stop1939" /> + </linearGradient> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3816" + id="radialGradient1953" + cx="31.112698" + cy="19.008621" + fx="31.112698" + fy="19.008621" + r="8.6620579" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.914124,-3.896132e-15,-2.475021e-18,1.631747,2.671799,-12.00863)" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2851" + id="linearGradient1955" + x1="6.878005" + y1="11.789385" + x2="12.233074" + y2="27.77807" + gradientUnits="userSpaceOnUse" /> + <radialGradient + gradientUnits="userSpaceOnUse" + r="8.6620579" + fy="19.008621" + fx="31.112698" + cy="19.008621" + cx="31.112698" + id="radialGradient2818" + xlink:href="#linearGradient2812" + inkscape:collect="always" /> + <linearGradient + gradientUnits="userSpaceOnUse" + y2="11.024895" + x2="10.623409" + y1="2.7991772" + x1="4.5264969" + id="linearGradient2810" + xlink:href="#linearGradient2804" + inkscape:collect="always" /> + <linearGradient + gradientUnits="userSpaceOnUse" + y2="27.77807" + x2="12.233074" + y1="11.789385" + x1="6.878005" + id="linearGradient2963" + xlink:href="#linearGradient2851" + inkscape:collect="always" /> + <linearGradient + id="linearGradient2951"> + <stop + id="stop2953" + offset="0" + style="stop-color:#73d216;stop-opacity:1;" /> + <stop + id="stop2955" + offset="1" + style="stop-color:#5ca911;stop-opacity:1;" /> + </linearGradient> + <linearGradient + y2="40.032413" + x2="17.890068" + y1="8.0617304" + x1="17.890068" + gradientUnits="userSpaceOnUse" + id="linearGradient2949" + xlink:href="#linearGradient3149" + inkscape:collect="always" /> + <linearGradient + id="linearGradient2804" + inkscape:collect="always"> + <stop + id="stop2806" + offset="0" + style="stop-color:white;stop-opacity:1;" /> + <stop + id="stop2808" + offset="1" + style="stop-color:white;stop-opacity:0;" /> + </linearGradient> + <linearGradient + id="linearGradient2812" + inkscape:collect="always"> + <stop + id="stop2814" + offset="0" + style="stop-color:#2e3436;stop-opacity:1;" /> + <stop + id="stop2816" + offset="1" + style="stop-color:#2e3436;stop-opacity:0;" /> + </linearGradient> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient2812" + id="radialGradient3005" gradientUnits="userSpaceOnUse" - gradientTransform="matrix(1.000376,0,0,0.999343,-1.147524e-3,1.523185e-2)" /> + cx="31.112698" + cy="19.008621" + fx="31.112698" + fy="19.008621" + r="8.6620579" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2804" + id="linearGradient3007" + gradientUnits="userSpaceOnUse" + x1="4.5264969" + y1="2.7991772" + x2="10.623409" + y2="11.024895" /> + <linearGradient + gradientUnits="userSpaceOnUse" + y2="36.574547" + x2="17.890068" + y1="8.3091545" + x1="17.890068" + id="linearGradient3155" + xlink:href="#linearGradient3149" + inkscape:collect="always" /> + <radialGradient + gradientUnits="userSpaceOnUse" + r="8.6620579" + fy="19.008621" + fx="31.112698" + cy="19.008621" + cx="31.112698" + id="radialGradient1988" + xlink:href="#linearGradient3816" + inkscape:collect="always" /> + <linearGradient + id="linearGradient3149" + inkscape:collect="always"> + <stop + id="stop3151" + offset="0" + style="stop-color:#eeeeec;stop-opacity:1;" /> + <stop + id="stop3153" + offset="1" + style="stop-color:#eeeeec;stop-opacity:0;" /> + </linearGradient> + <linearGradient + id="linearGradient2851"> + <stop + id="stop2853" + offset="0" + style="stop-color:#73d216;stop-opacity:1;" /> + <stop + id="stop2855" + offset="1" + style="stop-color:#5ca911;stop-opacity:1;" /> + </linearGradient> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient2812" + id="radialGradient2070" + gradientUnits="userSpaceOnUse" + cx="31.112698" + cy="19.008621" + fx="31.112698" + fy="19.008621" + r="8.6620579" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3149" + id="linearGradient2083" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1.004822,0,0,1.004822,-54.47635,15.84276)" + x1="15.498499" + y1="9.4211226" + x2="24.240097" + y2="36.603138" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2851" + id="linearGradient2087" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1.076595,0,0,1.076595,-55.76035,14.58151)" + x1="6.878005" + y1="11.789385" + x2="12.233074" + y2="27.77807" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient2812" + id="radialGradient2093" + gradientUnits="userSpaceOnUse" + cx="31.112698" + cy="19.008621" + fx="31.112698" + fy="19.008621" + r="8.6620579" /> + <linearGradient + gradientUnits="userSpaceOnUse" + y2="27.77807" + x2="12.233074" + y1="11.789385" + x1="6.878005" + id="linearGradient2857" + xlink:href="#linearGradient2851" + inkscape:collect="always" /> + <radialGradient + gradientTransform="matrix(0.914124,-3.896132e-15,-2.475021e-18,1.631747,2.671799,-12.00863)" + gradientUnits="userSpaceOnUse" + r="8.6620579" + fy="19.008621" + fx="31.112698" + cy="19.008621" + cx="31.112698" + id="radialGradient2187" + xlink:href="#linearGradient3816" + inkscape:collect="always" /> + <linearGradient + id="linearGradient2169"> + <stop + id="stop2171" + offset="0" + style="stop-color:#73d216;stop-opacity:1;" /> + <stop + id="stop2173" + offset="1" + style="stop-color:#5ca911;stop-opacity:1;" /> + </linearGradient> + <linearGradient + y2="40.032413" + x2="17.890068" + y1="8.0617304" + x1="17.890068" + gradientUnits="userSpaceOnUse" + id="linearGradient2167" + xlink:href="#linearGradient3149" + inkscape:collect="always" /> + <linearGradient + gradientTransform="matrix(0.482882,0,0,0.482874,0.269812,0.26982)" + gradientUnits="userSpaceOnUse" + y2="39.834526" + x2="31.18539" + y1="4.5934086" + x1="8.7505674" + id="linearGradient2165" + xlink:href="#linearGradient2239" + inkscape:collect="always" /> + <linearGradient + gradientTransform="matrix(0.684526,0,0,0.687171,-0.20455,-0.253325)" + gradientUnits="userSpaceOnUse" + y2="17.697369" + x2="11.226587" + y1="-1.5641226" + x1="9.2594385" + id="linearGradient2157" + xlink:href="#linearGradient2186" + inkscape:collect="always" /> + <radialGradient + r="8.6620579" + fy="19.008621" + fx="31.112698" + cy="19.008621" + cx="31.112698" + gradientUnits="userSpaceOnUse" + id="radialGradient2149" + xlink:href="#linearGradient2812" + inkscape:collect="always" /> + <radialGradient + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(3.018423,0.664359,-1.388844,4.257661,-0.134567,-26.02469)" + r="0.8078171" + fy="6.9473476" + fx="4.8470273" + cy="6.9473476" + cx="4.8470273" + id="radialGradient2141" + xlink:href="#linearGradient2898" + inkscape:collect="always" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient2186" - id="linearGradient2194" - x1="11.226587" - y1="-5.4832759" - x2="11.226587" - y2="17.697369" + id="linearGradient2208" gradientUnits="userSpaceOnUse" - gradientTransform="matrix(1.418323,0,0,1.416852,-1.021803,-0.99085)" /> + gradientTransform="matrix(3.048768,0,0,3.033857,-3.920843,-3.729339)" + x1="3.3119085" + y1="-0.76356995" + x2="9.0812168" + y2="10.792614" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2239" + id="linearGradient2210" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(2.150367,0,0,2.139859,-1.726897,-1.575055)" + x1="6.6158633" + y1="4.5275822" + x2="11.507221" + y2="32.896225" /> </defs> <sodipodi:namedview id="base" @@ -96,18 +614,18 @@ borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="25.992076" - inkscape:cx="23.061682" - inkscape:cy="14.291409" + inkscape:zoom="11.313708" + inkscape:cx="32.077294" + inkscape:cy="17.208225" inkscape:current-layer="layer1" showgrid="true" inkscape:grid-bbox="true" inkscape:document-units="px" fill="#ef2929" - inkscape:window-width="1268" - inkscape:window-height="972" - inkscape:window-x="6" - inkscape:window-y="21" /> + inkscape:window-width="1440" + inkscape:window-height="849" + inkscape:window-x="0" + inkscape:window-y="0" /> <metadata id="metadata1336"> <rdf:RDF> @@ -124,43 +642,47 @@ inkscape:label="Layer 1" inkscape:groupmode="layer"> <path - d="M 39.774755 19.008621 A 8.6620579 8.6620579 0 1 1 22.45064,19.008621 A 8.6620579 8.6620579 0 1 1 39.774755 19.008621 z" - sodipodi:ry="8.6620579" - sodipodi:rx="8.6620579" - sodipodi:cy="19.008621" + transform="matrix(1.731691,0,0,0.461784,-37.87759,19.22212)" + sodipodi:type="arc" + style="color:black;fill:url(#radialGradient2093);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" + id="path2091" sodipodi:cx="31.112698" - id="path4318" - style="opacity:1;color:#000000;fill:url(#radialGradient3822);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - sodipodi:type="arc" - transform="matrix(1.847136,0,0,0.865845,-41.46938,8.041481)" /> + sodipodi:cy="19.008621" + sodipodi:rx="8.6620579" + sodipodi:ry="8.6620579" + d="M 39.774755 19.008621 A 8.6620579 8.6620579 0 1 1 22.45064,19.008621 A 8.6620579 8.6620579 0 1 1 39.774755 19.008621 z" /> <path sodipodi:type="arc" - style="opacity:1;color:#000000;fill:#ef2929;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.36561811px;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - id="path1311" + style="color:black;fill:#ef2929;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.36561811px;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" + id="path2194" sodipodi:cx="15.590227" sodipodi:cy="16.57217" sodipodi:rx="14.345175" sodipodi:ry="14.345175" d="M 29.935402 16.57217 A 14.345175 14.345175 0 1 1 1.2450523,16.57217 A 14.345175 14.345175 0 1 1 29.935402 16.57217 z" - transform="matrix(0.989705,0,0,0.989705,0.437593,-0.53424)" /> + transform="matrix(0.936036,0,0,0.936032,1.023071,0.100614)" /> <path sodipodi:type="arc" - style="opacity:1;color:#000000;fill:#ef2929;fill-opacity:1;fill-rule:evenodd;stroke:#a40000;stroke-width:0.98950732px;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - id="path1339" + style="color:black;fill:#f24747;fill-opacity:1;fill-rule:evenodd;stroke:#820000;stroke-width:0.95634508px;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" + id="path2196" sodipodi:cx="15.590227" sodipodi:cy="16.57217" sodipodi:rx="14.345175" sodipodi:ry="14.345175" d="M 29.935402 16.57217 A 14.345175 14.345175 0 1 1 1.2450523,16.57217 A 14.345175 14.345175 0 1 1 29.935402 16.57217 z" - transform="matrix(1.010428,0,0,1.010778,0.242013,-0.750701)" /> + transform="matrix(1.045648,0,0,1.045648,-0.801887,-1.828653)" /> <path - style="opacity:0.6;color:#000000;fill:url(#linearGradient2194);fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient2245);stroke-width:1.0000006px;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - d="M 29.499568,16.004716 C 29.499568,23.446135 23.453927,29.485548 16.004828,29.485548 C 8.5557329,29.485548 2.5100898,23.446135 2.5100898,16.004716 C 2.5100898,8.5632961 8.5557329,2.5238833 16.004828,2.5238833 C 23.453927,2.5238833 29.499568,8.5632961 29.499568,16.004716 z " - id="path2220" /> - <path - style="color:#000000;fill:#eeeeec;fill-opacity:1;fill-rule:evenodd;stroke:#a40000;stroke-width:0.99999958px;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - d="M 27.51954,15.864482 C 27.51954,20.204712 25.510558,19.437434 15.893137,19.437434 C 6.2213077,19.437434 4.46153,20.133953 4.46153,16.055453 C 4.46153,11.913293 6.4064326,12.529223 15.990534,12.529223 C 25.520227,12.529223 27.51954,11.460602 27.51954,15.864482 z " - id="path1341" - sodipodi:nodetypes="czzzz" /> + style="opacity:0.6;color:black;fill:url(#linearGradient2208);fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient2210);stroke-width:0.99999946px;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" + d="M 29.499988,15.499986 C 29.499988,23.227979 23.227989,29.499978 15.49999,29.499978 C 7.7719953,29.499978 1.4999991,23.227979 1.4999991,15.499986 C 1.4999991,7.7719948 7.7719953,1.4999985 15.49999,1.4999985 C 23.227989,1.4999985 29.499988,7.7719948 29.499988,15.499986 z " + id="path2199" /> + <rect + style="fill:#eeeeec;fill-opacity:1;stroke:#a40000;stroke-width:1.00000036;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="rect3207" + width="24" + height="5.9877748" + x="3.5000014" + y="12.535524" + rx="2.098541" + ry="1.919746" /> </g> </svg>
--- a/pidgin/pixmaps/status/32/scalable/offline.svg Thu Jun 14 19:48:48 2007 +0000 +++ b/pidgin/pixmaps/status/32/scalable/offline.svg Mon Jun 18 01:48:35 2007 +0000 @@ -15,7 +15,7 @@ sodipodi:version="0.32" inkscape:version="0.44.1" version="1.0" - sodipodi:docbase="/home/hbons/GUI/Tango/Gaim Refresh/status/32/scalable" + sodipodi:docbase="/home/hbons/Desktop/experiment/status/32/scalable" sodipodi:docname="offline.svg" inkscape:export-filename="/home/hbons/GUI/Tango/Gaim Refresh/status/32/offline.png" inkscape:export-xdpi="90" @@ -106,10 +106,498 @@ id="linearGradient2270" gradientUnits="userSpaceOnUse" x1="12.00096" - y1="18.000015" + y1="17.203793" x2="12.00096" - y2="12.421011" - gradientTransform="matrix(1.318182,0,0,1.318182,-2.3895e-2,0.33147)" /> + y2="9.1482677" + gradientTransform="matrix(1.40375,0,0,1.403934,-1.668488,-1.296374)" /> + <radialGradient + r="8.6620579" + fy="19.008621" + fx="31.112698" + cy="19.008621" + cx="31.112698" + gradientUnits="userSpaceOnUse" + id="radialGradient2148" + xlink:href="#linearGradient2812" + inkscape:collect="always" /> + <linearGradient + y2="36.603138" + x2="24.240097" + y1="9.4211226" + x1="15.498499" + gradientTransform="matrix(0.466524,0,0,0.466525,38.65385,10.80199)" + gradientUnits="userSpaceOnUse" + id="linearGradient2146" + xlink:href="#linearGradient3149" + inkscape:collect="always" /> + <linearGradient + y2="21.045444" + x2="15.602553" + y1="1.5657365" + x1="15.602553" + gradientTransform="matrix(0.705322,0,0,0.705327,-58.76363,3.243275)" + gradientUnits="userSpaceOnUse" + id="linearGradient2132" + xlink:href="#linearGradient2239" + inkscape:collect="always" /> + <linearGradient + y2="36.603138" + x2="24.240097" + y1="9.4211226" + x1="15.498499" + gradientTransform="matrix(0.466524,0,0,0.466525,38.65385,10.80199)" + gradientUnits="userSpaceOnUse" + id="linearGradient2126" + xlink:href="#linearGradient3149" + inkscape:collect="always" /> + <linearGradient + inkscape:collect="always" + id="linearGradient5129"> + <stop + style="stop-color:white;stop-opacity:1;" + offset="0" + id="stop5131" /> + <stop + style="stop-color:white;stop-opacity:0;" + offset="1" + id="stop5133" /> + </linearGradient> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3150" + id="radialGradient2035" + cx="10.748654" + cy="10.457643" + fx="10.748654" + fy="10.457643" + r="6.6449099" + gradientTransform="matrix(-0.842757,0,0,-0.35721,19.80716,14.19321)" + gradientUnits="userSpaceOnUse" /> + <linearGradient + inkscape:collect="always" + id="linearGradient2239"> + <stop + style="stop-color:#ffffff;stop-opacity:1;" + offset="0" + id="stop2241" /> + <stop + style="stop-color:#ffffff;stop-opacity:0;" + offset="1" + id="stop2243" /> + </linearGradient> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient5129" + id="radialGradient5135" + cx="10.99079" + cy="5.3375292" + fx="10.99079" + fy="5.3375292" + r="5.7619157" + gradientTransform="matrix(1,0,0,0.493392,0,4.185903)" + gradientUnits="userSpaceOnUse" /> + <radialGradient + gradientUnits="userSpaceOnUse" + r="8.6620579" + fy="19.008621" + fx="31.112698" + cy="19.008621" + cx="31.112698" + id="radialGradient2068" + xlink:href="#linearGradient2812" + inkscape:collect="always" /> + <linearGradient + gradientUnits="userSpaceOnUse" + y2="11.024895" + x2="10.623409" + y1="2.7991772" + x1="4.5264969" + id="linearGradient2070" + xlink:href="#linearGradient2804" + inkscape:collect="always" /> + <linearGradient + gradientUnits="userSpaceOnUse" + y2="27.77807" + x2="12.233074" + y1="11.789385" + x1="6.878005" + id="linearGradient2072" + xlink:href="#linearGradient2851" + inkscape:collect="always" /> + <linearGradient + id="linearGradient2080"> + <stop + id="stop2082" + offset="0" + style="stop-color:#73d216;stop-opacity:1;" /> + <stop + id="stop2084" + offset="1" + style="stop-color:#5ca911;stop-opacity:1;" /> + </linearGradient> + <linearGradient + y2="40.032413" + x2="17.890068" + y1="8.0617304" + x1="17.890068" + gradientUnits="userSpaceOnUse" + id="linearGradient2086" + xlink:href="#linearGradient3149" + inkscape:collect="always" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2804" + id="linearGradient2100" + gradientUnits="userSpaceOnUse" + x1="4.5264969" + y1="2.7991772" + x2="10.623409" + y2="11.024895" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient2812" + id="radialGradient1985" + gradientUnits="userSpaceOnUse" + cx="31.112698" + cy="19.008621" + fx="31.112698" + fy="19.008621" + r="8.6620579" /> + <linearGradient + gradientTransform="matrix(0.999824,0,0,0.999281,2.209264e-4,5.644055e-4)" + gradientUnits="userSpaceOnUse" + y2="33.483475" + x2="15.522223" + y1="1.5657365" + x1="15.602553" + id="linearGradient2040" + xlink:href="#linearGradient2239" + inkscape:collect="always" /> + <radialGradient + gradientUnits="userSpaceOnUse" + r="8.6620579" + fy="19.008621" + fx="31.112698" + cy="19.008621" + cx="31.112698" + id="radialGradient2032" + xlink:href="#linearGradient3816" + inkscape:collect="always" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3816" + id="radialGradient2057" + gradientUnits="userSpaceOnUse" + cx="31.112698" + cy="19.008621" + fx="31.112698" + fy="19.008621" + r="8.6620579" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2239" + id="linearGradient2073" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.705322,0,0,0.705327,8.71963,7.710084)" + x1="15.602553" + y1="1.5657365" + x2="15.602553" + y2="21.045444" /> + <radialGradient + r="8.6620579" + fy="19.008621" + fx="31.112698" + cy="19.008621" + cx="31.112698" + gradientUnits="userSpaceOnUse" + id="radialGradient1992" + xlink:href="#linearGradient2812" + inkscape:collect="always" /> + <radialGradient + r="0.8078171" + fy="6.9473476" + fx="4.8470273" + cy="6.9473476" + cx="4.8470273" + gradientTransform="matrix(3.018423,0.664359,-1.388844,4.257661,-0.134567,-26.02469)" + gradientUnits="userSpaceOnUse" + id="radialGradient1990" + xlink:href="#linearGradient2898" + inkscape:collect="always" /> + <linearGradient + gradientTransform="matrix(1.076595,0,0,1.076595,-3.760351,-3.418494)" + y2="27.77807" + x2="12.233074" + y1="11.789385" + x1="6.878005" + gradientUnits="userSpaceOnUse" + id="linearGradient1986" + xlink:href="#linearGradient2851" + inkscape:collect="always" /> + <linearGradient + gradientTransform="matrix(1.004822,0,0,1.004822,-2.476351,-2.157242)" + y2="36.603138" + x2="24.240097" + y1="9.4211226" + x1="15.498499" + gradientUnits="userSpaceOnUse" + id="linearGradient1983" + xlink:href="#linearGradient3149" + inkscape:collect="always" /> + <linearGradient + inkscape:collect="always" + id="linearGradient2898"> + <stop + style="stop-color:white;stop-opacity:1;" + offset="0" + id="stop2900" /> + <stop + style="stop-color:white;stop-opacity:0;" + offset="1" + id="stop2902" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2851" + id="linearGradient4738" + gradientUnits="userSpaceOnUse" + x1="6.878005" + y1="11.789385" + x2="12.233074" + y2="27.77807" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3149" + id="linearGradient4740" + gradientUnits="userSpaceOnUse" + x1="15.498499" + y1="9.4211226" + x2="24.240097" + y2="36.603138" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3149" + id="linearGradient2269" + gradientUnits="userSpaceOnUse" + x1="17.890068" + y1="8.0617304" + x2="17.890068" + y2="40.032413" /> + <linearGradient + id="linearGradient1935"> + <stop + style="stop-color:#73d216;stop-opacity:1;" + offset="0" + id="stop1937" /> + <stop + style="stop-color:#5ca911;stop-opacity:1;" + offset="1" + id="stop1939" /> + </linearGradient> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3816" + id="radialGradient1953" + cx="31.112698" + cy="19.008621" + fx="31.112698" + fy="19.008621" + r="8.6620579" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.914124,-3.896132e-15,-2.475021e-18,1.631747,2.671799,-12.00863)" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2851" + id="linearGradient1955" + x1="6.878005" + y1="11.789385" + x2="12.233074" + y2="27.77807" + gradientUnits="userSpaceOnUse" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient2898" + id="radialGradient2904" + cx="4.8470273" + cy="6.9473476" + fx="4.8470273" + fy="6.9473476" + r="0.8078171" + gradientTransform="matrix(3.018423,0.664359,-1.388844,4.257661,-0.134567,-26.02469)" + gradientUnits="userSpaceOnUse" /> + <radialGradient + gradientUnits="userSpaceOnUse" + r="8.6620579" + fy="19.008621" + fx="31.112698" + cy="19.008621" + cx="31.112698" + id="radialGradient2818" + xlink:href="#linearGradient2812" + inkscape:collect="always" /> + <linearGradient + gradientUnits="userSpaceOnUse" + y2="11.024895" + x2="10.623409" + y1="2.7991772" + x1="4.5264969" + id="linearGradient2810" + xlink:href="#linearGradient2804" + inkscape:collect="always" /> + <linearGradient + gradientUnits="userSpaceOnUse" + y2="27.77807" + x2="12.233074" + y1="11.789385" + x1="6.878005" + id="linearGradient2963" + xlink:href="#linearGradient2851" + inkscape:collect="always" /> + <linearGradient + id="linearGradient2951"> + <stop + id="stop2953" + offset="0" + style="stop-color:#73d216;stop-opacity:1;" /> + <stop + id="stop2955" + offset="1" + style="stop-color:#5ca911;stop-opacity:1;" /> + </linearGradient> + <linearGradient + y2="40.032413" + x2="17.890068" + y1="8.0617304" + x1="17.890068" + gradientUnits="userSpaceOnUse" + id="linearGradient2949" + xlink:href="#linearGradient3149" + inkscape:collect="always" /> + <linearGradient + id="linearGradient2804" + inkscape:collect="always"> + <stop + id="stop2806" + offset="0" + style="stop-color:white;stop-opacity:1;" /> + <stop + id="stop2808" + offset="1" + style="stop-color:white;stop-opacity:0;" /> + </linearGradient> + <linearGradient + id="linearGradient2812" + inkscape:collect="always"> + <stop + id="stop2814" + offset="0" + style="stop-color:#2e3436;stop-opacity:1;" /> + <stop + id="stop2816" + offset="1" + style="stop-color:#2e3436;stop-opacity:0;" /> + </linearGradient> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient2812" + id="radialGradient3005" + gradientUnits="userSpaceOnUse" + cx="31.112698" + cy="19.008621" + fx="31.112698" + fy="19.008621" + r="8.6620579" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2804" + id="linearGradient3007" + gradientUnits="userSpaceOnUse" + x1="4.5264969" + y1="2.7991772" + x2="10.623409" + y2="11.024895" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient2812" + id="radialGradient3025" + gradientUnits="userSpaceOnUse" + cx="31.112698" + cy="19.008621" + fx="31.112698" + fy="19.008621" + r="8.6620579" /> + <linearGradient + gradientUnits="userSpaceOnUse" + y2="36.574547" + x2="17.890068" + y1="8.3091545" + x1="17.890068" + id="linearGradient3155" + xlink:href="#linearGradient3149" + inkscape:collect="always" /> + <radialGradient + gradientUnits="userSpaceOnUse" + r="8.6620579" + fy="19.008621" + fx="31.112698" + cy="19.008621" + cx="31.112698" + id="radialGradient1983" + xlink:href="#linearGradient3816" + inkscape:collect="always" /> + <linearGradient + id="linearGradient3149" + inkscape:collect="always"> + <stop + id="stop3151" + offset="0" + style="stop-color:#eeeeec;stop-opacity:1;" /> + <stop + id="stop3153" + offset="1" + style="stop-color:#eeeeec;stop-opacity:0;" /> + </linearGradient> + <linearGradient + id="linearGradient2851"> + <stop + id="stop2853" + offset="0" + style="stop-color:#73d216;stop-opacity:1;" /> + <stop + id="stop2855" + offset="1" + style="stop-color:#5ca911;stop-opacity:1;" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3149" + id="linearGradient2056" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1.004822,0,0,1.004822,-33.47635,-2.157242)" + x1="15.498499" + y1="9.4211226" + x2="24.240097" + y2="36.603138" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2851" + id="linearGradient2059" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1.076595,0,0,1.076595,-34.76035,-3.418494)" + x1="6.878005" + y1="11.789385" + x2="12.233074" + y2="27.77807" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient2812" + id="radialGradient2062" + gradientUnits="userSpaceOnUse" + cx="31.112698" + cy="19.008621" + fx="31.112698" + fy="19.008621" + r="8.6620579" /> </defs> <sodipodi:namedview id="base" @@ -119,16 +607,16 @@ inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="16.976026" - inkscape:cx="19.582303" - inkscape:cy="17.200313" + inkscape:cx="12.808044" + inkscape:cy="15.904368" inkscape:document-units="px" inkscape:current-layer="layer1" showgrid="true" fill="#888a85" - inkscape:window-width="1268" - inkscape:window-height="971" - inkscape:window-x="6" - inkscape:window-y="23" /> + inkscape:window-width="1440" + inkscape:window-height="849" + inkscape:window-x="0" + inkscape:window-y="0" /> <metadata id="metadata7"> <rdf:RDF> @@ -145,6 +633,16 @@ inkscape:groupmode="layer" id="layer1"> <path + transform="matrix(1.731691,0,0,0.461784,-37.87759,19.22212)" + sodipodi:type="arc" + style="color:black;fill:url(#radialGradient2062);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" + id="path2173" + sodipodi:cx="31.112698" + sodipodi:cy="19.008621" + sodipodi:rx="8.6620579" + sodipodi:ry="8.6620579" + d="M 39.774755 19.008621 A 8.6620579 8.6620579 0 1 1 22.45064,19.008621 A 8.6620579 8.6620579 0 1 1 39.774755 19.008621 z" /> + <path d="M 39.774755 19.008621 A 8.6620579 8.6620579 0 1 1 22.45064,19.008621 A 8.6620579 8.6620579 0 1 1 39.774755 19.008621 z" sodipodi:ry="8.6620579" sodipodi:rx="8.6620579" @@ -155,45 +653,26 @@ sodipodi:type="arc" transform="matrix(1.847136,0,0,0.865845,-41.46938,8.041481)" /> <path - sodipodi:type="arc" - style="opacity:1;fill:url(#radialGradient3156);fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="path3140" - sodipodi:cx="10.748654" - sodipodi:cy="10.457643" - sodipodi:rx="6.6449099" - sodipodi:ry="2.3675451" - d="M 17.393564 10.457643 A 6.6449099 2.3675451 0 1 1 4.1037445,10.457643 A 6.6449099 2.3675451 0 1 1 17.393564 10.457643 z" - transform="matrix(2.182121,0,0,1.391928,-7.954869,12.14827)" /> - <path - style="fill:#888a85;fill-opacity:1;stroke:#2e3436;stroke-width:0.99999875;stroke-miterlimit:4;stroke-opacity:1" - d="M 26.256921,26.256907 C 20.600315,31.913529 11.419537,31.914486 5.7641107,26.259045 C 0.10868503,20.603602 0.1096427,11.422797 5.7662484,5.7661742 C 11.422853,0.1095522 20.603631,0.10859439 26.259058,5.7640366 C 31.914483,11.419479 31.913526,20.600284 26.256921,26.256907 z " + style="fill:#888a85;fill-opacity:1;stroke:#2e3436;stroke-width:0.99999887;stroke-miterlimit:4;stroke-opacity:1" + d="M 26.107102,26.107103 C 20.250761,31.963443 10.74581,31.964434 4.8906904,26.109316 C -0.9644283,20.254196 -0.96343682,10.749245 4.8929036,4.8929035 C 10.749243,-0.96343684 20.254194,-0.96442847 26.109314,4.8906904 C 31.964432,10.74581 31.963442,20.250761 26.107102,26.107103 z " id="path2187" /> <path - sodipodi:type="inkscape:offset" - inkscape:radius="-1.0137641" - inkscape:original="M 16 1.53125 C 12.290802 1.5316369 8.6095524 2.9529389 5.78125 5.78125 C 0.1246443 11.437873 0.094574465 20.594557 5.75 26.25 C 11.405426 31.905441 20.593393 31.906622 26.25 26.25 C 31.906605 20.593377 31.905425 11.405442 26.25 5.75 C 23.422286 2.9222789 19.709198 1.5308631 16 1.53125 z " - xlink:href="#path2187" - style="opacity:0.4;fill:url(#linearGradient2231);fill-opacity:1;stroke:#ffffff;stroke-width:0.99999809;stroke-miterlimit:4;stroke-opacity:1" - id="path2215" - inkscape:href="#path2187" - d="M 16,2.53125 C 12.549705,2.5316099 9.1373736,3.8626287 6.5,6.5 C 1.2289233,11.771071 1.2014746,20.26398 6.46875,25.53125 C 11.736026,30.798519 20.262813,30.799682 25.53125,25.53125 C 30.799686,20.262819 30.798523,11.736019 25.53125,6.46875 C 22.89972,3.837224 19.4556,2.5308896 16,2.53125 z " /> + style="opacity:1;fill:#eeeeec;fill-opacity:1;stroke:none;stroke-width:1.00000036;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="M 20.92264,5.5294893 L 15.440071,10.599712 L 10.134222,5.2349563 L 5.3520274,10.017152 L 10.598969,15.440813 L 5.6452582,20.865777 L 9.8972946,25.942506 L 15.322258,20.340822 L 20.894813,25.442125 L 25.618102,21.013369 L 20.222267,15.49972 L 25.469209,10.252778 L 20.92264,5.5294893 z " + id="path2233" + sodipodi:nodetypes="ccccccccccccc" /> <path - style="opacity:1;fill:#eeeeec;fill-opacity:1;stroke:none;stroke-width:1.00000036;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - d="M 20.689058,7.0625004 L 15.795555,11.956003 L 10.902052,7.0625004 L 6.5911096,11.373443 L 11.484612,16.266945 L 6.7076214,21.043936 L 11.018564,25.354879 L 15.795555,20.577888 L 20.543417,25.325751 L 24.85436,21.014808 L 20.106498,16.266945 L 25,11.373443 L 20.689058,7.0625004 z " - id="path2233" /> + style="opacity:0.4;fill:url(#linearGradient2231);fill-opacity:1;stroke:white;stroke-width:0.99999809;stroke-miterlimit:4;stroke-opacity:1" + d="M 15.5,1.5 C 11.919821,1.5003735 8.3615884,2.8884111 5.625,5.625 C 0.15534426,11.094657 0.15654704,19.906546 5.625,25.375 C 11.093454,30.843452 19.905345,30.844655 25.375,25.375 C 30.844655,19.905343 30.843452,11.093454 25.375,5.625 C 22.638996,2.8889961 19.07979,1.4996266 15.5,1.5 z " + id="path2215" /> <path style="opacity:1;fill:url(#linearGradient2270);fill-opacity:1;stroke:#555753;stroke-width:1.00000036;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - d="M 20.999968,6.7515891 L 16.03118,11.543656 L 11.018644,6.7127252 L 6.7383758,11.020002 L 11.484612,16.031319 L 6.7076211,21.043936 L 11.018564,25.354879 L 16.028737,20.500159 L 20.97092,25.325751 L 25.242999,20.975944 L 20.534,16.033762 L 25.310911,11.101395 L 20.999968,6.7515891 z " + d="M 20.955744,5.3057668 L 15.428786,10.645198 L 10.208679,5.2643747 L 5.2971223,10.087479 L 10.587082,15.424797 L 5.3232778,20.999126 L 9.9729678,25.708323 L 15.426184,20.184349 L 20.92481,25.618393 L 25.650927,20.985618 L 20.223902,15.427399 L 25.723247,10.233074 L 20.955744,5.3057668 z " id="rect2204" sodipodi:nodetypes="ccccccccccccc" /> <path - sodipodi:type="inkscape:offset" - inkscape:radius="-1.0009557" - inkscape:original="M 11.03125 6.71875 L 6.75 11.03125 L 11.5 16.03125 L 6.71875 21.03125 L 11.03125 25.34375 L 16.03125 20.5 L 20.96875 25.3125 L 25.25 20.96875 L 20.53125 16.03125 L 25.3125 11.09375 L 21 6.75 L 16.03125 11.53125 L 11.03125 6.71875 z " - xlink:href="#rect2204" - style="opacity:1;fill:none;fill-opacity:1;stroke:#e1e1e1;stroke-width:1.00000036;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="path2268" - inkscape:href="#rect2204" - d="M 11.40625,8.5 L 8.53125,11.375 L 12.71875,15.5625 C 12.913242,15.751048 13.023019,16.010367 13.023019,16.28125 C 13.023019,16.552133 12.913242,16.811452 12.71875,17 L 8.65625,21.03125 L 11.53125,23.90625 L 15.5625,19.84375 C 15.751048,19.649258 16.010367,19.539481 16.28125,19.539481 C 16.552133,19.539481 16.811452,19.649258 17,19.84375 L 21.03125,23.875 L 23.90625,21 L 19.875,17 C 19.680508,16.811452 19.570731,16.552133 19.570731,16.28125 C 19.570731,16.010367 19.680508,15.751048 19.875,15.5625 L 24.0625,11.375 L 21.1875,8.5 L 17,12.6875 C 16.811452,12.881992 16.552133,12.991769 16.28125,12.991769 C 16.010367,12.991769 15.751048,12.881992 15.5625,12.6875 L 11.40625,8.5 z " /> + style="fill:none;fill-opacity:1;stroke:#e1e1e1;stroke-width:1.00000036;stroke-miterlimit:4;stroke-opacity:1" + d="M 10.21875,6.6875 L 6.75,10.09375 L 11.3125,14.71875 C 11.697174,15.10858 11.697174,15.73517 11.3125,16.125 L 6.6875,21 L 9.96875,24.28125 L 14.71875,19.46875 C 14.907298,19.274258 15.166617,19.164481 15.4375,19.164481 C 15.708383,19.164481 15.967702,19.274258 16.15625,19.46875 L 20.96875,24.21875 L 24.25,21 L 19.5,16.125 C 19.123854,15.726673 19.137781,15.099974 19.53125,14.71875 L 24.3125,10.1875 L 20.9375,6.71875 L 16.125,11.375 C 15.726673,11.751146 15.099974,11.737219 14.71875,11.34375 L 10.21875,6.6875 z " + id="path2268" /> </g> </svg>
--- a/pidgin/pixmaps/tray/16/Makefile.am Thu Jun 14 19:48:48 2007 +0000 +++ b/pidgin/pixmaps/tray/16/Makefile.am Mon Jun 18 01:48:35 2007 +0000 @@ -6,6 +6,7 @@ tray-connecting.png \ tray-extended-away.png \ tray-message.png \ + tray-new-im.png \ tray-offline.png \ tray-online.png
--- a/pidgin/pixmaps/tray/16/scalable/tray-away.svg Thu Jun 14 19:48:48 2007 +0000 +++ b/pidgin/pixmaps/tray/16/scalable/tray-away.svg Mon Jun 18 01:48:35 2007 +0000 @@ -14,7 +14,7 @@ id="svg1872" sodipodi:version="0.32" inkscape:version="0.44.1" - sodipodi:docbase="/home/hbons/Desktop" + sodipodi:docbase="/home/hbons/Desktop/experiment/tray/16/scalable" sodipodi:docname="tray-away.svg"> <defs id="defs1874"> @@ -549,37 +549,6 @@ offset="1" style="stop-color:#eeeeec;stop-opacity:0;" /> </linearGradient> - <radialGradient - inkscape:collect="always" - xlink:href="#linearGradient2781" - id="radialGradient3201" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(2,0,0,0.8,-13,-79.2)" - cx="1" - cy="44" - fx="1" - fy="44" - r="5" /> - <radialGradient - inkscape:collect="always" - xlink:href="#linearGradient2781" - id="radialGradient3203" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(2,0,0,0.8,36,8.8)" - cx="1" - cy="44" - fx="1" - fy="44" - r="5" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient2804" - id="linearGradient3205" - gradientUnits="userSpaceOnUse" - x1="21.875" - y1="48.000977" - x2="21.875" - y2="40" /> <linearGradient y2="14.895812" x2="11.802028" @@ -780,58 +749,297 @@ offset="1.0000000" style="stop-color:#e9e9e9;stop-opacity:1.0000000;" /> </linearGradient> - <radialGradient + <linearGradient inkscape:collect="always" - xlink:href="#linearGradient2781" - id="radialGradient3398" + xlink:href="#linearGradient3149" + id="linearGradient2046" gradientUnits="userSpaceOnUse" - gradientTransform="matrix(2,0,0,0.8,-13,-79.2)" - cx="1" - cy="44" - fx="1" - fy="44" - r="5" /> - <radialGradient + x1="17.890068" + y1="8.0617304" + x2="17.890068" + y2="40.032413" /> + <linearGradient + id="linearGradient2048"> + <stop + style="stop-color:#73d216;stop-opacity:1;" + offset="0" + id="stop2050" /> + <stop + style="stop-color:#5ca911;stop-opacity:1;" + offset="1" + id="stop2052" /> + </linearGradient> + <linearGradient inkscape:collect="always" - xlink:href="#linearGradient2781" - id="radialGradient3400" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(2,0,0,0.8,36,8.8)" - cx="1" - cy="44" - fx="1" - fy="44" - r="5" /> + xlink:href="#linearGradient2851" + id="linearGradient2060" + x1="6.878005" + y1="11.789385" + x2="12.233074" + y2="27.77807" + gradientUnits="userSpaceOnUse" /> <linearGradient inkscape:collect="always" xlink:href="#linearGradient2804" - id="linearGradient3402" - gradientUnits="userSpaceOnUse" - x1="21.875" - y1="48.000977" - x2="21.875" - y2="40" /> + id="linearGradient2062" + x1="4.5264969" + y1="2.7991772" + x2="10.623409" + y2="11.024895" + gradientUnits="userSpaceOnUse" /> <radialGradient inkscape:collect="always" - xlink:href="#linearGradient2260" - id="radialGradient3404" + xlink:href="#linearGradient2812" + id="radialGradient2064" + cx="31.112698" + cy="19.008621" + fx="31.112698" + fy="19.008621" + r="8.6620579" + gradientUnits="userSpaceOnUse" /> + <linearGradient + inkscape:collect="always" + id="linearGradient2812"> + <stop + style="stop-color:#2e3436;stop-opacity:1;" + offset="0" + id="stop2814" /> + <stop + style="stop-color:#2e3436;stop-opacity:0;" + offset="1" + id="stop2816" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3149" + id="linearGradient2269" + gradientUnits="userSpaceOnUse" + x1="17.890068" + y1="8.0617304" + x2="17.890068" + y2="40.032413" /> + <linearGradient + id="linearGradient2177"> + <stop + style="stop-color:#73d216;stop-opacity:1;" + offset="0" + id="stop2179" /> + <stop + style="stop-color:#5ca911;stop-opacity:1;" + offset="1" + id="stop2181" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient3149"> + <stop + style="stop-color:#eeeeec;stop-opacity:1;" + offset="0" + id="stop3151" /> + <stop + style="stop-color:#eeeeec;stop-opacity:0;" + offset="1" + id="stop3153" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2851" + id="linearGradient2857" + x1="6.878005" + y1="11.789385" + x2="12.233074" + y2="27.77807" + gradientUnits="userSpaceOnUse" /> + <linearGradient + y2="14.895812" + x2="11.802028" + y1="1.9986149" + x1="11.802028" + gradientUnits="userSpaceOnUse" + id="linearGradient6606" + xlink:href="#linearGradient2225" + inkscape:collect="always" /> + <linearGradient + y2="48.674999" + x2="15.535398" + y1="1.8014067" + x1="15.535398" + gradientTransform="matrix(0.37378,0,0,0.375227,17.64779,15.86312)" + gradientUnits="userSpaceOnUse" + id="linearGradient2170" + xlink:href="#linearGradient2239" + inkscape:collect="always" /> + <linearGradient + y2="17.697369" + x2="11.226587" + y1="-5.4832759" + x1="11.226587" + gradientTransform="matrix(0.529942,0,0,0.53199,17.26643,15.48536)" + gradientUnits="userSpaceOnUse" + id="linearGradient2168" + xlink:href="#linearGradient2186" + inkscape:collect="always" /> + <linearGradient + y2="33.483475" + x2="15.522223" + y1="1.5657365" + x1="15.602553" + gradientTransform="matrix(0.371983,0,0,0.372254,2.539836,8.539528)" + gradientUnits="userSpaceOnUse" + id="linearGradient1357" + xlink:href="#linearGradient2239" + inkscape:collect="always" /> + <radialGradient gradientUnits="userSpaceOnUse" gradientTransform="matrix(1,0,0,0.626667,0,6.566431)" - cx="11.756953" - cy="17.588654" + r="6.3436799" + fy="17.588654" fx="11.756953" - fy="17.588654" - r="6.3436799" /> + cy="17.588654" + cx="11.756953" + id="radialGradient2266" + xlink:href="#linearGradient2260" + inkscape:collect="always" /> + <radialGradient + r="7.0034069" + fy="8.963316" + fx="9.9988937" + cy="8.963316" + cx="9.9988937" + gradientTransform="matrix(-2.522332,-1.518129e-16,-1.517788e-16,2.521765,40.1904,-21.80154)" + gradientUnits="userSpaceOnUse" + id="radialGradient2158" + xlink:href="#linearGradient2200" + inkscape:collect="always" /> + <radialGradient + r="7.0034069" + fy="8.963316" + fx="9.9988937" + cy="8.963316" + cx="9.9988937" + gradientTransform="matrix(-2.522332,-1.518129e-16,-1.517788e-16,2.521765,40.1904,-21.83521)" + gradientUnits="userSpaceOnUse" + id="radialGradient2156" + xlink:href="#linearGradient2200" + inkscape:collect="always" /> + <radialGradient + gradientUnits="userSpaceOnUse" + r="8.6620579" + fy="19.008621" + fx="31.112698" + cy="19.008621" + cx="31.112698" + id="radialGradient2148" + xlink:href="#linearGradient3816" + inkscape:collect="always" /> + <linearGradient + gradientTransform="matrix(0.529942,0,0,0.53199,17.26643,15.48536)" + gradientUnits="userSpaceOnUse" + y2="17.697369" + x2="11.226587" + y1="-5.4832759" + x1="11.226587" + id="linearGradient2134" + xlink:href="#linearGradient2186" + inkscape:collect="always" /> + <linearGradient + gradientTransform="matrix(0.37378,0,0,0.375227,17.64779,15.86312)" + gradientUnits="userSpaceOnUse" + y2="48.674999" + x2="15.535398" + y1="1.8014067" + x1="15.535398" + id="linearGradient2126" + xlink:href="#linearGradient2239" + inkscape:collect="always" /> + <radialGradient + r="5" + fy="44" + fx="1" + cy="44" + cx="1" + gradientTransform="matrix(2,0,0,0.8,-13,-79.2)" + gradientUnits="userSpaceOnUse" + id="radialGradient2124" + xlink:href="#linearGradient2781" + inkscape:collect="always" /> + <radialGradient + r="5" + fy="44" + fx="1" + cy="44" + cx="1" + gradientTransform="matrix(2,0,0,0.8,36,8.8)" + gradientUnits="userSpaceOnUse" + id="radialGradient2116" + xlink:href="#linearGradient2781" + inkscape:collect="always" /> + <linearGradient + y2="40" + x2="21.875" + y1="48.000977" + x1="21.875" + gradientUnits="userSpaceOnUse" + id="linearGradient2114" + xlink:href="#linearGradient2804" + inkscape:collect="always" /> + <linearGradient + id="linearGradient2106"> + <stop + id="stop2108" + offset="0" + style="stop-color:black;stop-opacity:0;" /> + <stop + style="stop-color:black;stop-opacity:1;" + offset="0.5" + id="stop2110" /> + <stop + id="stop2112" + offset="1" + style="stop-color:black;stop-opacity:0;" /> + </linearGradient> + <linearGradient + y2="24.143761" + x2="27.273300" + y1="10.957423" + x1="35.003674" + gradientTransform="matrix(-0.977228,0,0,0.995878,50.60272,9.115637)" + gradientUnits="userSpaceOnUse" + id="linearGradient2104" + xlink:href="#linearGradient29418" + inkscape:collect="always" /> + <linearGradient + id="linearGradient2098"> + <stop + id="stop2100" + offset="0.0000000" + style="stop-color:#f5f5f5;stop-opacity:1.0000000;" /> + <stop + id="stop2102" + offset="1.0000000" + style="stop-color:#e9e9e9;stop-opacity:1.0000000;" /> + </linearGradient> + <linearGradient + id="linearGradient2989" + inkscape:collect="always"> + <stop + id="stop2991" + offset="0" + style="stop-color:#eeeeec;stop-opacity:1;" /> + <stop + id="stop2993" + offset="1" + style="stop-color:#eeeeec;stop-opacity:0;" /> + </linearGradient> <linearGradient inkscape:collect="always" - xlink:href="#linearGradient2239" - id="linearGradient3409" + xlink:href="#linearGradient2989" + id="linearGradient2232" gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.296524,0,0,0.296522,5.75564,5.75564)" - x1="15.602553" - y1="1.5657365" - x2="15.522223" - y2="33.483475" /> + x1="1.5769236" + y1="1.3319674" + x2="10.043059" + y2="10.018044" /> </defs> <sodipodi:namedview id="base" @@ -840,15 +1048,15 @@ borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="22.197802" - inkscape:cx="15.940485" - inkscape:cy="11.44958" + inkscape:zoom="44.395604" + inkscape:cx="14.075416" + inkscape:cy="6.2074085" inkscape:current-layer="layer1" showgrid="true" inkscape:grid-bbox="true" inkscape:document-units="px" inkscape:window-width="1440" - inkscape:window-height="853" + inkscape:window-height="849" inkscape:window-x="0" inkscape:window-y="0" /> <metadata @@ -903,90 +1111,6 @@ d="M 9.2045414,1.5000001 C 9.3816286,1.5000001 9.4999957,1.6028844 9.4999957,1.7987807 L 9.4999957,7.3475646 C 9.4999957,7.543461 9.3816293,7.6463453 9.2045414,7.6463453 L 4.9999978,8.3220879 C 4.8242182,8.3232475 4.6547723,8.3838621 4.5227251,8.4928197 L 3.7045437,9.175747 L 3.7045437,9.0050151 C 3.7025982,8.6286041 3.3781242,8.3239148 2.9772712,8.3220879 L 1.7954537,7.6463453 C 1.6183665,7.6463453 1.4999993,7.5434596 1.4999993,7.3475646 L 1.4999993,1.7987807 C 1.4999993,1.6028846 1.6183665,1.5000001 1.7954537,1.5000001 L 9.2045414,1.5000001 z " id="path5807" sodipodi:nodetypes="cccccccccccccc" /> - <g - id="g3183" - style="opacity:0.3" - transform="matrix(-0.340425,0,0,0.625,-11.6596,-23.99648)"> - <rect - transform="scale(-1,-1)" - y="-48" - x="-11" - height="8" - width="10" - id="rect3185" - style="opacity:1;color:black;fill:url(#radialGradient3201);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" /> - <rect - y="40" - x="38" - height="8" - width="10" - id="rect3187" - style="opacity:1;color:black;fill:url(#radialGradient3203);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" /> - <rect - y="40" - x="11" - height="8" - width="27" - id="rect3189" - style="opacity:1;color:black;fill:url(#linearGradient3205);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" /> - </g> - <path - style="fill:#efefef;fill-opacity:1;fill-rule:evenodd;stroke:#787878;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - d="M -14.90628,-7.496478 C -14.122201,-7.496478 -13.50003,-6.8637163 -13.50003,-6.058978 L -13.50003,2.066022 C -13.50003,2.87076 -14.1222,3.503522 -14.90628,3.503522 L -20.68753,3.503522 L -23.46878,5.941022 L -23.46878,3.503522 L -25.09378,3.503522 C -25.877859,3.503522 -26.500031,2.87076 -26.50003,2.066022 L -26.50003,-6.058978 C -26.50003,-6.8637163 -25.877859,-7.496478 -25.09378,-7.496478 L -14.90628,-7.496478 z " - id="path3192" - sodipodi:nodetypes="cccccccccccc" /> - <path - sodipodi:type="inkscape:offset" - inkscape:radius="-1.0047876" - inkscape:original="M 1.59375 0.5 C 0.990612 0.5 0.49999997 1.0124794 0.5 1.65625 L 0.5 8.34375 C 0.49999924 8.9875204 0.99061204 9.46875 1.59375 9.46875 L 2.46875 9.46875 L 2.46875 11.4375 L 5.25 9.46875 L 9.40625 9.46875 C 10.009388 9.46875 10.5 8.9875205 10.5 8.34375 L 10.5 1.65625 C 10.5 1.0124794 10.009387 0.50000001 9.40625 0.5 L 1.59375 0.5 z " - xlink:href="#path2221" - style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:white;stroke-width:1.19785893;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="path3194" - inkscape:href="#path2221" - d="M 1.59375,1.5 C 1.5597829,1.5 1.5,1.5229727 1.5,1.65625 L 1.5,8.34375 C 1.4999998,8.4770255 1.5250763,8.46875 1.59375,8.46875 L 2.46875,8.46875 C 3.0199231,8.4714246 3.4660754,8.9175769 3.46875,9.46875 L 3.46875,9.5 L 4.65625,8.65625 C 4.8293233,8.532463 5.0372235,8.4668103 5.25,8.46875 L 9.40625,8.46875 C 9.4749239,8.46875 9.5,8.4770272 9.5,8.34375 L 9.5,1.65625 C 9.5,1.5229737 9.4402151,1.5 9.40625,1.5 L 1.59375,1.5 z " - transform="matrix(-0.834823,0,0,0.834823,13.43129,5.899303)" /> - <g - id="g3378" - style="opacity:0.3" - transform="matrix(-0.340425,0,0,0.625,-6.6596,-33.99648)"> - <rect - transform="scale(-1,-1)" - y="-48" - x="-11" - height="8" - width="10" - id="rect3380" - style="opacity:1;color:black;fill:url(#radialGradient3398);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" /> - <rect - y="40" - x="38" - height="8" - width="10" - id="rect3382" - style="opacity:1;color:black;fill:url(#radialGradient3400);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" /> - <rect - y="40" - x="11" - height="8" - width="27" - id="rect3384" - style="opacity:1;color:black;fill:url(#linearGradient3402);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" /> - </g> - <path - sodipodi:type="arc" - style="fill:url(#radialGradient3404);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.81530744;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="path2234" - sodipodi:cx="11.756953" - sodipodi:cy="17.588654" - sodipodi:rx="6.3436799" - sodipodi:ry="3.9753728" - d="M 18.100633 17.588654 A 6.3436799 3.9753728 0 1 1 5.4132733,17.588654 A 6.3436799 3.9753728 0 1 1 18.100633 17.588654 z" - transform="matrix(-1.024642,0,0,0.754646,3.54664,-13.27321)" /> - <path - style="fill:#efefef;fill-opacity:1;fill-rule:evenodd;stroke:#787878;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - d="M -9.90628,-17.49648 C -9.1222007,-17.49648 -8.5000301,-16.863718 -8.50003,-16.05898 L -8.50003,-7.93398 C -8.50003,-7.129242 -9.1222003,-6.49648 -9.90628,-6.49648 L -15.68753,-6.49648 L -18.46878,-4.05898 L -18.46878,-6.49648 L -20.09378,-6.49648 C -20.877859,-6.49648 -21.500031,-7.129242 -21.50003,-7.93398 L -21.50003,-16.05898 C -21.50003,-16.863718 -20.877859,-17.49648 -20.09378,-17.49648 L -9.90628,-17.49648 z " - id="path3387" - sodipodi:nodetypes="cccccccccccc" /> <path sodipodi:type="inkscape:offset" inkscape:radius="-1.0047876" @@ -998,47 +1122,89 @@ d="M 1.59375,1.5 C 1.5597829,1.5 1.5,1.5229727 1.5,1.65625 L 1.5,8.34375 C 1.4999998,8.4770255 1.5250763,8.46875 1.59375,8.46875 L 2.46875,8.46875 C 3.0199231,8.4714246 3.4660754,8.9175769 3.46875,9.46875 L 3.46875,9.5 L 4.65625,8.65625 C 4.8293233,8.532463 5.0372235,8.4668103 5.25,8.46875 L 9.40625,8.46875 C 9.4749239,8.46875 9.5,8.4770272 9.5,8.34375 L 9.5,1.65625 C 9.5,1.5229737 9.4402151,1.5 9.40625,1.5 L 1.59375,1.5 z " transform="matrix(-1,0,0,1,-3e-5,-19.99648)" /> <path - sodipodi:type="arc" - style="color:black;fill:#729fcf;fill-opacity:1;fill-rule:evenodd;stroke:#204a87;stroke-width:2.86901665px;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - id="path1339" - sodipodi:cx="15.590227" - sodipodi:cy="16.57217" - sodipodi:rx="14.345175" - sodipodi:ry="14.345175" - d="M 29.935402 16.57217 A 14.345175 14.345175 0 1 1 1.2450523,16.57217 A 14.345175 14.345175 0 1 1 29.935402 16.57217 z" - transform="matrix(0.348549,0,0,0.348549,5.066035,4.723779)" /> + style="fill:#efefef;fill-opacity:1;fill-rule:evenodd;stroke:#787878;stroke-width:0.99999994;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="M 33.877402,-6.5000005 C 34.782108,-6.5000005 35.499998,-5.7936619 35.499998,-4.8953494 L 35.499998,4.174417 C 35.499998,5.07273 34.78211,5.491987 33.877402,5.491987 L 27.20673,5.491987 L 23.519125,8.212917 L 23.519125,5.491987 L 22.122596,5.491987 C 21.217889,5.491987 20.499999,5.07273 20.5,4.174417 L 20.5,-4.8953494 C 20.5,-5.7936619 21.217889,-6.5000005 22.122596,-6.5000005 L 33.877402,-6.5000005 z " + id="path2198" + sodipodi:nodetypes="cccccccccccc" /> + <path + sodipodi:type="inkscape:offset" + inkscape:radius="-1.0047876" + inkscape:original="M 1.59375 0.5 C 0.990612 0.5 0.49999997 1.0124794 0.5 1.65625 L 0.5 8.34375 C 0.49999924 8.9875204 0.99061204 9.46875 1.59375 9.46875 L 2.46875 9.46875 L 2.46875 11.4375 L 5.25 9.46875 L 9.40625 9.46875 C 10.009388 9.46875 10.5 8.9875205 10.5 8.34375 L 10.5 1.65625 C 10.5 1.0124794 10.009387 0.50000001 9.40625 0.5 L 1.59375 0.5 z " + xlink:href="#path2221" + style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:white;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="path2200" + inkscape:href="#path2221" + d="M 1.59375,1.5 C 1.5597829,1.5 1.5,1.5229727 1.5,1.65625 L 1.5,8.34375 C 1.4999998,8.4770255 1.5250763,8.46875 1.59375,8.46875 L 2.46875,8.46875 C 3.0199231,8.4714246 3.4660754,8.9175769 3.46875,9.46875 L 3.46875,9.5 L 4.65625,8.65625 C 4.8293233,8.532463 5.0372235,8.4668103 5.25,8.46875 L 9.40625,8.46875 C 9.4749239,8.46875 9.5,8.4770272 9.5,8.34375 L 9.5,1.65625 C 9.5,1.5229737 9.4402151,1.5 9.40625,1.5 L 1.59375,1.5 z " + transform="translate(19,-8)" /> <path sodipodi:type="arc" - style="color:black;fill:#eeeeec;fill-opacity:1;fill-rule:evenodd;stroke:#204a87;stroke-width:4.78170681px;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - id="path1341" + style="color:black;fill:#729fcf;fill-opacity:1;fill-rule:evenodd;stroke:#173867;stroke-width:2.86902547px;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" + id="path2069" sodipodi:cx="15.590227" sodipodi:cy="16.57217" sodipodi:rx="14.345175" sodipodi:ry="14.345175" d="M 29.935402 16.57217 A 14.345175 14.345175 0 1 1 1.2450523,16.57217 A 14.345175 14.345175 0 1 1 29.935402 16.57217 z" - transform="matrix(0.20913,0,0,0.20913,7.239621,7.034267)" /> + transform="matrix(0.348549,0,0,0.348549,5.066037,4.723781)" /> + <path + sodipodi:type="arc" + style="fill:#8ab0d7;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="path2788" + sodipodi:cx="-3.8088531" + sodipodi:cy="3.303823" + sodipodi:rx="3.1932809" + sodipodi:ry="3.3471739" + d="M -0.61557221 3.303823 A 3.1932809 3.3471739 0 1 1 -7.0021341,3.303823 A 3.1932809 3.3471739 0 1 1 -0.61557221 3.303823 z" + transform="matrix(1.409209,0,0,1.344418,15.86747,6.058282)" /> <path - style="opacity:0.5;color:black;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient3409);stroke-width:0.99999952px;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - d="M 14.5,10.500004 C 14.5,12.708004 12.708,14.500005 10.499999,14.500005 C 8.2920005,14.500005 6.4999997,12.708004 6.4999997,10.500004 C 6.4999997,8.2920009 8.2920005,6.4999998 10.499999,6.4999998 C 12.708,6.4999998 14.5,8.2920009 14.5,10.500004 z " - id="path2220" /> + sodipodi:type="arc" + style="fill:#dcdcd8;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="path2796" + sodipodi:cx="6.0403023" + sodipodi:cy="7.5551186" + sodipodi:rx="1.615877" + sodipodi:ry="1.3273276" + d="M 7.6561793 7.5551186 A 1.615877 1.3273276 0 1 1 4.4244252,7.5551186 A 1.615877 1.3273276 0 1 1 7.6561793 7.5551186 z" + transform="matrix(2.784865,0,0,3.390272,-6.321424,-15.11391)" /> <rect - style="fill:#2e3436;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none" - id="rect3421" + style="fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="rect2832" width="1" - height="3" + height="1" x="10" - y="8" - rx="0.5" - ry="0.5" /> + y="-11" + transform="matrix(0,1,-1,0,0,0)" /> <rect - style="fill:#2e3436;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none" - id="rect3423" + style="fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="rect2236" + width="1" + height="1" + x="9" + y="-12" + transform="matrix(0,1,-1,0,0,0)" /> + <rect + style="fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="rect2240" width="1" - height="3" - x="10" + height="1" + x="11" + y="-12" + transform="matrix(0,1,-1,0,0,0)" /> + <rect + style="fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="rect3133" + width="1" + height="1" + x="8" y="-13" - transform="matrix(0,1,-1,0,0,0)" - rx="0.5" - ry="0.5" /> + transform="matrix(0,1,-1,0,0,0)" /> + <rect + style="fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="rect3135" + width="1" + height="1" + x="12" + y="-13" + transform="matrix(0,1,-1,0,0,0)" /> </g> </svg>
--- a/pidgin/pixmaps/tray/16/scalable/tray-online.svg Thu Jun 14 19:48:48 2007 +0000 +++ b/pidgin/pixmaps/tray/16/scalable/tray-online.svg Mon Jun 18 01:48:35 2007 +0000 @@ -14,7 +14,7 @@ id="svg1872" sodipodi:version="0.32" inkscape:version="0.44.1" - sodipodi:docbase="/home/hbons/Desktop" + sodipodi:docbase="/home/hbons/Desktop/experiment/tray/16/scalable" sodipodi:docname="tray-online.svg"> <defs id="defs1874"> @@ -150,6 +150,573 @@ y1="48.000977" x2="21.875" y2="40" /> + <linearGradient + inkscape:collect="always" + id="linearGradient2898"> + <stop + style="stop-color:white;stop-opacity:1;" + offset="0" + id="stop2900" /> + <stop + style="stop-color:white;stop-opacity:0;" + offset="1" + id="stop2902" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2851" + id="linearGradient4738" + gradientUnits="userSpaceOnUse" + x1="6.878005" + y1="11.789385" + x2="12.233074" + y2="27.77807" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3149" + id="linearGradient4740" + gradientUnits="userSpaceOnUse" + x1="15.498499" + y1="9.4211226" + x2="24.240097" + y2="36.603138" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3149" + id="linearGradient3044" + gradientUnits="userSpaceOnUse" + x1="17.890068" + y1="8.0617304" + x2="17.890068" + y2="40.032413" /> + <linearGradient + id="linearGradient3046"> + <stop + style="stop-color:#73d216;stop-opacity:1;" + offset="0" + id="stop3048" /> + <stop + style="stop-color:#5ca911;stop-opacity:1;" + offset="1" + id="stop3050" /> + </linearGradient> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3816" + id="radialGradient3064" + cx="31.112698" + cy="19.008621" + fx="31.112698" + fy="19.008621" + r="8.6620579" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.914124,-3.896132e-15,-2.475021e-18,1.631747,2.671799,-12.00863)" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2851" + id="linearGradient3066" + x1="6.878005" + y1="11.789385" + x2="12.233074" + y2="27.77807" + gradientUnits="userSpaceOnUse" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient2898" + id="radialGradient2904" + cx="4.8470273" + cy="6.9473476" + fx="4.8470273" + fy="6.9473476" + r="0.8078171" + gradientTransform="matrix(3.018423,0.664359,-1.388844,4.257661,-0.134567,-26.02469)" + gradientUnits="userSpaceOnUse" /> + <radialGradient + gradientUnits="userSpaceOnUse" + r="8.6620579" + fy="19.008621" + fx="31.112698" + cy="19.008621" + cx="31.112698" + id="radialGradient2818" + xlink:href="#linearGradient2812" + inkscape:collect="always" /> + <linearGradient + gradientUnits="userSpaceOnUse" + y2="11.024895" + x2="10.623409" + y1="2.7991772" + x1="4.5264969" + id="linearGradient2810" + xlink:href="#linearGradient2804" + inkscape:collect="always" /> + <linearGradient + gradientUnits="userSpaceOnUse" + y2="27.77807" + x2="12.233074" + y1="11.789385" + x1="6.878005" + id="linearGradient2963" + xlink:href="#linearGradient2851" + inkscape:collect="always" /> + <linearGradient + id="linearGradient2951"> + <stop + id="stop2953" + offset="0" + style="stop-color:#73d216;stop-opacity:1;" /> + <stop + id="stop2955" + offset="1" + style="stop-color:#5ca911;stop-opacity:1;" /> + </linearGradient> + <linearGradient + y2="40.032413" + x2="17.890068" + y1="8.0617304" + x1="17.890068" + gradientUnits="userSpaceOnUse" + id="linearGradient2949" + xlink:href="#linearGradient3149" + inkscape:collect="always" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient2812" + id="radialGradient3005" + gradientUnits="userSpaceOnUse" + cx="31.112698" + cy="19.008621" + fx="31.112698" + fy="19.008621" + r="8.6620579" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2804" + id="linearGradient3007" + gradientUnits="userSpaceOnUse" + x1="4.5264969" + y1="2.7991772" + x2="10.623409" + y2="11.024895" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient2812" + id="radialGradient3025" + gradientUnits="userSpaceOnUse" + cx="31.112698" + cy="19.008621" + fx="31.112698" + fy="19.008621" + r="8.6620579" /> + <linearGradient + gradientUnits="userSpaceOnUse" + y2="10.018044" + x2="10.043059" + y1="1.3319674" + x1="1.5769236" + id="linearGradient2995" + xlink:href="#linearGradient2989" + inkscape:collect="always" /> + <radialGradient + r="8.6620579" + fy="19.008621" + fx="31.112698" + cy="19.008621" + cx="31.112698" + gradientUnits="userSpaceOnUse" + id="radialGradient2084" + xlink:href="#linearGradient2812" + inkscape:collect="always" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3149" + id="linearGradient2046" + gradientUnits="userSpaceOnUse" + x1="17.890068" + y1="8.0617304" + x2="17.890068" + y2="40.032413" /> + <linearGradient + id="linearGradient2048"> + <stop + style="stop-color:#73d216;stop-opacity:1;" + offset="0" + id="stop2050" /> + <stop + style="stop-color:#5ca911;stop-opacity:1;" + offset="1" + id="stop2052" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2851" + id="linearGradient2060" + x1="6.878005" + y1="11.789385" + x2="12.233074" + y2="27.77807" + gradientUnits="userSpaceOnUse" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2804" + id="linearGradient2062" + x1="4.5264969" + y1="2.7991772" + x2="10.623409" + y2="11.024895" + gradientUnits="userSpaceOnUse" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient2812" + id="radialGradient2064" + cx="31.112698" + cy="19.008621" + fx="31.112698" + fy="19.008621" + r="8.6620579" + gradientUnits="userSpaceOnUse" /> + <linearGradient + inkscape:collect="always" + id="linearGradient2812"> + <stop + style="stop-color:#2e3436;stop-opacity:1;" + offset="0" + id="stop2814" /> + <stop + style="stop-color:#2e3436;stop-opacity:0;" + offset="1" + id="stop2816" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3149" + id="linearGradient2269" + gradientUnits="userSpaceOnUse" + x1="17.890068" + y1="8.0617304" + x2="17.890068" + y2="40.032413" /> + <linearGradient + id="linearGradient2055"> + <stop + style="stop-color:#73d216;stop-opacity:1;" + offset="0" + id="stop2057" /> + <stop + style="stop-color:#5ca911;stop-opacity:1;" + offset="1" + id="stop2059" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2851" + id="linearGradient2857" + x1="6.878005" + y1="11.789385" + x2="12.233074" + y2="27.77807" + gradientUnits="userSpaceOnUse" /> + <linearGradient + y2="14.895812" + x2="11.802028" + y1="1.9986149" + x1="11.802028" + gradientUnits="userSpaceOnUse" + id="linearGradient6606" + xlink:href="#linearGradient2225" + inkscape:collect="always" /> + <linearGradient + y2="48.674999" + x2="15.535398" + y1="1.8014067" + x1="15.535398" + gradientTransform="matrix(0.37378,0,0,0.375227,17.64779,15.86312)" + gradientUnits="userSpaceOnUse" + id="linearGradient2339" + xlink:href="#linearGradient2239" + inkscape:collect="always" /> + <linearGradient + y2="17.697369" + x2="11.226587" + y1="-5.4832759" + x1="11.226587" + gradientTransform="matrix(0.529942,0,0,0.53199,17.26643,15.48536)" + gradientUnits="userSpaceOnUse" + id="linearGradient2337" + xlink:href="#linearGradient2186" + inkscape:collect="always" /> + <linearGradient + y2="33.483475" + x2="15.522223" + y1="1.5657365" + x1="15.602553" + gradientTransform="matrix(0.371983,0,0,0.372254,2.539836,8.539528)" + gradientUnits="userSpaceOnUse" + id="linearGradient1357" + xlink:href="#linearGradient2239" + inkscape:collect="always" /> + <linearGradient + inkscape:collect="always" + id="linearGradient2239"> + <stop + style="stop-color:#ffffff;stop-opacity:1;" + offset="0" + id="stop2241" /> + <stop + style="stop-color:#ffffff;stop-opacity:0;" + offset="1" + id="stop2243" /> + </linearGradient> + <radialGradient + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1,0,0,0.626667,0,6.566431)" + r="6.3436799" + fy="17.588654" + fx="11.756953" + cy="17.588654" + cx="11.756953" + id="radialGradient2266" + xlink:href="#linearGradient2260" + inkscape:collect="always" /> + <radialGradient + r="7.0034069" + fy="8.963316" + fx="9.9988937" + cy="8.963316" + cx="9.9988937" + gradientTransform="matrix(-2.522332,-1.518129e-16,-1.517788e-16,2.521765,40.1904,-21.80154)" + gradientUnits="userSpaceOnUse" + id="radialGradient2225" + xlink:href="#linearGradient2200" + inkscape:collect="always" /> + <radialGradient + r="7.0034069" + fy="8.963316" + fx="9.9988937" + cy="8.963316" + cx="9.9988937" + gradientTransform="matrix(-2.522332,-1.518129e-16,-1.517788e-16,2.521765,40.1904,-21.83521)" + gradientUnits="userSpaceOnUse" + id="radialGradient2216" + xlink:href="#linearGradient2200" + inkscape:collect="always" /> + <linearGradient + id="linearGradient2200" + inkscape:collect="always"> + <stop + id="stop2202" + offset="0" + style="stop-color:#d3d7cf;stop-opacity:1;" /> + <stop + id="stop2204" + offset="1" + style="stop-color:#d3d7cf;stop-opacity:0;" /> + </linearGradient> + <radialGradient + gradientUnits="userSpaceOnUse" + r="8.6620579" + fy="19.008621" + fx="31.112698" + cy="19.008621" + cx="31.112698" + id="radialGradient3822" + xlink:href="#linearGradient3816" + inkscape:collect="always" /> + <linearGradient + id="linearGradient3816" + inkscape:collect="always"> + <stop + id="stop3818" + offset="0" + style="stop-color:#000000;stop-opacity:1;" /> + <stop + id="stop3820" + offset="1" + style="stop-color:#000000;stop-opacity:0;" /> + </linearGradient> + <linearGradient + id="linearGradient2260" + inkscape:collect="always"> + <stop + id="stop2262" + offset="0" + style="stop-color:#555753;stop-opacity:1;" /> + <stop + id="stop2264" + offset="1" + style="stop-color:#555753;stop-opacity:0;" /> + </linearGradient> + <linearGradient + gradientTransform="matrix(0.529942,0,0,0.53199,17.26643,15.48536)" + gradientUnits="userSpaceOnUse" + y2="17.697369" + x2="11.226587" + y1="-5.4832759" + x1="11.226587" + id="linearGradient2194" + xlink:href="#linearGradient2186" + inkscape:collect="always" /> + <linearGradient + id="linearGradient2186" + inkscape:collect="always"> + <stop + id="stop2188" + offset="0" + style="stop-color:#ffffff;stop-opacity:1;" /> + <stop + id="stop2190" + offset="1" + style="stop-color:#ffffff;stop-opacity:0;" /> + </linearGradient> + <linearGradient + gradientTransform="matrix(0.37378,0,0,0.375227,17.64779,15.86312)" + gradientUnits="userSpaceOnUse" + y2="48.674999" + x2="15.535398" + y1="1.8014067" + x1="15.535398" + id="linearGradient2245" + xlink:href="#linearGradient2239" + inkscape:collect="always" /> + <radialGradient + r="5" + fy="44" + fx="1" + cy="44" + cx="1" + gradientTransform="matrix(2,0,0,0.8,-13,-79.2)" + gradientUnits="userSpaceOnUse" + id="radialGradient2827" + xlink:href="#linearGradient2781" + inkscape:collect="always" /> + <radialGradient + r="5" + fy="44" + fx="1" + cy="44" + cx="1" + gradientTransform="matrix(2,0,0,0.8,36,8.8)" + gradientUnits="userSpaceOnUse" + id="radialGradient2829" + xlink:href="#linearGradient2781" + inkscape:collect="always" /> + <linearGradient + y2="40" + x2="21.875" + y1="48.000977" + x1="21.875" + gradientUnits="userSpaceOnUse" + id="linearGradient2831" + xlink:href="#linearGradient2804" + inkscape:collect="always" /> + <linearGradient + id="linearGradient2006"> + <stop + id="stop2008" + offset="0" + style="stop-color:black;stop-opacity:0;" /> + <stop + style="stop-color:black;stop-opacity:1;" + offset="0.5" + id="stop2010" /> + <stop + id="stop2012" + offset="1" + style="stop-color:black;stop-opacity:0;" /> + </linearGradient> + <linearGradient + y2="24.143761" + x2="27.273300" + y1="10.957423" + x1="35.003674" + gradientTransform="matrix(-0.977228,0,0,0.995878,50.60272,9.115637)" + gradientUnits="userSpaceOnUse" + id="linearGradient29443" + xlink:href="#linearGradient29418" + inkscape:collect="always" /> + <linearGradient + id="linearGradient29418"> + <stop + id="stop29420" + offset="0.0000000" + style="stop-color:#f5f5f5;stop-opacity:1.0000000;" /> + <stop + id="stop29422" + offset="1.0000000" + style="stop-color:#e9e9e9;stop-opacity:1.0000000;" /> + </linearGradient> + <linearGradient + id="linearGradient2225" + inkscape:collect="always"> + <stop + id="stop2227" + offset="0" + style="stop-color:#eeeeec;stop-opacity:1;" /> + <stop + id="stop2229" + offset="1" + style="stop-color:#eeeeec;stop-opacity:0;" /> + </linearGradient> + <linearGradient + id="linearGradient2989" + inkscape:collect="always"> + <stop + id="stop2991" + offset="0" + style="stop-color:#eeeeec;stop-opacity:1;" /> + <stop + id="stop2993" + offset="1" + style="stop-color:#eeeeec;stop-opacity:0;" /> + </linearGradient> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient2812" + id="radialGradient2112" + gradientUnits="userSpaceOnUse" + cx="31.112698" + cy="19.008621" + fx="31.112698" + fy="19.008621" + r="8.6620579" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2851" + id="linearGradient2114" + gradientUnits="userSpaceOnUse" + x1="6.878005" + y1="11.789385" + x2="12.233074" + y2="27.77807" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3149" + id="linearGradient2116" + gradientUnits="userSpaceOnUse" + x1="15.498499" + y1="9.4211226" + x2="24.240097" + y2="36.603138" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3149" + id="linearGradient2119" + gradientUnits="userSpaceOnUse" + x1="15.498499" + y1="9.4211226" + x2="24.240097" + y2="36.603138" + gradientTransform="matrix(0.287092,0,0,0.287092,5.363901,5.455069)" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2851" + id="linearGradient2122" + gradientUnits="userSpaceOnUse" + x1="6.878005" + y1="11.789385" + x2="12.233074" + y2="27.77807" + gradientTransform="matrix(0.358865,0,0,0.358865,4.079883,4.193835)" /> </defs> <sodipodi:namedview id="base" @@ -159,14 +726,14 @@ inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="22.197802" - inkscape:cx="24.938614" - inkscape:cy="9.7569307" + inkscape:cx="15.613366" + inkscape:cy="10.112799" inkscape:current-layer="layer1" showgrid="true" inkscape:grid-bbox="true" inkscape:document-units="px" - inkscape:window-width="1440" - inkscape:window-height="853" + inkscape:window-width="1434" + inkscape:window-height="844" inkscape:window-x="0" inkscape:window-y="0" /> <metadata @@ -222,12 +789,12 @@ id="path5807" sodipodi:nodetypes="cccccccccccccc" /> <path - style="fill:url(#linearGradient1959);fill-opacity:1;fill-rule:evenodd;stroke:#387101;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - d="M 15.541385,10.5 C 15.541385,13.26 13.292114,15.5 10.520692,15.5 C 7.7492697,15.5 5.4999993,13.26 5.4999993,10.5 C 5.4999993,7.7399998 7.7492697,5.5000001 10.520692,5.5000001 C 13.292114,5.5000001 15.541385,7.7399998 15.541385,10.5 z " - id="path2245" /> + style="fill:url(#linearGradient2122);fill-opacity:1;fill-rule:evenodd;stroke:#306300;stroke-width:0.99999887;stroke-miterlimit:4;stroke-opacity:1" + d="M 15.500002,10.5 C 15.500002,13.26 13.260001,15.5 10.500001,15.5 C 7.7400006,15.5 5.4999996,13.26 5.4999996,10.5 C 5.4999996,7.739999 7.7400006,5.4999989 10.500001,5.4999989 C 13.260001,5.4999989 15.500002,7.739999 15.500002,10.5 z " + id="path4331" /> <path - style="opacity:0.6;fill:url(#linearGradient1956);fill-opacity:1;fill-rule:evenodd;stroke:white;stroke-width:1.00000024;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - d="M 14.500006,10.499996 C 14.500006,12.707996 12.708004,14.499996 10.500004,14.499996 C 8.2920042,14.499996 6.5000039,12.707996 6.5000039,10.499996 C 6.5000039,8.2919968 8.2920042,6.4999962 10.500004,6.4999962 C 12.708004,6.4999962 14.500006,8.2919968 14.500006,10.499996 z " - id="path3145" /> + style="opacity:0.6;fill:url(#linearGradient2119);fill-opacity:1;fill-rule:evenodd;stroke:white;stroke-width:0.99999845;stroke-miterlimit:4;stroke-opacity:1" + d="M 14.500006,10.500002 C 14.500006,12.708002 12.708005,14.500003 10.500003,14.500003 C 8.2920011,14.500003 6.4999992,12.708002 6.4999992,10.500002 C 6.4999992,8.2920001 8.2920011,6.4999996 10.500003,6.4999996 C 12.708005,6.4999996 14.500006,8.2920001 14.500006,10.500002 z " + id="path4333" /> </g> </svg>
--- a/pidgin/pixmaps/tray/22/Makefile.am Thu Jun 14 19:48:48 2007 +0000 +++ b/pidgin/pixmaps/tray/22/Makefile.am Mon Jun 18 01:48:35 2007 +0000 @@ -6,6 +6,7 @@ tray-extended-away.png \ tray-invisible.png \ tray-message.png \ + tray-new-im.png \ tray-offline.png \ tray-online.png
--- a/pidgin/pixmaps/tray/22/scalable/tray-invisible.svg Thu Jun 14 19:48:48 2007 +0000 +++ b/pidgin/pixmaps/tray/22/scalable/tray-invisible.svg Mon Jun 18 01:48:35 2007 +0000 @@ -11,71 +11,62 @@ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="24" height="24" - id="svg4403" + id="svg2" sodipodi:version="0.32" inkscape:version="0.44.1" version="1.0" - sodipodi:docbase="/home/hbons/code/pidgin-mtn/pidgin/pixmaps/tray/22/scalable" + sodipodi:docbase="/home/hbons/Desktop" sodipodi:docname="tray-invisible.svg" - inkscape:export-filename="/home/hbons/code/pidgin-mtn/pidgin/pixmaps/tray/22/tray-invisible.png" + inkscape:export-filename="/home/hbons/Desktop/Gaim Refresh/notification-area/tray-busy.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90"> <defs - id="defs4405"> + id="defs4"> <linearGradient - id="linearGradient5187" - inkscape:collect="always"> + inkscape:collect="always" + id="linearGradient2989"> <stop - id="stop5189" + style="stop-color:#eeeeec;stop-opacity:1;" offset="0" - style="stop-color:#d3d7cf;stop-opacity:1;" /> + id="stop2991" /> <stop - id="stop5191" + style="stop-color:#eeeeec;stop-opacity:0;" offset="1" - style="stop-color:#d3d7cf;stop-opacity:0;" /> - </linearGradient> - <linearGradient - id="linearGradient2851"> - <stop - style="stop-color:#73d216;stop-opacity:1;" - offset="0" - id="stop2853" /> - <stop - style="stop-color:#5ca911;stop-opacity:1;" - offset="1" - id="stop2855" /> + id="stop2993" /> </linearGradient> <linearGradient inkscape:collect="always" - xlink:href="#linearGradient2804" - id="linearGradient2261" - gradientUnits="userSpaceOnUse" - x1="21.875" - y1="48.000977" - x2="21.875" - y2="40" /> - <radialGradient + id="linearGradient2225"> + <stop + style="stop-color:#eeeeec;stop-opacity:1;" + offset="0" + id="stop2227" /> + <stop + style="stop-color:#eeeeec;stop-opacity:0;" + offset="1" + id="stop2229" /> + </linearGradient> + <linearGradient + id="linearGradient29418"> + <stop + style="stop-color:#f5f5f5;stop-opacity:1.0000000;" + offset="0.0000000" + id="stop29420" /> + <stop + style="stop-color:#e9e9e9;stop-opacity:1.0000000;" + offset="1.0000000" + id="stop29422" /> + </linearGradient> + <linearGradient inkscape:collect="always" - xlink:href="#linearGradient2781" - id="radialGradient2259" + xlink:href="#linearGradient29418" + id="linearGradient29443" gradientUnits="userSpaceOnUse" - gradientTransform="matrix(2,0,0,0.8,36,8.8)" - cx="1" - cy="44" - fx="1" - fy="44" - r="5" /> - <radialGradient - inkscape:collect="always" - xlink:href="#linearGradient2781" - id="radialGradient2257" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(2,0,0,0.8,-13,-79.2)" - cx="1" - cy="44" - fx="1" - fy="44" - r="5" /> + gradientTransform="matrix(-0.977228,0,0,0.995878,50.60272,9.115637)" + x1="35.003674" + y1="10.957423" + x2="27.273300" + y2="24.143761" /> <linearGradient id="linearGradient2804"> <stop @@ -94,7 +85,7 @@ <linearGradient inkscape:collect="always" xlink:href="#linearGradient2804" - id="linearGradient7755" + id="linearGradient2831" gradientUnits="userSpaceOnUse" x1="21.875" y1="48.000977" @@ -103,7 +94,7 @@ <radialGradient inkscape:collect="always" xlink:href="#linearGradient2781" - id="radialGradient7753" + id="radialGradient2829" gradientUnits="userSpaceOnUse" gradientTransform="matrix(2,0,0,0.8,36,8.8)" cx="1" @@ -126,7 +117,7 @@ <radialGradient inkscape:collect="always" xlink:href="#linearGradient2781" - id="radialGradient7751" + id="radialGradient2827" gradientUnits="userSpaceOnUse" gradientTransform="matrix(2,0,0,0.8,-13,-79.2)" cx="1" @@ -136,14 +127,723 @@ r="5" /> <linearGradient inkscape:collect="always" - xlink:href="#linearGradient5187" - id="linearGradient2220" + id="linearGradient2186"> + <stop + style="stop-color:#ffffff;stop-opacity:1;" + offset="0" + id="stop2188" /> + <stop + style="stop-color:#ffffff;stop-opacity:0;" + offset="1" + id="stop2190" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient2260"> + <stop + style="stop-color:#555753;stop-opacity:1;" + offset="0" + id="stop2262" /> + <stop + style="stop-color:#555753;stop-opacity:0;" + offset="1" + id="stop2264" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient3816"> + <stop + style="stop-color:#000000;stop-opacity:1;" + offset="0" + id="stop3818" /> + <stop + style="stop-color:#000000;stop-opacity:0;" + offset="1" + id="stop3820" /> + </linearGradient> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3816" + id="radialGradient3822" + cx="31.112698" + cy="19.008621" + fx="31.112698" + fy="19.008621" + r="8.6620579" + gradientUnits="userSpaceOnUse" /> + <linearGradient + inkscape:collect="always" + id="linearGradient2200"> + <stop + style="stop-color:#d3d7cf;stop-opacity:1;" + offset="0" + id="stop2202" /> + <stop + style="stop-color:#d3d7cf;stop-opacity:0;" + offset="1" + id="stop2204" /> + </linearGradient> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient2200" + id="radialGradient2216" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(-2.522332,-1.518129e-16,-1.517788e-16,2.521765,40.1904,-21.83521)" + cx="9.9988937" + cy="8.963316" + fx="9.9988937" + fy="8.963316" + r="7.0034069" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient2200" + id="radialGradient2225" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(-2.522332,-1.518129e-16,-1.517788e-16,2.521765,40.1904,-21.80154)" + cx="9.9988937" + cy="8.963316" + fx="9.9988937" + fy="8.963316" + r="7.0034069" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient2260" + id="radialGradient2266" + cx="11.756953" + cy="17.588654" + fx="11.756953" + fy="17.588654" + r="6.3436799" + gradientTransform="matrix(1,0,0,0.626667,0,6.566431)" + gradientUnits="userSpaceOnUse" /> + <linearGradient + id="linearGradient2239" + inkscape:collect="always"> + <stop + id="stop2241" + offset="0" + style="stop-color:#ffffff;stop-opacity:1;" /> + <stop + id="stop2243" + offset="1" + style="stop-color:#ffffff;stop-opacity:0;" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2239" + id="linearGradient1357" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.371983,0,0,0.372254,2.539836,8.539528)" + x1="15.602553" + y1="1.5657365" + x2="15.522223" + y2="33.483475" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2186" + id="linearGradient2337" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.529942,0,0,0.53199,17.26643,15.48536)" + x1="11.226587" + y1="-5.4832759" + x2="11.226587" + y2="17.697369" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2239" + id="linearGradient2339" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.37378,0,0,0.375227,17.64779,15.86312)" + x1="15.535398" + y1="1.8014067" + x2="15.535398" + y2="48.674999" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2225" + id="linearGradient6606" + gradientUnits="userSpaceOnUse" + x1="11.802028" + y1="1.9986149" + x2="11.802028" + y2="14.895812" /> + <linearGradient + gradientUnits="userSpaceOnUse" + y2="27.77807" + x2="12.233074" + y1="11.789385" + x1="6.878005" + id="linearGradient2857" + xlink:href="#linearGradient2851" + inkscape:collect="always" /> + <linearGradient + id="linearGradient3149" + inkscape:collect="always"> + <stop + id="stop3151" + offset="0" + style="stop-color:#eeeeec;stop-opacity:1;" /> + <stop + id="stop3153" + offset="1" + style="stop-color:#eeeeec;stop-opacity:0;" /> + </linearGradient> + <linearGradient + id="linearGradient2851"> + <stop + id="stop2853" + offset="0" + style="stop-color:#73d216;stop-opacity:1;" /> + <stop + id="stop2855" + offset="1" + style="stop-color:#5ca911;stop-opacity:1;" /> + </linearGradient> + <linearGradient + y2="40.032413" + x2="17.890068" + y1="8.0617304" + x1="17.890068" + gradientUnits="userSpaceOnUse" + id="linearGradient2269" + xlink:href="#linearGradient3149" + inkscape:collect="always" /> + <linearGradient + id="linearGradient2812" + inkscape:collect="always"> + <stop + id="stop2814" + offset="0" + style="stop-color:#2e3436;stop-opacity:1;" /> + <stop + id="stop2816" + offset="1" + style="stop-color:#2e3436;stop-opacity:0;" /> + </linearGradient> + <radialGradient + gradientUnits="userSpaceOnUse" + r="8.6620579" + fy="19.008621" + fx="31.112698" + cy="19.008621" + cx="31.112698" + id="radialGradient2064" + xlink:href="#linearGradient2812" + inkscape:collect="always" /> + <linearGradient + gradientUnits="userSpaceOnUse" + y2="11.024895" + x2="10.623409" + y1="2.7991772" + x1="4.5264969" + id="linearGradient2062" + xlink:href="#linearGradient2804" + inkscape:collect="always" /> + <linearGradient + gradientUnits="userSpaceOnUse" + y2="27.77807" + x2="12.233074" + y1="11.789385" + x1="6.878005" + id="linearGradient2060" + xlink:href="#linearGradient2851" + inkscape:collect="always" /> + <linearGradient + id="linearGradient2048"> + <stop + id="stop2050" + offset="0" + style="stop-color:#73d216;stop-opacity:1;" /> + <stop + id="stop2052" + offset="1" + style="stop-color:#5ca911;stop-opacity:1;" /> + </linearGradient> + <linearGradient + y2="40.032413" + x2="17.890068" + y1="8.0617304" + x1="17.890068" + gradientUnits="userSpaceOnUse" + id="linearGradient2046" + xlink:href="#linearGradient3149" + inkscape:collect="always" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient2812" + id="radialGradient2084" + gradientUnits="userSpaceOnUse" + cx="31.112698" + cy="19.008621" + fx="31.112698" + fy="19.008621" + r="8.6620579" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2989" + id="linearGradient2995" + x1="1.5769236" + y1="1.3319674" + x2="10.043059" + y2="10.018044" + gradientUnits="userSpaceOnUse" /> + <radialGradient + r="8.6620579" + fy="19.008621" + fx="31.112698" + cy="19.008621" + cx="31.112698" + gradientUnits="userSpaceOnUse" + id="radialGradient3025" + xlink:href="#linearGradient2812" + inkscape:collect="always" /> + <linearGradient + y2="11.024895" + x2="10.623409" + y1="2.7991772" + x1="4.5264969" + gradientUnits="userSpaceOnUse" + id="linearGradient3007" + xlink:href="#linearGradient2804" + inkscape:collect="always" /> + <radialGradient + r="8.6620579" + fy="19.008621" + fx="31.112698" + cy="19.008621" + cx="31.112698" + gradientUnits="userSpaceOnUse" + id="radialGradient3005" + xlink:href="#linearGradient2812" + inkscape:collect="always" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3149" + id="linearGradient2949" + gradientUnits="userSpaceOnUse" + x1="17.890068" + y1="8.0617304" + x2="17.890068" + y2="40.032413" /> + <linearGradient + id="linearGradient2951"> + <stop + style="stop-color:#73d216;stop-opacity:1;" + offset="0" + id="stop2953" /> + <stop + style="stop-color:#5ca911;stop-opacity:1;" + offset="1" + id="stop2955" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2851" + id="linearGradient2963" + x1="6.878005" + y1="11.789385" + x2="12.233074" + y2="27.77807" + gradientUnits="userSpaceOnUse" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2804" + id="linearGradient2810" + x1="4.5264969" + y1="2.7991772" + x2="10.623409" + y2="11.024895" + gradientUnits="userSpaceOnUse" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient2812" + id="radialGradient2818" + cx="31.112698" + cy="19.008621" + fx="31.112698" + fy="19.008621" + r="8.6620579" + gradientUnits="userSpaceOnUse" /> + <radialGradient + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(3.018423,0.664359,-1.388844,4.257661,-0.134567,-26.02469)" + r="0.8078171" + fy="6.9473476" + fx="4.8470273" + cy="6.9473476" + cx="4.8470273" + id="radialGradient2904" + xlink:href="#linearGradient2898" + inkscape:collect="always" /> + <linearGradient gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.394752,0,0,0.394752,8.437859,8.563225)" - x1="19.461548" - y1="6.4422231" - x2="19.461548" - y2="28.669207" /> + y2="27.77807" + x2="12.233074" + y1="11.789385" + x1="6.878005" + id="linearGradient3066" + xlink:href="#linearGradient2851" + inkscape:collect="always" /> + <radialGradient + gradientTransform="matrix(0.914124,-3.896132e-15,-2.475021e-18,1.631747,2.671799,-12.00863)" + gradientUnits="userSpaceOnUse" + r="8.6620579" + fy="19.008621" + fx="31.112698" + cy="19.008621" + cx="31.112698" + id="radialGradient3064" + xlink:href="#linearGradient3816" + inkscape:collect="always" /> + <linearGradient + id="linearGradient3046"> + <stop + id="stop3048" + offset="0" + style="stop-color:#73d216;stop-opacity:1;" /> + <stop + id="stop3050" + offset="1" + style="stop-color:#5ca911;stop-opacity:1;" /> + </linearGradient> + <linearGradient + y2="40.032413" + x2="17.890068" + y1="8.0617304" + x1="17.890068" + gradientUnits="userSpaceOnUse" + id="linearGradient3044" + xlink:href="#linearGradient3149" + inkscape:collect="always" /> + <linearGradient + y2="36.603138" + x2="24.240097" + y1="9.4211226" + x1="15.498499" + gradientUnits="userSpaceOnUse" + id="linearGradient4740" + xlink:href="#linearGradient3149" + inkscape:collect="always" /> + <linearGradient + id="linearGradient2898" + inkscape:collect="always"> + <stop + id="stop2900" + offset="0" + style="stop-color:white;stop-opacity:1;" /> + <stop + id="stop2902" + offset="1" + style="stop-color:white;stop-opacity:0;" /> + </linearGradient> + <linearGradient + gradientUnits="userSpaceOnUse" + y2="27.77807" + x2="12.233074" + y1="11.789385" + x1="6.878005" + id="linearGradient2055" + xlink:href="#linearGradient2851" + inkscape:collect="always" /> + <radialGradient + gradientTransform="matrix(0.914124,-3.896132e-15,-2.475021e-18,1.631747,2.671799,-12.00863)" + gradientUnits="userSpaceOnUse" + r="8.6620579" + fy="19.008621" + fx="31.112698" + cy="19.008621" + cx="31.112698" + id="radialGradient2053" + xlink:href="#linearGradient3816" + inkscape:collect="always" /> + <linearGradient + id="linearGradient2034"> + <stop + id="stop2036" + offset="0" + style="stop-color:#73d216;stop-opacity:1;" /> + <stop + id="stop2038" + offset="1" + style="stop-color:#5ca911;stop-opacity:1;" /> + </linearGradient> + <linearGradient + y2="40.032413" + x2="17.890068" + y1="8.0617304" + x1="17.890068" + gradientUnits="userSpaceOnUse" + id="linearGradient2032" + xlink:href="#linearGradient3149" + inkscape:collect="always" /> + <linearGradient + gradientTransform="matrix(0.482882,0,0,0.482874,0.269812,0.26982)" + gradientUnits="userSpaceOnUse" + y2="39.834526" + x2="31.18539" + y1="4.5934086" + x1="8.7505674" + id="linearGradient2030" + xlink:href="#linearGradient2239" + inkscape:collect="always" /> + <linearGradient + gradientTransform="matrix(0.684526,0,0,0.687171,-0.20455,-0.253325)" + gradientUnits="userSpaceOnUse" + y2="17.697369" + x2="11.226587" + y1="-1.5641226" + x1="9.2594385" + id="linearGradient2022" + xlink:href="#linearGradient2186" + inkscape:collect="always" /> + <radialGradient + r="8.6620579" + fy="19.008621" + fx="31.112698" + cy="19.008621" + cx="31.112698" + gradientUnits="userSpaceOnUse" + id="radialGradient2014" + xlink:href="#linearGradient2812" + inkscape:collect="always" /> + <radialGradient + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(3.018423,0.664359,-1.388844,4.257661,-0.134567,-26.02469)" + r="0.8078171" + fy="6.9473476" + fx="4.8470273" + cy="6.9473476" + cx="4.8470273" + id="radialGradient2006" + xlink:href="#linearGradient2898" + inkscape:collect="always" /> + <linearGradient + gradientUnits="userSpaceOnUse" + y2="27.77807" + x2="12.233074" + y1="11.789385" + x1="6.878005" + id="linearGradient3069" + xlink:href="#linearGradient2851" + inkscape:collect="always" /> + <radialGradient + gradientTransform="matrix(0.914124,-3.896132e-15,-2.475021e-18,1.631747,2.671799,-12.00863)" + gradientUnits="userSpaceOnUse" + r="8.6620579" + fy="19.008621" + fx="31.112698" + cy="19.008621" + cx="31.112698" + id="radialGradient3067" + xlink:href="#linearGradient3816" + inkscape:collect="always" /> + <linearGradient + id="linearGradient3049"> + <stop + id="stop3051" + offset="0" + style="stop-color:#73d216;stop-opacity:1;" /> + <stop + id="stop3053" + offset="1" + style="stop-color:#5ca911;stop-opacity:1;" /> + </linearGradient> + <linearGradient + y2="40.032413" + x2="17.890068" + y1="8.0617304" + x1="17.890068" + gradientUnits="userSpaceOnUse" + id="linearGradient3047" + xlink:href="#linearGradient3149" + inkscape:collect="always" /> + <linearGradient + gradientTransform="matrix(0.482882,0,0,0.482874,0.269812,0.26982)" + gradientUnits="userSpaceOnUse" + y2="39.834526" + x2="31.18539" + y1="4.5934086" + x1="8.7505674" + id="linearGradient3045" + xlink:href="#linearGradient2239" + inkscape:collect="always" /> + <linearGradient + gradientTransform="matrix(0.684526,0,0,0.687171,-0.20455,-0.253325)" + gradientUnits="userSpaceOnUse" + y2="19.159578" + x2="14.441897" + y1="3.7276814" + x1="6.2538223" + id="linearGradient2194" + xlink:href="#linearGradient2186" + inkscape:collect="always" /> + <radialGradient + r="8.6620579" + fy="19.008621" + fx="31.112698" + cy="19.008621" + cx="31.112698" + gradientUnits="userSpaceOnUse" + id="radialGradient3030" + xlink:href="#linearGradient2812" + inkscape:collect="always" /> + <radialGradient + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(3.018423,0.664359,-1.388844,4.257661,-0.134567,-26.02469)" + r="0.8078171" + fy="6.9473476" + fx="4.8470273" + cy="6.9473476" + cx="4.8470273" + id="radialGradient3022" + xlink:href="#linearGradient2898" + inkscape:collect="always" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient2812" + id="radialGradient3082" + gradientUnits="userSpaceOnUse" + cx="31.112698" + cy="19.008621" + fx="31.112698" + fy="19.008621" + r="8.6620579" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2239" + id="linearGradient3084" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.37378,0,0,0.375227,5.518529,18.82427)" + x1="15.535398" + y1="1.8014067" + x2="15.535398" + y2="48.674999" /> + <radialGradient + r="8.6620579" + fy="19.008621" + fx="31.112698" + cy="19.008621" + cx="31.112698" + gradientUnits="userSpaceOnUse" + id="radialGradient3198" + xlink:href="#linearGradient2812" + inkscape:collect="always" /> + <linearGradient + y2="11.024895" + x2="10.623409" + y1="2.7991772" + x1="4.5264969" + gradientUnits="userSpaceOnUse" + id="linearGradient3196" + xlink:href="#linearGradient2804" + inkscape:collect="always" /> + <radialGradient + r="8.6620579" + fy="19.008621" + fx="31.112698" + cy="19.008621" + cx="31.112698" + gradientUnits="userSpaceOnUse" + id="radialGradient3194" + xlink:href="#linearGradient2812" + inkscape:collect="always" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3149" + id="linearGradient3180" + gradientUnits="userSpaceOnUse" + x1="17.890068" + y1="8.0617304" + x2="17.890068" + y2="40.032413" /> + <linearGradient + id="linearGradient3174"> + <stop + style="stop-color:#73d216;stop-opacity:1;" + offset="0" + id="stop3176" /> + <stop + style="stop-color:#5ca911;stop-opacity:1;" + offset="1" + id="stop3178" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2851" + id="linearGradient3172" + x1="6.878005" + y1="11.789385" + x2="12.233074" + y2="27.77807" + gradientUnits="userSpaceOnUse" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2804" + id="linearGradient3170" + x1="4.5264969" + y1="2.7991772" + x2="10.623409" + y2="11.024895" + gradientUnits="userSpaceOnUse" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient2812" + id="radialGradient3168" + cx="31.112698" + cy="19.008621" + fx="31.112698" + fy="19.008621" + r="8.6620579" + gradientUnits="userSpaceOnUse" /> + <linearGradient + gradientUnits="userSpaceOnUse" + y2="27.77807" + x2="12.233074" + y1="11.789385" + x1="6.878005" + id="linearGradient3166" + xlink:href="#linearGradient2851" + inkscape:collect="always" /> + <radialGradient + gradientTransform="matrix(0.914124,-3.896132e-15,-2.475021e-18,1.631747,2.671799,-12.00863)" + gradientUnits="userSpaceOnUse" + r="8.6620579" + fy="19.008621" + fx="31.112698" + cy="19.008621" + cx="31.112698" + id="radialGradient3164" + xlink:href="#linearGradient3816" + inkscape:collect="always" /> + <linearGradient + id="linearGradient3146"> + <stop + id="stop3148" + offset="0" + style="stop-color:#73d216;stop-opacity:1;" /> + <stop + id="stop3150" + offset="1" + style="stop-color:#5ca911;stop-opacity:1;" /> + </linearGradient> + <linearGradient + y2="40.032413" + x2="17.890068" + y1="8.0617304" + x1="17.890068" + gradientUnits="userSpaceOnUse" + id="linearGradient3144" + xlink:href="#linearGradient3149" + inkscape:collect="always" /> + <linearGradient + y2="36.603138" + x2="24.240097" + y1="9.4211226" + x1="15.498499" + gradientUnits="userSpaceOnUse" + id="linearGradient3142" + xlink:href="#linearGradient3149" + inkscape:collect="always" /> </defs> <sodipodi:namedview id="base" @@ -152,21 +852,19 @@ borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="25.498579" - inkscape:cx="19.883015" - inkscape:cy="11.999162" + inkscape:zoom="20.899939" + inkscape:cx="26.526463" + inkscape:cy="11.289944" + inkscape:document-units="px" inkscape:current-layer="layer1" showgrid="true" - inkscape:grid-bbox="true" - inkscape:document-units="px" - width="24px" - height="24px" - inkscape:window-width="1274" - inkscape:window-height="844" - inkscape:window-x="6" + fill="#d3d7cf" + inkscape:window-width="1440" + inkscape:window-height="849" + inkscape:window-x="0" inkscape:window-y="0" /> <metadata - id="metadata4408"> + id="metadata7"> <rdf:RDF> <cc:Work rdf:about=""> @@ -177,53 +875,55 @@ </rdf:RDF> </metadata> <g - id="layer1" inkscape:label="Layer 1" - inkscape:groupmode="layer"> + inkscape:groupmode="layer" + id="layer1"> + <path + style="opacity:1;fill:#efefef;fill-opacity:1;fill-rule:evenodd;stroke:#787878;stroke-width:0.99999994;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="M 14.877402,1.4999995 C 15.782108,1.4999995 16.499998,2.2063381 16.499998,3.1046506 L 16.499998,12.174417 C 16.499998,13.07273 15.78211,13.491987 14.877402,13.491987 L 8.2067299,13.491987 L 4.5191254,16.212917 L 4.5191254,13.491987 L 3.1225959,13.491987 C 2.2178895,13.491987 1.4999988,13.07273 1.5,12.174417 L 1.5,3.1046506 C 1.5,2.2063381 2.2178895,1.4999995 3.1225959,1.4999995 L 14.877402,1.4999995 z " + id="path2221" + sodipodi:nodetypes="cccccccccccc" /> + <path + sodipodi:type="inkscape:offset" + inkscape:radius="-1.0047876" + inkscape:original="M 3.125 1.5 C 2.2202936 1.5 1.5 2.1954376 1.5 3.09375 L 1.5 12.1875 C 1.4999988 13.085813 2.2202937 13.5 3.125 13.5 L 4.53125 13.5 L 4.53125 16.21875 L 8.21875 13.5 L 14.875 13.5 C 15.779708 13.5 16.5 13.085813 16.5 12.1875 L 16.5 3.09375 C 16.5 2.1954375 15.779706 1.5 14.875 1.5 L 3.125 1.5 z " + xlink:href="#path2221" + style="opacity:1;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:white;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="path5807" + inkscape:href="#path2221" + d="M 2.90625,2.5 C 2.6627552,2.5 2.5,2.6506524 2.5,2.9375 L 2.5,11.0625 C 2.4999996,11.349346 2.6627555,11.5 2.90625,11.5 L 4.53125,11.5 C 5.0824231,11.502675 5.5285754,11.948827 5.53125,12.5 L 5.53125,12.75 L 6.65625,11.75 C 6.8378154,11.590455 7.0708028,11.501698 7.3125,11.5 L 13.09375,11.5 C 13.337246,11.5 13.5,11.349348 13.5,11.0625 L 13.5,2.9375 C 13.5,2.6506524 13.337245,2.5 13.09375,2.5 L 2.90625,2.5 z " /> + <g + id="g2057" + inkscape:label="Layer 1" + transform="translate(19.12926,4.037634)" /> <g - id="g2249" - style="opacity:0.3" - transform="matrix(-0.340425,0,0,0.625,17.34043,-14)"> - <rect - transform="scale(-1,-1)" - y="-48" - x="-11" - height="8" - width="10" - id="rect2251" - style="opacity:1;color:black;fill:url(#radialGradient2257);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" /> - <rect - y="40" - x="38" - height="8" - width="10" - id="rect2253" - style="opacity:1;color:black;fill:url(#radialGradient2259);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" /> - <rect - y="40" - x="11" - height="8" - width="27" - id="rect2255" - style="opacity:1;color:black;fill:url(#linearGradient2261);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" /> + id="g3200" + inkscape:label="Layer 1" + transform="translate(6.999999,7.000001)"> + <g + style="opacity:0.8" + id="g1918"> + <path + d="M 39.774755 19.008621 A 8.6620579 8.6620579 0 1 1 22.45064,19.008621 A 8.6620579 8.6620579 0 1 1 39.774755 19.008621 z" + sodipodi:ry="8.6620579" + sodipodi:rx="8.6620579" + sodipodi:cy="19.008621" + sodipodi:cx="31.112698" + id="path3203" + style="color:black;fill:url(#radialGradient3025);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" + sodipodi:type="arc" + transform="matrix(0.923568,0,0,0.173169,-20.73469,11.2083)" /> + <path + transform="matrix(0.538297,0,0,0.538297,-1.630177,-1.459246)" + style="fill:#babdb6;fill-opacity:1;fill-rule:evenodd;stroke:#888a85;stroke-width:1.85770929;stroke-miterlimit:4;stroke-opacity:1" + d="M 31.822886,17.572527 C 31.822886,25.263442 25.580983,31.505344 17.890068,31.505344 C 10.199153,31.505344 3.9572506,25.263442 3.9572506,17.572527 C 3.9572506,9.8816117 10.199153,3.6397095 17.890068,3.6397095 C 25.580983,3.6397095 31.822886,9.8816117 31.822886,17.572527 z " + id="path4331" /> + <path + transform="matrix(0.466524,0,0,0.466525,-0.346154,-0.198015)" + style="opacity:0.6;fill:url(#linearGradient4740);fill-opacity:1;fill-rule:evenodd;stroke:white;stroke-width:2.14350748;stroke-miterlimit:4;stroke-opacity:1" + d="M 31.822886,17.572527 C 31.822886,25.263442 25.580983,31.505344 17.890068,31.505344 C 10.199153,31.505344 3.9572506,25.263442 3.9572506,17.572527 C 3.9572506,9.8816117 10.199153,3.6397095 17.890068,3.6397095 C 25.580983,3.6397095 31.822886,9.8816117 31.822886,17.572527 z " + id="path4333" /> + </g> </g> - <path - style="fill:#efefef;fill-opacity:1;fill-rule:evenodd;stroke:#787878;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1" - d="M 9.90625,2.5 C 9.1221707,2.5 8.5000001,3.1327617 8.5,3.9375 L 8.5,12.0625 C 8.5,12.867238 9.1221703,13.5 9.90625,13.5 L 15.6875,13.5 L 18.46875,15.9375 L 18.46875,13.5 L 20.09375,13.5 C 20.877829,13.5 21.500001,12.867238 21.5,12.0625 L 21.5,3.9375 C 21.5,3.1327617 20.877829,2.5 20.09375,2.5 L 9.90625,2.5 z " - id="path2221" - transform="matrix(-1,0,0,1,24,0)" /> - <path - style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:white;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1" - d="M 9.90625,3.5 C 9.6627547,3.5 9.5,3.650652 9.5,3.9375 L 9.5,12.0625 C 9.5,12.349348 9.6627543,12.5 9.90625,12.5 L 15.6875,12.5 C 15.929197,12.501698 16.162185,12.590455 16.34375,12.75 L 17.46875,13.75 L 17.46875,13.5 C 17.471425,12.948827 17.917577,12.502675 18.46875,12.5 L 20.09375,12.5 C 20.337245,12.5 20.5,12.349346 20.5,12.0625 L 20.5,3.9375 C 20.5,3.6506524 20.337245,3.5 20.09375,3.5 L 9.90625,3.5 z " - id="path5807" - transform="matrix(-1,0,0,1,24,0)" /> - <path - style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#babdb6;stroke-width:0.99999863;stroke-miterlimit:4;stroke-opacity:1" - d="M 21.500007,15.500001 C 21.500007,18.812 18.81201,21.499999 15.500004,21.499999 C 12.188,21.499999 9.5000032,18.812 9.5000032,15.500001 C 9.5000032,12.188001 12.188,9.5000014 15.500004,9.5000014 C 18.81201,9.5000014 21.500007,12.188001 21.500007,15.500001 z " - id="path4331" /> - <path - style="opacity:0.6;fill:url(#linearGradient2220);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.14350748;stroke-miterlimit:4;stroke-opacity:1" - d="M 21,15.500001 C 21,18.536 18.535999,21 15.499999,21 C 12.464,21 10,18.536 10,15.500001 C 10,12.464 12.464,10 15.499999,10 C 18.535999,10 21,12.464 21,15.500001 z " - id="path4333" /> </g> </svg>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pidgin/pixmaps/tray/32/Makefile.am Mon Jun 18 01:48:35 2007 +0000 @@ -0,0 +1,13 @@ +TRAY_ICONS = tray-away.png \ + tray-busy.png \ + tray-connecting.png \ + tray-extended-away.png \ + tray-invisible.png \ + tray-new-im.png \ + tray-offline.png \ + tray-online.png + +EXTRA_DIST = $(TRAY_ICONS) + +pidgintraypixdir = $(datadir)/pixmaps/pidgin/tray/32 +pidgintraypix_DATA = $(TRAY_ICONS)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pidgin/pixmaps/tray/32/Makefile.mingw Mon Jun 18 01:48:35 2007 +0000 @@ -0,0 +1,20 @@ +# +# Makefile.mingw +# +# Description: Makefile for win32 (mingw) version of Pidgin pixmaps +# + +PIDGIN_TREE_TOP := ../../../.. +include $(PIDGIN_TREE_TOP)/libpurple/win32/global.mak + +datadir = $(PIDGIN_INSTALL_DIR) +include ./Makefile.am + +.PHONY: install + +install: + if test '$(pidgintraypix_DATA)'; then \ + mkdir -p $(pidgintraypixdir); \ + cp $(pidgintraypix_DATA) $(pidgintraypixdir); \ + fi; +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pidgin/pixmaps/tray/48/Makefile.am Mon Jun 18 01:48:35 2007 +0000 @@ -0,0 +1,13 @@ +TRAY_ICONS = tray-away.png \ + tray-busy.png \ + tray-connecting.png \ + tray-extended-away.png \ + tray-invisible.png \ + tray-new-im.png \ + tray-offline.png \ + tray-online.png + +EXTRA_DIST = $(TRAY_ICONS) + +pidgintraypixdir = $(datadir)/pixmaps/pidgin/tray/48 +pidgintraypix_DATA = $(TRAY_ICONS)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pidgin/pixmaps/tray/48/Makefile.mingw Mon Jun 18 01:48:35 2007 +0000 @@ -0,0 +1,20 @@ +# +# Makefile.mingw +# +# Description: Makefile for win32 (mingw) version of Pidgin pixmaps +# + +PIDGIN_TREE_TOP := ../../../.. +include $(PIDGIN_TREE_TOP)/libpurple/win32/global.mak + +datadir = $(PIDGIN_INSTALL_DIR) +include ./Makefile.am + +.PHONY: install + +install: + if test '$(pidgintraypix_DATA)'; then \ + mkdir -p $(pidgintraypixdir); \ + cp $(pidgintraypix_DATA) $(pidgintraypixdir); \ + fi; +
--- a/pidgin/pixmaps/tray/Makefile.am Thu Jun 14 19:48:48 2007 +0000 +++ b/pidgin/pixmaps/tray/Makefile.am Mon Jun 18 01:48:35 2007 +0000 @@ -1,7 +1,9 @@ -SUBDIRS = 16 22 +SUBDIRS = 16 22 32 48 EXTRA_DIST = \ Makefile.mingw \ 16/Makefile.mingw \ - 22/Makefile.mingw + 22/Makefile.mingw \ + 32/Makefile.mingw \ + 48/Makefile.mingw
--- a/pidgin/plugins/Makefile.am Thu Jun 14 19:48:48 2007 +0000 +++ b/pidgin/plugins/Makefile.am Mon Jun 18 01:48:35 2007 +0000 @@ -30,6 +30,7 @@ contact_priority_la_LDFLAGS = -module -avoid-version extplacement_la_LDFLAGS = -module -avoid-version gtk_signals_test_la_LDFLAGS = -module -avoid-version +gtkbuddynote_la_LDFLAGS = -module -avoid-version history_la_LDFLAGS = -module -avoid-version iconaway_la_LDFLAGS = -module -avoid-version markerline_la_LDFLAGS = -module -avoid-version @@ -46,6 +47,7 @@ plugin_LTLIBRARIES = \ convcolors.la \ extplacement.la \ + gtkbuddynote.la \ history.la \ iconaway.la \ markerline.la \ @@ -65,6 +67,7 @@ contact_priority_la_SOURCES = contact_priority.c extplacement_la_SOURCES = extplacement.c gtk_signals_test_la_SOURCES = gtk-signals-test.c +gtkbuddynote_la_SOURCES = gtkbuddynote.c history_la_SOURCES = history.c iconaway_la_SOURCES = iconaway.c markerline_la_SOURCES = markerline.c @@ -80,6 +83,7 @@ contact_priority_la_LIBADD = $(GTK_LIBS) extplacement_la_LIBADD = $(GTK_LIBS) gtk_signals_test_la_LIBADD = $(GTK_LIBS) +gtkbuddynote_la_LIBADD = $(GTK_LIBS) history_la_LIBADD = $(GTK_LIBS) iconaway_la_LIBADD = $(GTK_LIBS) markerline_la_LIBADD = $(GTK_LIBS)
--- a/pidgin/plugins/Makefile.mingw Thu Jun 14 19:48:48 2007 +0000 +++ b/pidgin/plugins/Makefile.mingw Mon Jun 18 01:48:35 2007 +0000 @@ -77,11 +77,12 @@ plugins: \ convcolors.dll \ extplacement.dll \ - pidginrc.dll \ + gtkbuddynote.dll \ history.dll \ iconaway.dll \ markerline.dll \ notify.dll \ + pidginrc.dll \ relnot.dll \ spellchk.dll \ timestamp_format.dll \
--- a/pidgin/plugins/gevolution/gevolution.c Thu Jun 14 19:48:48 2007 +0000 +++ b/pidgin/plugins/gevolution/gevolution.c Mon Jun 18 01:48:35 2007 +0000 @@ -38,7 +38,6 @@ #include <libedata-book/Evolution-DataServer-Addressbook.h> -#include <libebook/e-book-listener.h> #include <libedata-book/e-data-book-factory.h> #include <bonobo/bonobo-main.h>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pidgin/plugins/gtkbuddynote.c Mon Jun 18 01:48:35 2007 +0000 @@ -0,0 +1,126 @@ +/* + * GtkBuddyNote - Store notes on particular buddies + * Copyright (C) 2007 Etan Reisner <deryni@pidgin.im> + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#include "internal.h" + +#include <gtkblist.h> +#include <gtkplugin.h> + +#include <debug.h> +#include <version.h> + +static void +append_to_tooltip(PurpleBlistNode *node, GString *text, gboolean full) +{ + if (full) { + const gchar *note = purple_blist_node_get_string(node, "notes"); + + if (note != NULL) { + g_string_append_printf(text, _("\nBuddy Note: %s"), + note); + } + } +} + +static gboolean +plugin_load(PurplePlugin *plugin) +{ + purple_signal_connect(pidgin_blist_get_handle(), "drawing-tooltip", + plugin, PURPLE_CALLBACK(append_to_tooltip), NULL); + return TRUE; +} + +static gboolean +plugin_unload(PurplePlugin *plugin) +{ + PurplePlugin *buddynote = NULL; + + buddynote = purple_plugins_find_with_id("core-plugin_pack-buddynote"); + + purple_plugin_unload(buddynote); + + return TRUE; +} + +static PurplePluginInfo info = +{ + PURPLE_PLUGIN_MAGIC, + PURPLE_MAJOR_VERSION, /**< major version */ + PURPLE_MINOR_VERSION, /**< minor version */ + PURPLE_PLUGIN_STANDARD, /**< type */ + PIDGIN_PLUGIN_TYPE, /**< ui_requirement */ + 0, /**< flags */ + NULL, /**< dependencies */ + PURPLE_PRIORITY_DEFAULT, /**< priority */