# HG changeset patch # User Richard Laager # Date 1179781103 0 # Node ID 618a3748ff64c93e35e7c8635bfa378f1625a0e0 # Parent e42309469a4a4980a8beb308359786ff2d1ff96e# Parent 0598803f9b6494ef2dba1a2dcb147eba9cc1a7d9 merge of '6a857845ed772173ecc2083603f0d661eb52c68a' and 'f806da14ec2d87cd6650b921eaeed3c6d6587598' diff -r e42309469a4a -r 618a3748ff64 COPYRIGHT --- a/COPYRIGHT Mon May 21 20:02:18 2007 +0000 +++ b/COPYRIGHT Mon May 21 20:58:23 2007 +0000 @@ -87,7 +87,9 @@ Palmer Cox Jeramey Crawford Michael Culbertson +Steven Danna Martijn Dekker +Vinicius Depizzol Philip Derrin Taso N. Devetzis Balwinder Singh Dheeman @@ -171,6 +173,7 @@ Thomas Huriaux Instant Messaging Freedom, Inc. Vitaliy Ischenko +Intel Corporation Scott Jackson Hans Petter Jansson Henry Jen @@ -302,6 +305,7 @@ David Schmitt Mark Schneider Evan Schoenberg +Gabriel Schulhof Federico Schwindt Torrey Searle Peter Seebach @@ -321,6 +325,7 @@ Phil Snowberger Eddie Sohn (tr1sk) Sony Computer Entertainment America, Inc. +Andy Spencer Mark Spencer Lex Spoon Chris Stafford @@ -353,11 +358,13 @@ Junichi Uekawa István Váradi Martijn van Beers +Arjan van de Ven Philip Van Hoof Kristof Vansant James Vega David Vermeille Sid Vicious +Jorge Villaseñor (Masca) Bjoern Voigt Wan Hing Wah Philip Walford diff -r e42309469a4a -r 618a3748ff64 ChangeLog --- a/ChangeLog Mon May 21 20:02:18 2007 +0000 +++ b/ChangeLog Mon May 21 20:58:23 2007 +0000 @@ -3,13 +3,59 @@ version 2.0.1 (??/??/????): * Buddy list update speedups when buddy icons are not being displayed. (Scott Wolchok) + * Fix icons on docklet change status menu to match the status selector + * Custom smileys on MSN can be saved by right-clicking on them + * Fix a crash deleting a buddy that is in the Buddy List more than once + * Compile fixes for Solaris + * Fix GTalk formatting when there's a space before/after a */_ + * Fix Log viewer crash when the filename is not in the expected format + * Get User Info now provides immediate feedback, and is updated when the + user information is available + * Make the choose buddy icon dialog correctly list the current directory + * Fix for buddy icons disappearing + * Timestamps are always on in debug output (-d) and Debug Window now + * Don't escape html entities in Yahoo! system messages + * Fix for the choose buddy icon dialog resizing strangely as files are selected + * Receives notifications when XMPP buddies send "leaving chat" + messages + * Fix the typing animation so it doesn't stop animating once a conversation + has gone from typing -> not typing -> typing + * Fix error messages when joing XMPP chats + * Identify the account when warning about plaintext auth over an + unencrypted channel + * Fix XMPP SASL authentication error when using Cyrus and a connect server + * Fix changing tab locations to update properly + * Turning off "Show formatting on incoming messages" now ignores + formatting in tags too + * File transfer progress for transfers on MSN is now correctly displayed + * You can set/change alias of buddies/chats by double-clicking on the + conversation tabs (Ma Xuan) + * Fix IRC connection bug with dircproxy (xjoe) + * Ctrl+[shift]+tab focuses the next most active tab (William Thompson) + * Fix Open Hotmail Inbox for MSN to work more reliably + * Add a Google Talk item to the protocol list, to help users who think + we don't support Google Talk. The item acts just like "XMPP". + * Remember if the X server supports XScreenSaver, to avoid waking it + every 5 seconds. (Arjan van de Ven with Intel Corporation) + * Change our idle checking to poll only as necessary and raise the + unidle timeout from 5 seconds to 60 when using XScreenSaver. This + and the XScreenSaver change will reduce Pidgin's effect on power + consumption when running with NO_HZ. (Arjan van de Ven with Intel + Corporation) + * Conversation -> Save As will now use aliases. Finch: * Userlist in chat windows, which can be turned on or off using - "/users" command. - * Menus in the conversation windows. - * Improved tab completion support. - * Ctrl+c prompts with a dialog before exiting. + "/users" command + * Menus in the conversation windows + * Improved tab completion support + * Ctrl+c prompts with a dialog before exiting + * Filter string in the debug window + * Notify when you leave a chat + * Work around an ncurses bug which appears when half of a multi-cell + character is covered by an upper-level window + * New plugins are shown in bold text in the plugin dialog + * Nicer HTML screendumps version 2.0.0 (5/3/2007): * The project has new names - libpurple for the core, Pidgin for the diff -r e42309469a4a -r 618a3748ff64 ChangeLog.win32 --- a/ChangeLog.win32 Mon May 21 20:02:18 2007 +0000 +++ b/ChangeLog.win32 Mon May 21 20:58:23 2007 +0000 @@ -1,7 +1,9 @@ +version 2.0.1 (??/??/????): + version 2.0.0 (5/3/2007): * URI Handler support added via `pidgin.exe --protocolhandler=` * Running a second instance will popup the Buddy List, if possible. - * Updated GTK+ to 2.10.11 (rev.a) (Win98/ME will need to use 2.6.10) + * Updated GTK+ to 2.10.11 (rev.b) (Win98/ME will need to use 2.6.10) * The transparency plugin has been rewritten and enhanced. * MSN open email bug fixed. * Update SILC to use the 1.0.2 toolkit diff -r e42309469a4a -r 618a3748ff64 config.h.mingw --- a/config.h.mingw Mon May 21 20:02:18 2007 +0000 +++ b/config.h.mingw Mon May 21 20:58:23 2007 +0000 @@ -4,65 +4,26 @@ /* configure arguments */ /* #undef CONFIG_ARGS */ -/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP - systems. This function is required for `alloca.c' support on those systems. - */ -/* #undef CRAY_STACKSEG_END */ - -/* Define to 1 if using `alloca.c'. */ -/* #undef C_ALLOCA */ - /* Define if debugging is enabled. */ /* #undef DEBUG */ -/* Use binary relocation? */ -/* #undef ENABLE_BINRELOC */ - /* Define if mono enabled. */ /* #undef ENABLE_MONO */ -/* Define to 1 if translation of program messages to the user's native - language is requested. */ +/* always defined to indicate that i18n is enabled */ #define ENABLE_NLS 1 -/* Define to make assertions fatal (useful for debugging). */ -/* #undef PURPLE_FATAL_ASSERTS */ - -/* Define if plugins are enabled. */ -#define PURPLE_PLUGINS 1 - -/* Define to 1 if you have `alloca', as a function or macro. */ -#define HAVE_ALLOCA 1 - -/* Define to 1 if you have and it should be used (not on Ultrix). - */ -/* #undef HAVE_ALLOCA_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_ALSA_ASOUNDLIB_H */ - /* Define if you have the external 'altzone' variable. */ /* #undef HAVE_ALTZONE */ -/* Define to 1 if you have the header file. */ -/* #undef HAVE_ARGZ_H */ - /* Define to 1 if you have the header file. */ /* #undef HAVE_ARPA_NAMESER_COMPAT_H */ -/* Define to 1 if you have the `asprintf' function. */ -/* #undef HAVE_ASPRINTF */ - /* Define to 1 if you have the `atexit' function. */ #define HAVE_ATEXIT 1 -/* Define to 1 if you have the MacOS X function CFLocaleCopyCurrent in the - CoreFoundation framework. */ -/* #undef HAVE_CFLOCALECOPYCURRENT */ - -/* Define to 1 if you have the MacOS X function CFPreferencesCopyAppValue in - the CoreFoundation framework. */ -/* #undef HAVE_CFPREFERENCESCOPYAPPVALUE */ +/* Define to 1 if you have the `bind_textdomain_codeset' function. */ +/* #undef HAVE_BIND_TEXTDOMAIN_CODESET */ /* Define to 1 if you have the `connect' function. */ /* #undef HAVE_CONNECT */ @@ -73,39 +34,19 @@ /* Define if you have the external 'daylight' variable. */ #define HAVE_DAYLIGHT 1 -/* Define if we are re using DBUS. */ +/* Define if we are using D-Bus. */ /* #undef HAVE_DBUS */ -/* Define if the GNU dcgettext() function is already present or preinstalled. - */ +/* Define to 1 if you have the `dcgettext' function. */ /* #undef HAVE_DCGETTEXT */ -/* Define to 1 if you have the declaration of `feof_unlocked', and to 0 if you - don't. */ -/* #undef HAVE_DECL_FEOF_UNLOCKED */ - -/* Define to 1 if you have the declaration of `fgets_unlocked', and to 0 if - you don't. */ -/* #undef HAVE_DECL_FGETS_UNLOCKED */ - -/* Define to 1 if you have the declaration of `getc_unlocked', and to 0 if you - don't. */ -/* #undef HAVE_DECL_GETC_UNLOCKED */ - -/* Define to 1 if you have the declaration of `_snprintf', and to 0 if you - don't. */ -#define HAVE_DECL__SNPRINTF 1 - -/* Define to 1 if you have the declaration of `_snwprintf', and to 0 if you - don't. */ -#define HAVE_DECL__SNWPRINTF 1 +/* Define to 1 if you have the declaration of `tzname', and to 0 if you don't. + */ +/* #undef HAVE_DECL_TZNAME */ /* Define to 1 if you have the header file. */ /* #undef HAVE_DLFCN_H */ -/* Define to 1 if you have the `dlopen' function. */ -/* #undef HAVE_DLOPEN */ - /* whether or not we have dot */ /* #undef HAVE_DOT */ @@ -121,68 +62,28 @@ /* Define to 1 if you have the header file. */ #define HAVE_FCNTL_H 1 -/* Define to 1 if you have the `fwprintf' function. */ -#define HAVE_FWPRINTF 1 - /* Define to 1 if you have the getaddrinfo function. */ /* TODO: Use this on new enough versions of Windows */ /* #define HAVE_GETADDRINFO 1 */ -/* Define to 1 if you have the `getcwd' function. */ -#define HAVE_GETCWD 1 - -/* Define to 1 if you have the `getegid' function. */ -/* #define HAVE_GETEGID 1 */ - -/* Define to 1 if you have the `geteuid' function. */ -/* #define HAVE_GETEUID 1 */ - -/* Define to 1 if you have the `getgid' function. */ -/* #define HAVE_GETGID 1 */ - /* Define to 1 if you have the `gethostid' function. */ /* #define HAVE_GETHOSTID 1 */ /* Define to 1 if you have the `getopt_long' function. */ /* #define HAVE_GETOPT_LONG 1 */ -/* Define to 1 if you have the `getpagesize' function. */ -#define HAVE_GETPAGESIZE 1 - /* Define if the GNU gettext() function is already present or preinstalled. */ /* #define HAVE_GETTEXT 1 */ -/* Define to 1 if you have the `getuid' function. */ -/* #define HAVE_GETUID 1 */ - -/* Pidgin always has GLib, but Linphone can be built without it */ -/* #undef HAVE_GLIB */ - /* Define if you have GNUTLS */ /* #define HAVE_GNUTLS 1 */ /* Define to 1 if you have the header file. */ /* #define HAVE_GNUTLS_GNUTLS_H 1 */ -/* Define if you have the iconv() function. */ -/* #define HAVE_ICONV 1 */ - -/* Defined when we have ilbc codec lib */ -/* #undef HAVE_ILBC */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_ILBC_DECODE_H */ - -/* Define if you have the 'intmax_t' type in or . */ -#define HAVE_INTMAX_T 1 - /* Define if exists and doesn't clash with . */ #define HAVE_INTTYPES_H 1 -/* Define if exists, doesn't clash with , and - declares uintmax_t. */ -#define HAVE_INTTYPES_H_WITH_UINTMAX 1 - /* Define if we have IOKit */ /* #undef HAVE_IOKIT */ @@ -201,15 +102,15 @@ /* Define to 1 if you have the `krb_set_key' function. */ /* #undef HAVE_KRB_SET_KEY */ -/* Define if you have and nl_langinfo(CODESET). */ -/* #define HAVE_LANGINFO_CODESET 1 */ - /* Define if your file defines LC_MESSAGES. */ /* #define HAVE_LC_MESSAGES 1 */ /* Define to 1 if you have libgadu. */ #define HAVE_LIBGADU 1 +/* Define if you have NetworkManager */ +/* #undef HAVE_LIBNM */ + /* Define to 1 if you have the `nsl' library (-lnsl). */ /* #define HAVE_LIBNSL 1 */ @@ -219,24 +120,12 @@ /* Define to 1 if you have the `socket' library (-lsocket). */ /* #undef HAVE_LIBSOCKET */ -/* Define to 1 if you have the header file. */ -#define HAVE_LIMITS_H 1 - /* Define to 1 if you have the header file. */ #define HAVE_LOCALE_H 1 -/* Define if you have the 'long double' type. */ -#define HAVE_LONG_DOUBLE 1 - -/* Define if you have the 'long long' type. */ -#define HAVE_LONG_LONG 1 - /* Define to 1 if you have the `lrand48' function. */ /* #define HAVE_LRAND48 1 */ -/* Define to 1 if you have the header file. */ -/* #undef HAVE_MACHINE_SOUNDCARD_H */ - /* Define to 1 if you have the header file. */ #define HAVE_MALLOC_H 1 @@ -249,12 +138,6 @@ /* Define to 1 if you have the header file. */ #define HAVE_MEMORY_H 1 -/* Define to 1 if you have the `mempcpy' function. */ -/* #define HAVE_MEMPCPY 1*/ - -/* Define to 1 if you have a working `mmap' system call. */ -/* #define HAVE_MMAP 1 */ - /* Define to 1 if you have the `mono_jit_init' function. */ /* #undef HAVE_MONO_JIT_INIT */ @@ -264,12 +147,6 @@ /* Define to 1 if you have the header file. */ /* #undef HAVE_MONO_METADATA_OBJECT_H */ -/* Define to 1 if you have the `munmap' function. */ -/* #define HAVE_MUNMAP 1 */ - -/* Define to 1 if you have the header file. */ -/* #define HAVE_NL_TYPES_H 1 */ - /* Define to 1 if you have the header file. */ /* #undef HAVE_NSPR_H */ @@ -297,24 +174,15 @@ /* Define to 1 if you have the `perl_run' function. */ /* #define HAVE_PERL_RUN 1 */ -/* Define if your printf() function supports format strings with positions. */ -#define HAVE_POSIX_PRINTF 1 - /* Define to 1 if you have the header file. */ /* #undef HAVE_PRIO_H */ -/* Define to 1 if you have the `putenv' function. */ -#define HAVE_PUTENV 1 - /* Define to 1 if you have the `random' function. */ /* #define HAVE_RANDOM 1 */ /* Define to 1 if you have the header file. */ /* #define HAVE_REGEX_H 1 */ -/* Define to 1 if you have the `setenv' function. */ -/* #define HAVE_SETENV 1 */ - /* Define to 1 if you have the `setlocale' function. */ #define HAVE_SETLOCALE 1 @@ -333,12 +201,6 @@ /* Define to 1 if you have the `snprintf' function. */ #define HAVE_SNPRINTF 1 -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SOUNDCARD_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SPEEX_H */ - /* Define if you have SSL */ #define HAVE_SSL 1 @@ -351,25 +213,12 @@ /* Define to 1 if you have the header file. */ #define HAVE_STDARG_H 1 -/* Define to 1 if you have the header file. */ -#define HAVE_STDDEF_H 1 - /* Define to 1 if you have the header file. */ #define HAVE_STDINT_H 1 -/* Define if exists, doesn't clash with , and declares - uintmax_t. */ -#define HAVE_STDINT_H_WITH_UINTMAX 1 - /* Define to 1 if you have the header file. */ #define HAVE_STDLIB_H 1 -/* Define to 1 if you have the `stpcpy' function. */ -/* #define HAVE_STPCPY 1 */ - -/* Define to 1 if you have the `strcasecmp' function. */ -#define HAVE_STRCASECMP 1 - /* Define to 1 if you have the `strchr' function. */ #define HAVE_STRCHR 1 @@ -394,15 +243,9 @@ /* Define to 1 if you have the `strstr' function. */ #define HAVE_STRSTR 1 -/* Define to 1 if you have the `strtoul' function. */ -#define HAVE_STRTOUL 1 - /* Define to 1 if `tm_zone' is member of `struct tm'. */ /* #define HAVE_STRUCT_TM_TM_ZONE 1 */ -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_AUDIO_H */ - /* Define to 1 if you have the header file. */ /* #define HAVE_SYS_CDEFS_H 1 */ @@ -418,15 +261,9 @@ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_MSGBUF_H */ -/* Define to 1 if you have the header file. */ -/* #define HAVE_SYS_PARAM_H 1 */ - /* Define to 1 if you have the header file. */ /* #define HAVE_SYS_SELECT_H 1 */ -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_SOUNDCARD_H */ - /* Define to 1 if you have the header file. */ #define HAVE_SYS_STAT_H 1 @@ -464,61 +301,28 @@ `HAVE_STRUCT_TM_TM_ZONE' instead. */ /* #define HAVE_TM_ZONE 1 */ -/* Define to 1 if you have the `tsearch' function. */ -/* #define HAVE_TSEARCH 1 */ - /* Define to 1 if you don't have `tm_zone' but do have the external array `tzname'. */ /* #undef HAVE_TZNAME */ -/* Define if you have the 'uintmax_t' type in or . */ -#define HAVE_UINTMAX_T 1 - /* Define to 1 if you have the header file. */ #define HAVE_UNISTD_H 1 -/* Define if you have the 'unsigned long long' type. */ -#define HAVE_UNSIGNED_LONG_LONG 1 - /* Define to 1 if you have the `vprintf' function. */ #define HAVE_VPRINTF 1 -/* Compile with Voice/Video support */ -/* #undef HAVE_VV */ - -/* Define if you have the 'wchar_t' type. */ -#define HAVE_WCHAR_T 1 - -/* Define to 1 if you have the `wcslen' function. */ -#define HAVE_WCSLEN 1 - -/* Define if you have the 'wint_t' type. */ -#define HAVE_WINT_T 1 +/* Define to 1 if you have X11 */ +/* #define HAVE_X11 1 */ /* Define to 1 if you have the header file. */ /* #define HAVE_X11_SM_SMLIB_H 1 */ -/* Define to 1 if you have the `__argz_count' function. */ -/* #define HAVE___ARGZ_COUNT 1 */ - -/* Define to 1 if you have the `__argz_next' function. */ -/* #define HAVE___ARGZ_NEXT 1 */ - -/* Define to 1 if you have the `__argz_stringify' function. */ -/* #define HAVE___ARGZ_STRINGIFY 1 */ - -/* Define to 1 if you have the `__fsetlocking' function. */ -/* #define HAVE___FSETLOCKING 1 */ - -/* Define as const if the declaration of iconv() needs const. */ -/* #define ICONV_CONST */ - -/* Define if integer division by zero raises signal SIGFPE. */ -/* #define INTDIV0_RAISES_SIGFPE 1 */ - /* Define if external libzephyr should be used. */ /* #undef LIBZEPHYR_EXT */ +/* Define to 1 if you don't have wide-character support. */ +/* #undef NO_WIDECHAR */ + /* Define if old perl is installed. */ /* #undef OLD_PERL */ @@ -540,23 +344,17 @@ /* Define to the version of this package. */ /* #define PACKAGE_VERSION "2.0.0dev" */ -/* Define if exists and defines unusable PRI* macros. */ -/* #undef PRI_MACROS_BROKEN */ +/* Define to make assertions fatal (useful for debugging). */ +/* #define PURPLE_FATAL_ASSERTS 1 */ + +/* Define if plugins are enabled. */ +#define PURPLE_PLUGINS 1 /* Define as the return type of signal handlers (`int' or `void'). */ #define RETSIGTYPE void -/* Define as the maximum value of type 'size_t', if the system doesn't define - it. */ -/* #undef SIZE_MAX */ - -/* If using the C implementation of alloca, define if you know the - direction of stack growth for your system; otherwise it will be - automatically deduced at run-time. - STACK_DIRECTION > 0 => grows toward higher addresses - STACK_DIRECTION < 0 => grows toward lower addresses - STACK_DIRECTION = 0 => direction of growth unknown */ -/* #undef STACK_DIRECTION */ +/* The size of `time_t', as computed by sizeof. */ +#define SIZEOF_TIME_T 4 /* Loads static protocol plugin module initialization functions. */ #ifndef STATIC_PROTO_INIT @@ -569,10 +367,10 @@ /* Define to 1 if your declares `struct tm'. */ /* #undef TM_IN_SYS_TIME */ -/* Define if we're using libao and libaudiofile for sound playing */ -/* #define USE_AO 1 */ +/* Use GStreamer for playing sounds */ +/* #define USE_GSTREAMER 1 */ -/* do we have gtkspell? */ +/* Define if we're using GtkSpell */ #define USE_GTKSPELL 1 /* Define if we're using XScreenSaver. */ @@ -603,48 +401,14 @@ /* Define for large files, on AIX-style hosts. */ /* #undef _LARGE_FILES */ -/* Defined when alsa support is enabled */ -/* #undef __ALSA_ENABLED__ */ - -/* Jack support */ -/* #undef __JACK_ENABLED__ */ - /* Define to empty if `const' does not conform to ANSI C. */ /* #undef const */ -/* Define to `__inline__' or `__inline' if that's what the C compiler - calls it, or to nothing if 'inline' is not supported under any name. */ -#ifndef __cplusplus -/* #undef inline */ -#endif - -/* Define to `long' if does not define. */ -/* #undef off_t */ - -/* Define as the type of the result of subtracting two pointers, if the system - doesn't define it. */ -/* #undef ptrdiff_t */ - -/* Define to empty if the C compiler doesn't support this keyword. */ -/* #undef signed */ - -/* Define to `unsigned' if does not define. */ -/* #undef size_t */ - /* socklen_t size */ -/* #define socklen_t int */ - -/* Define to unsigned long or unsigned long long if and - don't define. */ -/* #undef uintmax_t */ - -#define HAVE_LIBXML 1 +/* #undef socklen_t */ /* * Following are added for Win32 version of Pidgin */ #define HAVE_VSNPRINTF 1 -#define SIZEOF_TIME_T 4 - -#define PIDGIN_NAME "Pidgin" diff -r e42309469a4a -r 618a3748ff64 configure.ac --- a/configure.ac Mon May 21 20:02:18 2007 +0000 +++ b/configure.ac Mon May 21 20:58:23 2007 +0000 @@ -139,6 +139,19 @@ ALL_LINGUAS="af am ar az bg bn bs ca ca@valencia cs da de dz el en_AU en_CA en_GB eo es et eu fa fi fr gl gu he hi hu id it ja ka kn ko ku lt mk my_MM nb ne nl nn pa pl pt_BR pt ps ro ru sk sl sq sr sr@Latn sv ta te th tr uk vi xh zh_CN zh_HK zh_TW" AM_GLIB_GNU_GETTEXT +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 +then + AC_ERROR([ + +The msgfmt command is required to build libpurple. If it is installed +on your system, ensure that it is in your path. If it is not, install +GNU gettext to continue. +]) +fi + dnl we don't use autobreak on cygwin!! dnl AC_CYGWIN @@ -892,22 +905,7 @@ AC_CHECK_HEADER(sys/utsname.h) AC_CHECK_FUNC(uname) -AC_ARG_ENABLE(fortify, [AC_HELP_STRING([--disable-fortify], [compile without FORTIFY_SOURCE support])], enable_fortify="$enableval", enable_fortify=yes) - -AC_ARG_ENABLE(mcheck, [AC_HELP_STRING([--enable-mcheck], [compile with mcheck (malloc debugging) support])], enable_mcheck="$enableval", enable_mcheck="$enable_debug") -if test "x$enable_mcheck" = "xyes" ; then - orig_LIBS="$LIBS" - LIBS="$LIBS -lmcheck" - AC_MSG_CHECKING(for mcheck support) - AC_TRY_COMPILE([], [ - int main() {return 0;} - ], [ - AC_MSG_RESULT(yes) - ], [ - AC_MSG_RESULT(no) - LIBS="$orig_LIBS" - ]) -fi +AC_ARG_ENABLE(fortify, [AC_HELP_STRING([--disable-fortify], [compile without FORTIFY_SOURCE support])], , enable_fortify=yes) if test "x$GCC" = "xyes"; then dnl We enable -Wall later. @@ -1987,16 +1985,11 @@ AC_ARG_ENABLE(debug, [AC_HELP_STRING([--enable-debug], [compile with debugging support])], , enable_debug=no) + if test "x$enable_debug" = "xyes" ; then AC_DEFINE(DEBUG, 1, [Define if debugging is enabled.]) fi -AC_ARG_ENABLE(fatal-asserts, [AC_HELP_STRING([--enable-fatal-asserts], - [make assertions fatal (useful for debugging)])], , enable_fatal_asserts=no) -if test "x$enable_fatal_asserts" = "xyes" ; then - AC_DEFINE(PURPLE_FATAL_ASSERTS, 1, [Define to make assertions fatal (useful for debugging).]) -fi - AC_OUTPUT([Makefile Doxyfile doc/Makefile @@ -2145,7 +2138,6 @@ echo Build with Tk support......... : $enable_tk echo echo Print debugging messages...... : $enable_debug -echo Assertions are fatal.......... : $enable_fatal_asserts echo eval eval echo Pidgin will be installed in $bindir. if test "x$pidginpath" != "x" ; then diff -r e42309469a4a -r 618a3748ff64 doc/finch.1.in --- a/doc/finch.1.in Mon May 21 20:02:18 2007 +0000 +++ b/doc/finch.1.in Mon May 21 20:58:23 2007 +0000 @@ -29,11 +29,12 @@ .SH DESCRIPTION .PP -\fBfinch\fR is a console-based modular messaging client capable of using -AIM, MSN, Yahoo!, XMPP, ICQ, IRC, SILC, Novell GroupWise, Lotus Sametime, -Zephyr, Gadu-Gadu, and QQ all at once. It has many common features found in -other clients, as well as many unique features. Finch is not endorsed by or -affiliated with America Online, ICQ, Microsoft, or Yahoo. +\fBfinch\fR is a console-based modular messaging client based on libpurple +which is capable of connecting to AIM, MSN, Yahoo!, XMPP, ICQ, IRC, SILC, +Novell GroupWise, Lotus Sametime, Zephyr, Gadu-Gadu, and QQ all at once. It has +many common features found in other clients, as well as many unique features. +Finch is not endorsed by or affiliated with America Online, ICQ, Microsoft, or +Yahoo. .SH OPTIONS The following options are provided by \fBfinch\fR using the standard GNU diff -r e42309469a4a -r 618a3748ff64 doc/pidgin.1.in --- a/doc/pidgin.1.in Mon May 21 20:02:18 2007 +0000 +++ b/doc/pidgin.1.in Mon May 21 20:58:23 2007 +0000 @@ -28,11 +28,12 @@ .SH DESCRIPTION .PP -Pidgin is a modular messaging client capable of using AIM, MSN, Yahoo!, XMPP, -ICQ, IRC, SILC, SIP/SIMPLE Novell GroupWise, Lotus Sametime, Bonjour, -Zephyr, Gadu-Gadu, and QQ all at once. It has many common features found in -other clients, as well as many unique features. Pidgin is not endorsed by or -affiliated with America Online, ICQ, Microsoft, or Yahoo. +\fBpidgin\fR is a graphical modular messaging client based on libpurple +which is capable of connecting to AIM, MSN, Yahoo!, XMPP, ICQ, IRC, SILC, +Novell GroupWise, Lotus Sametime, Zephyr, Gadu-Gadu, and QQ all at once. It has +many common features found in other clients, as well as many unique features. +Finch is not endorsed by or affiliated with America Online, ICQ, Microsoft, or +Yahoo. .SH OPTIONS The following options are provided by Pidgin using the standard GNU diff -r e42309469a4a -r 618a3748ff64 finch/finch.c --- a/finch/finch.c Mon May 21 20:02:18 2007 +0000 +++ b/finch/finch.c Mon May 21 20:58:23 2007 +0000 @@ -214,11 +214,6 @@ {0, 0, 0, 0} }; -#ifdef PURPLE_FATAL_ASSERTS - /* Make g_return_... functions fatal. */ - g_log_set_always_fatal(G_LOG_LEVEL_CRITICAL); -#endif - #ifdef ENABLE_NLS bindtextdomain(PACKAGE, LOCALEDIR); bind_textdomain_codeset(PACKAGE, "UTF-8"); @@ -274,7 +269,9 @@ } /* show version message */ if (opt_version) { - printf("%s v%s.\n", "Finch", VERSION); + /* Translators may want to transliterate the name. + It is not to be translated. */ + printf("%s %s\n", _("Finch"), VERSION); return 0; } @@ -303,7 +300,7 @@ char *text = g_strdup_printf(_( "%s encountered errors migrating your settings " "from %s to %s. Please investigate and complete the " - "migration by hand. Please report this error at http://developer.pidgin.im"), "Finch", + "migration by hand. Please report this error at http://developer.pidgin.im"), _("Finch"), old, purple_user_dir()); g_free(old); diff -r e42309469a4a -r 618a3748ff64 finch/gntaccount.c --- a/finch/gntaccount.c Mon May 21 20:02:18 2007 +0000 +++ b/finch/gntaccount.c Mon May 21 20:58:23 2007 +0000 @@ -930,11 +930,15 @@ static PurpleAccountUiOps ui_ops = { - .notify_added = notify_added, - .status_changed = NULL, - .request_add = request_add, - .request_authorize = finch_request_authorize, - .close_account_request = finch_request_close + notify_added, + NULL, + request_add, + finch_request_authorize, + finch_request_close, + NULL, + NULL, + NULL, + NULL }; PurpleAccountUiOps *finch_accounts_get_ui_ops() diff -r e42309469a4a -r 618a3748ff64 finch/gntblist.c --- a/finch/gntblist.c Mon May 21 20:02:18 2007 +0000 +++ b/finch/gntblist.c Mon May 21 20:58:23 2007 +0000 @@ -447,9 +447,13 @@ node_remove, NULL, NULL, - .request_add_buddy = finch_request_add_buddy, - .request_add_chat = finch_request_add_chat, - .request_add_group = finch_request_add_group + finch_request_add_buddy, + finch_request_add_chat, + finch_request_add_group, + NULL, + NULL, + NULL, + NULL }; static gpointer @@ -955,7 +959,7 @@ prompt = g_strdup_printf(_("Please enter the new name for %s"), name); - text = PURPLE_BLIST_NODE_IS_GROUP(node) ? _("Rename") : _("Alias"); + text = PURPLE_BLIST_NODE_IS_GROUP(node) ? _("Rename") : _("Set Alias"); purple_request_input(node, text, prompt, _("Enter empty string to reset the name."), name, FALSE, FALSE, NULL, text, G_CALLBACK(rename_blist_node), _("Cancel"), NULL, diff -r e42309469a4a -r 618a3748ff64 finch/gntconn.c --- a/finch/gntconn.c Mon May 21 20:02:18 2007 +0000 +++ b/finch/gntconn.c Mon May 21 20:58:23 2007 +0000 @@ -56,11 +56,17 @@ static PurpleConnectionUiOps ops = { - .connect_progress = NULL, - .connected = NULL, - .disconnected = NULL, - .notice = NULL, - .report_disconnect = finch_connection_report_disconnect + NULL, /* connect_progress */ + NULL, /* connected */ + NULL, /* disconnected */ + NULL, /* notice */ + finch_connection_report_disconnect, + NULL, /* network_connected */ + NULL, /* network_disconnected */ + NULL, + NULL, + NULL, + NULL }; PurpleConnectionUiOps *finch_connections_get_ui_ops() diff -r e42309469a4a -r 618a3748ff64 finch/gntconv.c --- a/finch/gntconv.c Mon May 21 20:02:18 2007 +0000 +++ b/finch/gntconv.c Mon May 21 20:58:23 2007 +0000 @@ -57,6 +57,9 @@ #include "config.h" +static void finch_write_common(PurpleConversation *conv, const char *who, + const char *message, PurpleMessageFlags flags, time_t mtime); + static void send_typing_notification(GntWidget *w, FinchConv *ggconv) { @@ -268,6 +271,13 @@ g_free(title); } +static void +chat_left_cb(PurpleConversation *conv, gpointer null) +{ + finch_write_common(conv, NULL, _("You have left this chat."), + PURPLE_MESSAGE_SYSTEM, time(NULL)); +} + static gpointer finch_conv_get_handle() { @@ -303,6 +313,11 @@ get_info_cb(GntMenuItem *item, gpointer ggconv) { FinchConv *ggc = ggconv; + PurpleNotifyUserInfo *info = purple_notify_user_info_new(); + purple_notify_user_info_add_pair(info, _("Information"), _("Retrieving...")); + purple_notify_userinfo(ggc->active_conv->account->gc, purple_conversation_get_name(ggc->active_conv), info, NULL, NULL); + purple_notify_user_info_destroy(info); + serv_get_info(purple_conversation_get_gc(ggc->active_conv), purple_conversation_get_name(ggc->active_conv)); } @@ -396,17 +411,26 @@ gnt_menuitem_set_callback(item, toggle_timestamps_cb, ggc); if (purple_conversation_get_type(ggc->active_conv) == PURPLE_CONV_TYPE_IM) { - item = gnt_menuitem_new(_("Send File")); - gnt_menu_add_item(GNT_MENU(sub), item); - gnt_menuitem_set_callback(item, send_file_cb, ggc); + PurpleAccount *account = purple_conversation_get_account(ggc->active_conv); + PurplePluginProtocolInfo *pinfo = account->gc ? PURPLE_PLUGIN_PROTOCOL_INFO(account->gc->prpl) : NULL; + + if (pinfo && pinfo->get_info) { + item = gnt_menuitem_new(_("Get Info")); + gnt_menu_add_item(GNT_MENU(sub), item); + gnt_menuitem_set_callback(item, get_info_cb, ggc); + } item = gnt_menuitem_new(_("Add Buddy Pounce...")); gnt_menu_add_item(GNT_MENU(sub), item); gnt_menuitem_set_callback(item, add_pounce_cb, ggc); - item = gnt_menuitem_new(_("Get Info")); - gnt_menu_add_item(GNT_MENU(sub), item); - gnt_menuitem_set_callback(item, get_info_cb, ggc); + if (pinfo && pinfo->send_file && + (!pinfo->can_receive_file || + pinfo->can_receive_file(account->gc, purple_conversation_get_name(ggc->active_conv)))) { + item = gnt_menuitem_new(_("Send File")); + gnt_menu_add_item(GNT_MENU(sub), item); + gnt_menuitem_set_callback(item, send_file_cb, ggc); + } generate_send_to_menu(ggc); } @@ -469,7 +493,8 @@ FinchConvChat *fc = ggc->u.chat = g_new0(FinchConvChat, 1); hbox = gnt_hbox_new(FALSE); gnt_box_set_pad(GNT_BOX(hbox), 0); - tree = fc->userlist = gnt_tree_new(); + tree = fc->userlist = gnt_tree_new_with_columns(2); + gnt_tree_set_col_width(GNT_TREE(tree), 0, 1); /* The flag column */ gnt_tree_set_compare_func(GNT_TREE(tree), (GCompareFunc)g_utf8_collate); gnt_tree_set_hash_fns(GNT_TREE(tree), g_str_hash, g_str_equal, g_free); GNT_WIDGET_SET_FLAGS(tree, GNT_WIDGET_NO_BORDER); @@ -505,10 +530,6 @@ if (type == PURPLE_CONV_TYPE_IM) { g_signal_connect(G_OBJECT(ggc->entry), "text_changed", G_CALLBACK(send_typing_notification), ggc); - purple_signal_connect(purple_conversations_get_handle(), "buddy-typing", finch_conv_get_handle(), - PURPLE_CALLBACK(update_buddy_typing), NULL); - purple_signal_connect(purple_conversations_get_handle(), "buddy-typing-stopped", finch_conv_get_handle(), - PURPLE_CALLBACK(update_buddy_typing), NULL); } g_free(title); @@ -655,6 +676,20 @@ finch_write_common(conv, name, message, flags, mtime); } +static const char * +chat_flag_text(PurpleConvChatBuddyFlags flags) +{ + if (flags & PURPLE_CBFLAGS_FOUNDER) + return "~"; + if (flags & PURPLE_CBFLAGS_OP) + return "@"; + if (flags & PURPLE_CBFLAGS_HALFOP) + return "%"; + if (flags & PURPLE_CBFLAGS_VOICE) + return "+"; + return " "; +} + static void finch_chat_add_users(PurpleConversation *conv, GList *users, gboolean new_arrivals) { @@ -689,7 +724,7 @@ gnt_entry_add_suggest(entry, cbuddy->name); gnt_entry_add_suggest(entry, cbuddy->alias); gnt_tree_add_row_after(tree, g_strdup(cbuddy->name), - gnt_tree_create_row(tree, cbuddy->alias), NULL, NULL); + gnt_tree_create_row(tree, chat_flag_text(cbuddy->flags), cbuddy->alias), NULL, NULL); } } @@ -700,16 +735,19 @@ FinchConv *ggc = conv->ui_data; GntEntry *entry = GNT_ENTRY(ggc->entry); GntTree *tree = GNT_TREE(ggc->u.chat->userlist); + PurpleConvChatBuddy *cb = purple_conv_chat_cb_find(PURPLE_CONV_CHAT(conv), new_n); + gnt_entry_remove_suggest(entry, old); + gnt_tree_remove(tree, (gpointer)old); + gnt_entry_add_suggest(entry, new_n); gnt_entry_add_suggest(entry, new_a); - gnt_tree_remove(tree, (gpointer)old); gnt_tree_add_row_after(tree, g_strdup(new_n), - gnt_tree_create_row(tree, new_a), NULL, NULL); + gnt_tree_create_row(tree, chat_flag_text(cb->flags), new_a), NULL, NULL); } static void -finch_chat_remove_user(PurpleConversation *conv, GList *list) +finch_chat_remove_users(PurpleConversation *conv, GList *list) { /* Remove the name from string completion */ FinchConv *ggc = conv->ui_data; @@ -724,24 +762,32 @@ static void finch_chat_update_user(PurpleConversation *conv, const char *user) { + PurpleConvChatBuddy *cb = purple_conv_chat_cb_find(PURPLE_CONV_CHAT(conv), user); + FinchConv *ggc = conv->ui_data; + gnt_tree_change_text(GNT_TREE(ggc->u.chat->userlist), (gpointer)user, 0, chat_flag_text(cb->flags)); } static PurpleConversationUiOps conv_ui_ops = { - .create_conversation = finch_create_conversation, - .destroy_conversation = finch_destroy_conversation, - .write_chat = finch_write_chat, - .write_im = finch_write_im, - .write_conv = finch_write_conv, - .chat_add_users = finch_chat_add_users, - .chat_rename_user = finch_chat_rename_user, - .chat_remove_users = finch_chat_remove_user, - .chat_update_user = finch_chat_update_user, - .present = NULL, - .has_focus = NULL, - .custom_smiley_add = NULL, - .custom_smiley_write = NULL, - .custom_smiley_close = NULL + finch_create_conversation, + finch_destroy_conversation, + finch_write_chat, + finch_write_im, + finch_write_conv, + finch_chat_add_users, + finch_chat_rename_user, + finch_chat_remove_users, + finch_chat_update_user, + NULL, /* present */ + NULL, /* has_focus */ + NULL, /* custom_smiley_add */ + NULL, /* custom_smiley_write */ + NULL, /* custom_smiley_close */ + NULL, /* send_confirm */ + NULL, + NULL, + NULL, + NULL }; PurpleConversationUiOps *finch_conv_get_ui_ops() @@ -930,10 +976,18 @@ purple_cmd_register("status", "", PURPLE_CMD_P_DEFAULT, PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_IM, NULL, cmd_show_window, _("statuses: Show the savedstatuses window."), finch_savedstatus_show_all); + + purple_signal_connect(purple_conversations_get_handle(), "buddy-typing", finch_conv_get_handle(), + PURPLE_CALLBACK(update_buddy_typing), NULL); + purple_signal_connect(purple_conversations_get_handle(), "buddy-typing-stopped", finch_conv_get_handle(), + PURPLE_CALLBACK(update_buddy_typing), NULL); + purple_signal_connect(purple_conversations_get_handle(), "chat-left", finch_conv_get_handle(), + PURPLE_CALLBACK(chat_left_cb), NULL); } void finch_conversation_uninit() { + purple_signals_disconnect_by_handle(finch_conv_get_handle()); } void finch_conversation_set_active(PurpleConversation *conv) diff -r e42309469a4a -r 618a3748ff64 finch/gntdebug.c --- a/finch/gntdebug.c Mon May 21 20:02:18 2007 +0000 +++ b/finch/gntdebug.c Mon May 21 20:58:23 2007 +0000 @@ -24,10 +24,12 @@ */ #include #include -#include #include #include +#include +#include #include +#include #include "gntdebug.h" #include "finch.h" @@ -42,26 +44,36 @@ { GntWidget *window; GntWidget *tview; + GntWidget *search; gboolean paused; - gboolean timestamps; } debug; +static gboolean +match_string(const char *category, const char *args) +{ + const char *str = gnt_entry_get_text(GNT_ENTRY(debug.search)); + if (!str || !*str) + return TRUE; + if (g_strrstr(category, str) != NULL) + return TRUE; + if (g_strrstr(args, str) != NULL) + return TRUE; + return FALSE; +} + static void finch_debug_print(PurpleDebugLevel level, const char *category, const char *args) { - if (debug.window && !debug.paused) + if (debug.window && !debug.paused && match_string(category, args)) { int pos = gnt_text_view_get_lines_below(GNT_TEXT_VIEW(debug.tview)); GntTextFormatFlags flag = GNT_TEXT_FLAG_NORMAL; - - if (debug.timestamps) { - const char *mdate; - time_t mtime = time(NULL); - mdate = purple_utf8_strftime("%H:%M:%S ", localtime(&mtime)); - gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(debug.tview), - mdate, flag); - } + const char *mdate; + time_t mtime = time(NULL); + mdate = purple_utf8_strftime("%H:%M:%S ", localtime(&mtime)); + gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(debug.tview), + mdate, flag); gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(debug.tview), category, GNT_TEXT_FLAG_BOLD); @@ -112,7 +124,7 @@ static void reset_debug_win(GntWidget *w, gpointer null) { - debug.window = debug.tview = NULL; + debug.window = debug.tview = debug.search = NULL; } static void @@ -137,13 +149,6 @@ debug.paused = !debug.paused; } -static void -toggle_timestamps(GntWidget *w, gpointer n) -{ - debug.timestamps = !debug.timestamps; - purple_prefs_set_bool("/purple/debug/timestamps", debug.timestamps); -} - /* Xerox */ static void purple_glib_log_handler(const gchar *domain, GLogLevelFlags flags, @@ -199,10 +204,24 @@ purple_prefs_set_int(PREF_ROOT "/size/height", h); } +static gboolean +for_real(gpointer entry) +{ + purple_prefs_set_string(PREF_ROOT "/filter", gnt_entry_get_text(entry)); + return FALSE; +} + +static void +update_filter_string(GntEntry *entry, gpointer null) +{ + int id = g_timeout_add(1000, for_real, entry); + g_object_set_data_full(G_OBJECT(entry), "update-filter", GINT_TO_POINTER(id), + (GDestroyNotify)g_source_remove); +} + void finch_debug_window_show() { debug.paused = FALSE; - debug.timestamps = purple_prefs_get_bool("/purple/debug/timestamps"); if (debug.window == NULL) { GntWidget *wid, *box; @@ -234,17 +253,16 @@ GNT_WIDGET_SET_FLAGS(wid, GNT_WIDGET_GROW_Y); gnt_box_add_widget(GNT_BOX(box), wid); + debug.search = gnt_entry_new(purple_prefs_get_string(PREF_ROOT "/filter")); + gnt_box_add_widget(GNT_BOX(box), gnt_label_new(_("Filter: "))); + gnt_box_add_widget(GNT_BOX(box), debug.search); + g_signal_connect(G_OBJECT(debug.search), "text_changed", G_CALLBACK(update_filter_string), NULL); + wid = gnt_check_box_new(_("Pause")); g_signal_connect(G_OBJECT(wid), "toggled", G_CALLBACK(toggle_pause), NULL); GNT_WIDGET_SET_FLAGS(wid, GNT_WIDGET_GROW_Y); gnt_box_add_widget(GNT_BOX(box), wid); - wid = gnt_check_box_new(_("Timestamps")); - gnt_check_box_set_checked(GNT_CHECK_BOX(wid), debug.timestamps); - g_signal_connect(G_OBJECT(wid), "toggled", G_CALLBACK(toggle_timestamps), NULL); - GNT_WIDGET_SET_FLAGS(wid, GNT_WIDGET_GROW_Y); - gnt_box_add_widget(GNT_BOX(box), wid); - gnt_box_add_widget(GNT_BOX(debug.window), box); GNT_WIDGET_SET_FLAGS(box, GNT_WIDGET_GROW_Y); @@ -283,6 +301,7 @@ g_set_printerr_handler(suppress_error_messages); purple_prefs_add_none(PREF_ROOT); + purple_prefs_add_string(PREF_ROOT "/filter", ""); purple_prefs_add_none(PREF_ROOT "/size"); purple_prefs_add_int(PREF_ROOT "/size/width", 60); purple_prefs_add_int(PREF_ROOT "/size/height", 15); diff -r e42309469a4a -r 618a3748ff64 finch/gntnotify.c --- a/finch/gntnotify.c Mon May 21 20:02:18 2007 +0000 +++ b/finch/gntnotify.c Mon May 21 20:58:23 2007 +0000 @@ -405,17 +405,21 @@ static PurpleNotifyUiOps ops = { - .notify_message = finch_notify_message, - .close_notify = finch_close_notify, /* The rest of the notify-uiops return a GntWidget. - These widgets should be destroyed from here. */ - .notify_formatted = finch_notify_formatted, - .notify_email = finch_notify_email, - .notify_emails = finch_notify_emails, - .notify_userinfo = finch_notify_userinfo, + finch_notify_message, + finch_notify_email, + finch_notify_emails, + finch_notify_formatted, + finch_notify_searchresults, + finch_notify_sr_new_rows, + finch_notify_userinfo, + NULL, /* notify_uri is of low-priority to me. --sadrul */ + finch_close_notify, /* The rest of the notify-uiops return a GntWidget. + These widgets should be destroyed from here. */ + NULL, + NULL, + NULL, + NULL - .notify_searchresults = finch_notify_searchresults, - .notify_searchresults_new_rows = finch_notify_sr_new_rows, - .notify_uri = NULL /* This is of low-priority to me */ }; PurpleNotifyUiOps *finch_notify_get_ui_ops() diff -r e42309469a4a -r 618a3748ff64 finch/gntplugin.c --- a/finch/gntplugin.c Mon May 21 20:02:18 2007 +0000 +++ b/finch/gntplugin.c Mon May 21 20:58:23 2007 +0000 @@ -67,11 +67,10 @@ static void plugin_toggled_cb(GntWidget *tree, PurplePlugin *plugin, gpointer null) { - /* TODO: Mark these strings for translation after the freeze */ if (gnt_tree_get_choice(GNT_TREE(tree), plugin)) { if (!purple_plugin_load(plugin)) { - purple_notify_error(NULL, "ERROR", "loading plugin failed", NULL); + purple_notify_error(NULL, _("ERROR"), _("loading plugin failed"), NULL); gnt_tree_set_choice(GNT_TREE(tree), plugin, FALSE); } } @@ -80,7 +79,7 @@ GntWidget *win; if (!purple_plugin_unload(plugin)) { - purple_notify_error(NULL, "ERROR", "unloading plugin failed", NULL); + purple_notify_error(NULL, _("ERROR"), _("unloading plugin failed"), NULL); gnt_tree_set_choice(GNT_TREE(tree), plugin, TRUE); } @@ -105,6 +104,20 @@ { PurplePlugin *plugin = current; char *text; + GList *list = NULL, *iter = NULL; + + /* If the selected plugin was unseen before, mark it as seen. But save the list + * only when the plugin list is closed. So if the user enables a plugin, and it + * crashes, it won't get marked as seen so the user can fix the bug and still + * quickly find the plugin in the list. + * I probably mean 'plugin developers' by 'users' here. */ + list = g_object_get_data(G_OBJECT(widget), "seen-list"); + if (list) + iter = g_list_find_custom(list, plugin->path, (GCompareFunc)strcmp); + if (!iter) { + list = g_list_prepend(list, g_strdup(plugin->path)); + g_object_set_data(G_OBJECT(widget), "seen-list", list); + } /* XXX: Use formatting and stuff */ gnt_text_view_clear(GNT_TEXT_VIEW(plugins.aboot)); @@ -121,6 +134,11 @@ static void reset_plugin_window(GntWidget *window, gpointer null) { + GList *list = g_object_get_data(G_OBJECT(plugins.tree), "seen-list"); + purple_prefs_set_path_list("/finch/plugins/seen", list); + g_list_foreach(list, (GFunc)g_free, NULL); + g_list_free(list); + plugins.window = NULL; plugins.tree = NULL; plugins.aboot = NULL; @@ -214,6 +232,8 @@ { GntWidget *window, *tree, *box, *aboot, *button; GList *iter; + GList *seen; + if (plugins.window) return; @@ -244,6 +264,7 @@ gnt_widget_set_size(aboot, 40, 20); gnt_box_add_widget(GNT_BOX(box), aboot); + seen = purple_prefs_get_path_list("/finch/plugins/seen"); for (iter = purple_plugins_get_all(); iter; iter = iter->next) { PurplePlugin *plug = iter->data; @@ -256,10 +277,13 @@ gnt_tree_add_choice(GNT_TREE(tree), plug, gnt_tree_create_row(GNT_TREE(tree), plug->info->name), NULL, NULL); gnt_tree_set_choice(GNT_TREE(tree), plug, purple_plugin_is_loaded(plug)); + if (!g_list_find_custom(seen, plug->path, (GCompareFunc)strcmp)) + gnt_tree_set_row_flags(GNT_TREE(tree), plug, GNT_TEXT_FLAG_BOLD); } gnt_tree_set_col_width(GNT_TREE(tree), 0, 30); g_signal_connect(G_OBJECT(tree), "toggled", G_CALLBACK(plugin_toggled_cb), NULL); g_signal_connect(G_OBJECT(tree), "selection_changed", G_CALLBACK(selection_changed), NULL); + g_object_set_data(G_OBJECT(tree), "seen-list", seen); box = gnt_hbox_new(FALSE); gnt_box_add_widget(GNT_BOX(window), box); diff -r e42309469a4a -r 618a3748ff64 finch/gntprefs.c --- a/finch/gntprefs.c Mon May 21 20:02:18 2007 +0000 +++ b/finch/gntprefs.c Mon May 21 20:58:23 2007 +0000 @@ -39,6 +39,7 @@ purple_prefs_add_none("/finch/plugins"); purple_prefs_add_path_list("/finch/plugins/loaded", NULL); + purple_prefs_add_path_list("/finch/plugins/seen", NULL); purple_prefs_add_none("/finch/conversations"); purple_prefs_add_bool("/finch/conversations/timestamps", TRUE); @@ -75,7 +76,7 @@ get_idle_options() { GList *list = NULL; - list = g_list_append(list, "Based on keyboard use"); /* XXX: string freeze */ + list = g_list_append(list, (char *)_("Based on keyboard use")); list = g_list_append(list, "system"); list = g_list_append(list, (char*)_("From last sent message")); list = g_list_append(list, "purple"); diff -r e42309469a4a -r 618a3748ff64 finch/gntrequest.c --- a/finch/gntrequest.c Mon May 21 20:02:18 2007 +0000 +++ b/finch/gntrequest.c Mon May 21 20:58:23 2007 +0000 @@ -612,13 +612,17 @@ static PurpleRequestUiOps uiops = { - .request_input = finch_request_input, - .close_request = finch_close_request, - .request_choice = finch_request_choice, - .request_action = finch_request_action, - .request_fields = finch_request_fields, - .request_file = finch_request_file, - .request_folder = NULL /* No plans for this */ + finch_request_input, + finch_request_choice, + finch_request_action, + finch_request_fields, + finch_request_file, + finch_close_request, + NULL, /* No plans for request_folder */ + NULL, + NULL, + NULL, + NULL }; PurpleRequestUiOps *finch_request_get_ui_ops() diff -r e42309469a4a -r 618a3748ff64 finch/libgnt/Makefile.am --- a/finch/libgnt/Makefile.am Mon May 21 20:02:18 2007 +0000 +++ b/finch/libgnt/Makefile.am Mon May 21 20:58:23 2007 +0000 @@ -66,10 +66,10 @@ gntmarshal.c: $(srcdir)/genmarshal gntmarshal.h echo "#include \"gntmarshal.h\"" > $@ - cat $(srcdir)/genmarshal | glib-genmarshal --prefix=gnt_closure_marshal --body >> $@ + glib-genmarshal --prefix=gnt_closure_marshal --body $(srcdir)/genmarshal >> $@ gntmarshal.h: $(srcdir)/genmarshal - cat $(srcdir)/genmarshal | glib-genmarshal --prefix=gnt_closure_marshal --header > $@ + glib-genmarshal --prefix=gnt_closure_marshal --header $(srcdir)/genmarshal > $@ libgnt_laincludedir=$(includedir)/gnt libgnt_lainclude_HEADERS = \ diff -r e42309469a4a -r 618a3748ff64 finch/libgnt/gntmain.c --- a/finch/libgnt/gntmain.c Mon May 21 20:02:18 2007 +0000 +++ b/finch/libgnt/gntmain.c Mon May 21 20:58:23 2007 +0000 @@ -144,8 +144,8 @@ event = GNT_MOUSE_UP; } else return FALSE; - - if (gnt_wm_process_click(wm, event, x, y, widget)) + + if (widget && gnt_wm_process_click(wm, event, x, y, widget)) return TRUE; if (event == GNT_LEFT_MOUSE_DOWN && widget && widget != wm->_list.window && @@ -177,7 +177,8 @@ offset = 0; } - gnt_widget_clicked(widget, event, x, y); + if (widget) + gnt_widget_clicked(widget, event, x, y); return TRUE; } @@ -348,6 +349,10 @@ gnt_wm_raise_window(wm, win); } +#ifdef SIGWINCH +static void (*org_winch_handler)(int); +#endif + static void sighandler(int sig) { @@ -357,6 +362,7 @@ werase(stdscr); wrefresh(stdscr); g_idle_add(refresh_screen, NULL); + org_winch_handler(sig); signal(SIGWINCH, sighandler); break; #endif @@ -434,7 +440,7 @@ wrefresh(stdscr); #ifdef SIGWINCH - signal(SIGWINCH, sighandler); + org_winch_handler = signal(SIGWINCH, sighandler); #endif signal(SIGCHLD, sighandler); signal(SIGINT, sighandler); diff -r e42309469a4a -r 618a3748ff64 finch/libgnt/gntwm.c --- a/finch/libgnt/gntwm.c Mon May 21 20:02:18 2007 +0000 +++ b/finch/libgnt/gntwm.c Mon May 21 20:58:23 2007 +0000 @@ -48,6 +48,10 @@ static void update_window_in_list(GntWM *wm, GntWidget *wid); static void shift_window(GntWM *wm, GntWidget *widget, int dir); +#ifndef NO_WIDECHAR +static int widestringwidth(wchar_t *wide); +#endif + static gboolean write_already(gpointer data); static int write_timeout; static time_t last_active_time; @@ -136,6 +140,65 @@ copywin(src, dst, node->scroll, 0, 0, 0, getmaxy(dst) - 1, getmaxx(dst) - 1, 0); } +/** + * The following is a workaround for a bug in most versions of ncursesw. + * Read about it in: http://article.gmane.org/gmane.comp.lib.ncurses.bugs/2751 + * + * In short, if a panel hides one cell of a multi-cell character, then the rest + * of the characters in that line get screwed. The workaround here is to erase + * any such character preemptively. + * + * Caveat: If a wide character is erased, and the panel above it is moved enough + * to expose the entire character, it is not always redrawn. + */ +static void +work_around_for_ncurses_bug() +{ +#ifndef NO_WIDECHAR + PANEL *panel = NULL; + while ((panel = panel_below(panel)) != NULL) { + int sx, ex, sy, ey, w, y; + cchar_t ch; + PANEL *below = panel; + + sx = panel->win->_begx; + ex = panel->win->_maxx + sx; + sy = panel->win->_begy; + ey = panel->win->_maxy + sy; + + while ((below = panel_below(below)) != NULL) { + if (sy > below->win->_begy + below->win->_maxy || + ey < below->win->_begy) + continue; + if (sx > below->win->_begx + below->win->_maxx || + ex < below->win->_begx) + continue; + for (y = MAX(sy, below->win->_begy); y <= MIN(ey, below->win->_begy + below->win->_maxy); y++) { + if (mvwin_wch(below->win, y - below->win->_begy, sx - 1 - below->win->_begx, &ch) != OK) + goto right; + w = widestringwidth(ch.chars); + if (w > 1 && (ch.attr & 1)) { + ch.chars[0] = ' '; + ch.attr &= ~ A_CHARTEXT; + mvwadd_wch(below->win, y - below->win->_begy, sx - 1 - below->win->_begx, &ch); + touchline(below->win, y - below->win->_begy, 1); + } +right: + if (mvwin_wch(below->win, y - below->win->_begy, ex + 1 - below->win->_begx, &ch) != OK) + continue; + w = widestringwidth(ch.chars); + if (w > 1 && !(ch.attr & 1)) { + ch.chars[0] = ' '; + ch.attr &= ~ A_CHARTEXT; + mvwadd_wch(below->win, y - below->win->_begy, ex + 1 - below->win->_begx, &ch); + touchline(below->win, y - below->win->_begy, 1); + } + } + } + } +#endif +} + static gboolean update_screen(GntWM *wm) { @@ -148,6 +211,7 @@ top = top->submenu; } } + work_around_for_ncurses_bug(); update_panels(); doupdate(); return TRUE; @@ -564,14 +628,40 @@ int x, y; chtype old = 0, now = 0; FILE *file = fopen("dump.html", "w"); + struct { + char ascii; + char *unicode; + } unis[] = { + {'q', "─"}, + {'t', "├"}, + {'u', "┤"}, + {'x', "│"}, + {'-', "↑"}, + {'.', "↓"}, + {'l', "┌"}, + {'k', "┐"}, + {'m', "└"}, + {'j', "┘"}, + {'a', "▒"}, + {'\0', NULL} + }; + fprintf(file, "\n \n\n\n"); fprintf(file, "
");
 	for (y = 0; y < getmaxy(stdscr); y++) {
 		for (x = 0; x < getmaxx(stdscr); x++) {
-			char ch;
+			char ch[2] = {0, 0}, *print;
+#ifdef NO_WIDECHAR
 			now = mvwinch(curscr, y, x);
-			ch = now & A_CHARTEXT;
-			now ^= ch;
+			ch[0] = now & A_CHARTEXT;
+			now ^= ch[0];
+#else
+			cchar_t wch;
+			char unicode[12];
+			mvwin_wch(curscr, y, x, &wch);
+			now = wch.attr;
+			ch[0] = (char)(wch.chars[0] & 0xff);
+#endif
 
 #define CHECK(attr, start, end) \
 			do \
@@ -607,7 +697,11 @@
 				if (bgp == -1)
 					bgp = COLOR_WHITE;
 				if (now & A_REVERSE)
-					fgp ^= bgp ^= fgp ^= bgp;  /* *wink* */
+				{
+					short tmp = fgp;
+					fgp = bgp;
+					bgp = tmp;
+				}
 				ret = color_content(fgp, &r, &g, &b);
 				fg.r = r; fg.b = b; fg.g = g;
 				ret = color_content(bgp, &r, &g, &b);
@@ -624,48 +718,39 @@
 				fprintf(file, "",
 						bg.r, bg.g, bg.b, fg.r, fg.g, fg.b);
 			}
+			print = ch;
+#ifndef NO_WIDECHAR
+			if (wch.chars[0] > 255) {
+				snprintf(unicode, sizeof(unicode), "&#x%x;", wch.chars[0]);
+				print = unicode;
+			}
+#endif
 			if (now & A_ALTCHARSET)
 			{
-				switch (ch)
-				{
-					case 'q':
-						ch = '-'; break;
-					case 't':
-					case 'u':
-					case 'x':
-						ch = '|'; break;
-					case 'v':
-					case 'w':
-					case 'l':
-					case 'm':
-					case 'k':
-					case 'j':
-					case 'n':
-						ch = '+'; break;
-					case '-':
-						ch = '^'; break;
-					case '.':
-						ch = 'v'; break;
-					case 'a':
-						ch = '#'; break;
-					default:
-						ch = ' '; break;
+				int u;
+				for (u = 0; unis[u].ascii; u++) {
+					if (ch[0] == unis[u].ascii) {
+						print = unis[u].unicode;
+						break;
+					}
 				}
+				if (!unis[u].ascii)
+					print = " ";
 			}
-			if (ch == '&')
+			if (ch[0] == '&')
 				fprintf(file, "&");
-			else if (ch == '<')
+			else if (ch[0] == '<')
 				fprintf(file, "<");
-			else if (ch == '>')
+			else if (ch[0] == '>')
 				fprintf(file, ">");
 			else
-				fprintf(file, "%c", ch);
+				fprintf(file, "%s", print);
 			old = now;
 		}
 		fprintf(file, "\n");
 		old = 0;
 	}
-	fprintf(file, "
"); + fprintf(file, "\n"); fclose(file); return TRUE; } diff -r e42309469a4a -r 618a3748ff64 finch/plugins/gntgf.c --- a/finch/plugins/gntgf.c Mon May 21 20:02:18 2007 +0000 +++ b/finch/plugins/gntgf.c Mon May 21 20:58:23 2007 +0000 @@ -56,7 +56,8 @@ #include #include -#include +#include "gntplugin.h" +#include "gntconv.h" typedef struct { @@ -154,7 +155,7 @@ #endif static void -notify(const char *fmt, ...) +notify(PurpleConversation *conv, const char *fmt, ...) { GntWidget *window; GntToast *toast; @@ -164,6 +165,13 @@ if (purple_prefs_get_bool(PREFS_BEEP)) beep(); + + if (conv != NULL) { + FinchConv *fc = conv->ui_data; + if (gnt_widget_has_focus(fc->window)) + return; + } + #ifdef HAVE_X11 if (purple_prefs_get_bool(PREFS_URGENT)) urgent(); @@ -220,14 +228,14 @@ buddy_signed_on(PurpleBuddy *buddy, gpointer null) { if (purple_prefs_get_bool(PREFS_EVENT_SIGNONF)) - notify(_("%s just signed on"), purple_buddy_get_alias(buddy)); + notify(NULL, _("%s just signed on"), purple_buddy_get_alias(buddy)); } static void buddy_signed_off(PurpleBuddy *buddy, gpointer null) { if (purple_prefs_get_bool(PREFS_EVENT_SIGNONF)) - notify(_("%s just signed off"), purple_buddy_get_alias(buddy)); + notify(NULL, _("%s just signed off"), purple_buddy_get_alias(buddy)); } static void @@ -235,7 +243,7 @@ PurpleConversation *conv, PurpleMessageFlags flags, gpointer null) { if (purple_prefs_get_bool(PREFS_EVENT_IM_MSG)) - notify(_("%s sent you a message"), sender); + notify(conv, _("%s sent you a message"), sender); } static void @@ -254,9 +262,9 @@ if (purple_prefs_get_bool(PREFS_EVENT_CHAT_NICK) && (purple_utf8_has_word(msg, nick))) - notify(_("%s said your nick in %s"), sender, purple_conversation_get_name(conv)); + notify(conv, _("%s said your nick in %s"), sender, purple_conversation_get_name(conv)); else if (purple_prefs_get_bool(PREFS_EVENT_CHAT_MSG)) - notify(_("%s sent a message in %s"), sender, purple_conversation_get_name(conv)); + notify(conv, _("%s sent a message in %s"), sender, purple_conversation_get_name(conv)); } static gboolean diff -r e42309469a4a -r 618a3748ff64 libpurple/Makefile.am --- a/libpurple/Makefile.am Mon May 21 20:02:18 2007 +0000 +++ b/libpurple/Makefile.am Mon May 21 20:58:23 2007 +0000 @@ -151,7 +151,7 @@ dbus_headers = dbus-bindings.h dbus-purple.h dbus-server.h dbus-useful.h dbus-define-api.h dbus_exported = dbus-useful.h dbus-define-api.h account.h blist.h buddyicon.h \ - connection.h conversation.h core.h log.h prefs.h roomlist.h \ + connection.h conversation.h core.h log.h notify.h prefs.h roomlist.h \ savedstatuses.h status.h server.h util.h xmlnode.h purple_build_coreheaders = $(addprefix $(srcdir)/, $(purple_coreheaders)) diff -r e42309469a4a -r 618a3748ff64 libpurple/account.c --- a/libpurple/account.c Mon May 21 20:02:18 2007 +0000 +++ b/libpurple/account.c Mon May 21 20:58:23 2007 +0000 @@ -548,9 +548,9 @@ data = xmlnode_get_attrib(node, "active"); if (data == NULL) return; - if (strcasecmp(data, "true") == 0) + if (g_ascii_strcasecmp(data, "true") == 0) active = TRUE; - else if (strcasecmp(data, "false") == 0) + else if (g_ascii_strcasecmp(data, "false") == 0) active = FALSE; else return; diff -r e42309469a4a -r 618a3748ff64 libpurple/buddyicon.c --- a/libpurple/buddyicon.c Mon May 21 20:02:18 2007 +0000 +++ b/libpurple/buddyicon.c Mon May 21 20:58:23 2007 +0000 @@ -416,7 +416,7 @@ } ref_filename(filename); } - else + else if (!icon->img) { purple_blist_node_remove_setting((PurpleBlistNode *)buddy, "buddy_icon"); purple_blist_node_remove_setting((PurpleBlistNode *)buddy, "icon_checksum"); diff -r e42309469a4a -r 618a3748ff64 libpurple/cipher.c --- a/libpurple/cipher.c Mon May 21 20:02:18 2007 +0000 +++ b/libpurple/cipher.c Mon May 21 20:58:23 2007 +0000 @@ -1275,6 +1275,175 @@ }; /******************************************************************************* + * RC4 + ******************************************************************************/ + +struct RC4Context { + guchar state[256]; + guchar x; + guchar y; + gint key_len; +}; + +static void +rc4_init(PurpleCipherContext *context, void *extra) { + struct RC4Context *rc4_ctx; + rc4_ctx = g_new0(struct RC4Context, 1); + purple_cipher_context_set_data(context, rc4_ctx); + purple_cipher_context_reset(context, extra); +} + + +static void +rc4_reset(PurpleCipherContext *context, void *extra) { + struct RC4Context *rc4_ctx; + guint i; + + rc4_ctx = purple_cipher_context_get_data(context); + + g_return_if_fail(rc4_ctx); + + for(i = 0; i < 256; i++) + rc4_ctx->state[i] = i; + rc4_ctx->x = 0; + rc4_ctx->y = 0; + + /* default is 5 bytes (40bit key) */ + rc4_ctx->key_len = 5; + +} + +static void +rc4_uninit(PurpleCipherContext *context) { + struct RC4Context *rc4_ctx; + + rc4_ctx = purple_cipher_context_get_data(context); + memset(rc4_ctx, 0, sizeof(rc4_ctx)); + + g_free(rc4_ctx); + rc4_ctx = NULL; +} + + + +static void +rc4_set_key (PurpleCipherContext *context, const guchar * key) { + struct RC4Context *ctx; + guchar *state; + guchar temp_swap; + guchar x, y; + guint i; + + ctx = purple_cipher_context_get_data(context); + + x = 0; + y = 0; + state = &ctx->state[0]; + for(i = 0; i < 256; i++) + { + y = (key[x] + state[i] + y) % 256; + temp_swap = state[i]; + state[i] = state[y]; + state[y] = temp_swap; + x = (x + 1) % ctx->key_len; + } +} + +static void +rc4_set_opt(PurpleCipherContext *context, const gchar *name, void *value) { + struct RC4Context *ctx; + + ctx = purple_cipher_context_get_data(context); + + if(!strcmp(name, "key_len")) { + ctx->key_len = GPOINTER_TO_INT(value); + } +} + +static size_t +rc4_get_key_size (PurpleCipherContext *context) +{ + struct RC4Context *ctx; + + g_return_val_if_fail(context, -1); + + ctx = purple_cipher_context_get_data(context); + + g_return_val_if_fail(ctx, -1); + + return ctx->key_len; +} + +static void * +rc4_get_opt(PurpleCipherContext *context, const gchar *name) { + struct RC4Context *ctx; + + ctx = purple_cipher_context_get_data(context); + + if(!strcmp(name, "key_len")) { + return GINT_TO_POINTER(ctx->key_len); + } + + return NULL; +} + +static gint +rc4_encrypt(PurpleCipherContext *context, const guchar data[], + size_t len, guchar output[], size_t *outlen) { + struct RC4Context *ctx; + guchar temp_swap; + guchar x, y, z; + guchar *state; + guint i; + + ctx = purple_cipher_context_get_data(context); + + x = ctx->x; + y = ctx->y; + state = &ctx->state[0]; + + for(i = 0; i < len; i++) + { + x = (x + 1) % 256; + y = (state[x] + y) % 256; + temp_swap = state[x]; + state[x] = state[y]; + state[y] = temp_swap; + z = state[x] + (state[y]) % 256; + output[i] = data[i] ^ state[z]; + } + ctx->x = x; + ctx->y = y; + if(outlen) + *outlen = len; + + return 0; +} + +static PurpleCipherOps RC4Ops = { + rc4_set_opt, /* Set Option */ + rc4_get_opt, /* Get Option */ + rc4_init, /* init */ + rc4_reset, /* reset */ + rc4_uninit, /* uninit */ + NULL, /* set iv */ + NULL, /* append */ + NULL, /* digest */ + rc4_encrypt, /* encrypt */ + NULL, /* decrypt */ + NULL, /* set salt */ + NULL, /* get salt size */ + rc4_set_key, /* set key */ + rc4_get_key_size, /* get key size */ + + /* padding */ + NULL, + NULL, + NULL, + NULL +}; + +/******************************************************************************* * Structs ******************************************************************************/ struct _PurpleCipher { @@ -1468,6 +1637,7 @@ purple_ciphers_register_cipher("sha1", &SHA1Ops); purple_ciphers_register_cipher("md4", &MD4Ops); purple_ciphers_register_cipher("des", &DESOps); + purple_ciphers_register_cipher("rc4", &RC4Ops); } void @@ -1830,8 +2000,8 @@ /* Check for a supported algorithm. */ g_return_val_if_fail(algorithm == NULL || *algorithm == '\0' || - strcasecmp(algorithm, "MD5") || - strcasecmp(algorithm, "MD5-sess"), NULL); + g_ascii_strcasecmp(algorithm, "MD5") || + g_ascii_strcasecmp(algorithm, "MD5-sess"), NULL); cipher = purple_ciphers_find_cipher("md5"); g_return_val_if_fail(cipher != NULL, NULL); @@ -1844,7 +2014,7 @@ purple_cipher_context_append(context, (guchar *)":", 1); purple_cipher_context_append(context, (guchar *)password, strlen(password)); - if (algorithm != NULL && !strcasecmp(algorithm, "MD5-sess")) + if (algorithm != NULL && !g_ascii_strcasecmp(algorithm, "MD5-sess")) { guchar digest[16]; @@ -1895,14 +2065,14 @@ /* Check for a supported algorithm. */ g_return_val_if_fail(algorithm == NULL || *algorithm == '\0' || - strcasecmp(algorithm, "MD5") || - strcasecmp(algorithm, "MD5-sess"), NULL); + g_ascii_strcasecmp(algorithm, "MD5") || + g_ascii_strcasecmp(algorithm, "MD5-sess"), NULL); /* Check for a supported "quality of protection". */ g_return_val_if_fail(qop == NULL || *qop == '\0' || - strcasecmp(qop, "auth") || - strcasecmp(qop, "auth-int"), NULL); + g_ascii_strcasecmp(qop, "auth") || + g_ascii_strcasecmp(qop, "auth-int"), NULL); cipher = purple_ciphers_find_cipher("md5"); g_return_val_if_fail(cipher != NULL, NULL); @@ -1913,7 +2083,7 @@ purple_cipher_context_append(context, (guchar *)":", 1); purple_cipher_context_append(context, (guchar *)digest_uri, strlen(digest_uri)); - if (qop != NULL && !strcasecmp(qop, "auth-int")) + if (qop != NULL && !g_ascii_strcasecmp(qop, "auth-int")) { PurpleCipherContext *context2; gchar entity_hash[33]; diff -r e42309469a4a -r 618a3748ff64 libpurple/conversation.c --- a/libpurple/conversation.c Mon May 21 20:02:18 2007 +0000 +++ b/libpurple/conversation.c Mon May 21 20:58:23 2007 +0000 @@ -970,20 +970,20 @@ { im->typing_state = state; - if (state == PURPLE_TYPING) - { - purple_signal_emit(purple_conversations_get_handle(), - "buddy-typing", im->conv->account, im->conv->name); - } - else if (state == PURPLE_TYPED) + switch (state) { - purple_signal_emit(purple_conversations_get_handle(), - "buddy-typed", im->conv->account, im->conv->name); - } - else if (state == PURPLE_NOT_TYPING) - { - purple_signal_emit(purple_conversations_get_handle(), - "buddy-typing-stopped", im->conv->account, im->conv->name); + case PURPLE_TYPING: + purple_signal_emit(purple_conversations_get_handle(), + "buddy-typing", im->conv->account, im->conv->name); + break; + case PURPLE_TYPED: + purple_signal_emit(purple_conversations_get_handle(), + "buddy-typed", im->conv->account, im->conv->name); + break; + case PURPLE_NOT_TYPING: + purple_signal_emit(purple_conversations_get_handle(), + "buddy-typing-stopped", im->conv->account, im->conv->name); + break; } } } @@ -1497,7 +1497,7 @@ } else if (a->buddy != b->buddy) { ret = a->buddy ? -1 : 1; } else { - ret = strcasecmp(user1, user2); + ret = purple_utf8_strcasecmp(user1, user2); } return ret; diff -r e42309469a4a -r 618a3748ff64 libpurple/dbus-analyze-functions.py --- a/libpurple/dbus-analyze-functions.py Mon May 21 20:02:18 2007 +0000 +++ b/libpurple/dbus-analyze-functions.py Mon May 21 20:58:23 2007 +0000 @@ -96,7 +96,7 @@ if len(type) == 1: # simple types (int, gboolean, etc.) and enums - if (type[0] in simpletypes) or (type[0].startswith("Purple")): + if (type[0] in simpletypes) or ((type[0].startswith("Purple") and not type[0].endswith("Callback"))): return self.inputsimple(type, name) # pointers ... @@ -118,7 +118,6 @@ # unknown pointers are always replaced with NULL else: return self.inputpointer(type, name) - return raise myexception diff -r e42309469a4a -r 618a3748ff64 libpurple/dbus-server.c --- a/libpurple/dbus-server.c Mon May 21 20:02:18 2007 +0000 +++ b/libpurple/dbus-server.c Mon May 21 20:58:23 2007 +0000 @@ -654,11 +654,12 @@ #define my_arg(type) (ptr != NULL ? * ((type *)ptr) : va_arg(data, type)) -static void +static gboolean purple_dbus_message_append_purple_values(DBusMessageIter *iter, int number, PurpleValue **purple_values, va_list data) { int i; + gboolean error = FALSE; for (i = 0; i < number; i++) { @@ -668,11 +669,12 @@ guint xuint; gboolean xboolean; gpointer ptr = NULL; + gpointer val; if (purple_value_is_outgoing(purple_values[i])) { ptr = my_arg(gpointer); - g_return_if_fail(ptr); + g_return_val_if_fail(ptr, TRUE); } switch (purple_values[i]->type) @@ -705,14 +707,18 @@ case PURPLE_TYPE_POINTER: case PURPLE_TYPE_OBJECT: case PURPLE_TYPE_BOXED: - id = purple_dbus_pointer_to_id(my_arg(gpointer)); + val = my_arg(gpointer); + id = purple_dbus_pointer_to_id(val); + if (id == 0 && val != NULL) + error = TRUE; /* Some error happened. */ dbus_message_iter_append_basic(iter, (sizeof(void *) == 4) ? DBUS_TYPE_UINT32 : DBUS_TYPE_UINT64, &id); break; default: /* no conversion implemented */ - g_return_if_reached(); + g_return_val_if_reached(TRUE); } } + return error; } #undef my_arg @@ -746,7 +752,8 @@ signal = dbus_message_new_signal(DBUS_PATH_PURPLE, DBUS_INTERFACE_PURPLE, newname); dbus_message_iter_init_append(signal, &iter); - purple_dbus_message_append_purple_values(&iter, num_values, values, vargs); + if (purple_dbus_message_append_purple_values(&iter, num_values, values, vargs)) + purple_debug_warning("dbus", "The signal \"%s\" caused some dbus error.\n", name); dbus_connection_send(purple_dbus_connection, signal, NULL); diff -r e42309469a4a -r 618a3748ff64 libpurple/debug.c --- a/libpurple/debug.c Mon May 21 20:02:18 2007 +0000 +++ b/libpurple/debug.c Mon May 21 20:58:23 2007 +0000 @@ -61,18 +61,12 @@ if (debug_enabled) { gchar *ts_s; - - if ((category != NULL) && - (purple_prefs_exists("/purple/debug/timestamps")) && - (purple_prefs_get_bool("/purple/debug/timestamps"))) { - const char *mdate; + const char *mdate; + time_t mtime = time(NULL); - time_t mtime = time(NULL); - mdate = purple_utf8_strftime("%H:%M:%S", localtime(&mtime)); - ts_s = g_strdup_printf("(%s) ", mdate); - } else { - ts_s = g_strdup(""); - } + + mdate = purple_utf8_strftime("%H:%M:%S", localtime(&mtime)); + ts_s = g_strdup_printf("(%s) ", mdate); if (category == NULL) g_print("%s%s", ts_s, arg_s); @@ -189,11 +183,4 @@ void purple_debug_init(void) { - purple_prefs_add_none("/purple/debug"); - - /* - * This pref is currently used by both the console - * output and the debug window output. - */ - purple_prefs_add_bool("/purple/debug/timestamps", FALSE); } diff -r e42309469a4a -r 618a3748ff64 libpurple/example/nullclient.c --- a/libpurple/example/nullclient.c Mon May 21 20:02:18 2007 +0000 +++ b/libpurple/example/nullclient.c Mon May 21 20:58:23 2007 +0000 @@ -137,7 +137,25 @@ static PurpleConversationUiOps null_conv_uiops = { - .write_conv = null_write_conv + NULL, /* create_conversation */ + NULL, /* destroy_conversation */ + NULL, /* write_chat */ + NULL, /* write_im */ + null_write_conv, /* write_conv */ + NULL, /* chat_add_users */ + NULL, /* chat_rename_user */ + NULL, /* chat_remove_users */ + NULL, /* chat_update_user */ + NULL, /* present */ + NULL, /* has_focus */ + NULL, /* custom_smiley_add */ + NULL, /* custom_smiley_write */ + NULL, /* custom_smiley_close */ + NULL, /* send_confirm */ + NULL, + NULL, + NULL, + NULL }; static void diff -r e42309469a4a -r 618a3748ff64 libpurple/ft.c --- a/libpurple/ft.c Mon May 21 20:02:18 2007 +0000 +++ b/libpurple/ft.c Mon May 21 20:58:23 2007 +0000 @@ -972,7 +972,8 @@ fseek(xfer->dest_fp, xfer->bytes_sent, SEEK_SET); - xfer->watcher = purple_input_add(xfer->fd, cond, transfer_cb, xfer); + if (xfer->fd) + xfer->watcher = purple_input_add(xfer->fd, cond, transfer_cb, xfer); xfer->start_time = time(NULL); diff -r e42309469a4a -r 618a3748ff64 libpurple/idle.c --- a/libpurple/idle.c Mon May 21 20:02:18 2007 +0000 +++ b/libpurple/idle.c Mon May 21 20:58:23 2007 +0000 @@ -31,7 +31,6 @@ #include "signals.h" #define IDLEMARK 600 /* 10 minutes! */ -#define IDLE_CHECK_INTERVAL 5 /* 5 seconds */ typedef enum { @@ -92,6 +91,9 @@ purple_presence_set_idle(presence, FALSE, 0); } + +static int no_away = 0; +static gint time_until_next_idle_event; /* * This function should be called when you think your idle state * may have changed. Maybe you're over the 10-minute mark and @@ -110,14 +112,17 @@ * 2. Set or unset your auto-away message. * 3. Report your current idle time to the IM server. */ -static gint -check_idleness() + +static void +check_idleness(void) { time_t time_idle; gboolean auto_away; const gchar *idle_reporting; gboolean report_idle; GList *l; + gint away_seconds = 0; + gint idle_recheck_interval; purple_signal_emit(purple_blist_get_handle(), "update-idle"); @@ -128,11 +133,13 @@ { /* Use system idle time (mouse or keyboard movement, etc.) */ time_idle = idle_ui_ops->get_time_idle(); + idle_recheck_interval = 60; } else if (!strcmp(idle_reporting, "purple")) { /* Use 'Purple idle' */ time_idle = time(NULL) - last_active_time; + idle_recheck_interval = 0; } else { @@ -146,21 +153,54 @@ /* 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 && auto_away) { - if ((idle_ui_ops != NULL) && (idle_ui_ops->get_time_idle != NULL)) - time_idle = idle_ui_ops->get_time_idle(); + if (!report_idle) + { + if (auto_away) + { + if ((idle_ui_ops != NULL) && (idle_ui_ops->get_time_idle != NULL)) + { + time_idle = idle_ui_ops->get_time_idle(); + idle_recheck_interval = 60; + } + else + { + time_idle = time(NULL) - last_active_time; + idle_recheck_interval = 0; + } + } else - time_idle = time(NULL) - last_active_time; + { + if (!no_away) + { + purple_savedstatus_set_idleaway(FALSE); + no_away = 1; + } + time_until_next_idle_event = 0; + return; + } } - if (auto_away && - (time_idle > (60 * purple_prefs_get_int("/purple/away/mins_before_away")))) + time_until_next_idle_event = IDLEMARK - time_idle; + if (time_until_next_idle_event < 0) + { + /* If we're already idle, check again as appropriate. */ + time_until_next_idle_event = idle_recheck_interval; + } + + if (auto_away || !no_away) + away_seconds = 60 * purple_prefs_get_int("/purple/away/mins_before_away"); + + if (auto_away && time_idle > away_seconds) { purple_savedstatus_set_idleaway(TRUE); + no_away = 0; } - else if (time_idle < 60 * purple_prefs_get_int("/purple/away/mins_before_away")) + else if (!no_away && time_idle < away_seconds) { + no_away = 1; 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; } /* Idle reporting stuff */ @@ -177,8 +217,21 @@ while (idled_accts != NULL) set_account_unidle(idled_accts->data); } +} - return TRUE; + +/* + * Check idle and set the timer to fire at the next idle-worth event + */ +static gint +check_idleness_timer() +{ + check_idleness(); + if (time_until_next_idle_event == 0) + idle_timer = 0; + else + idle_timer = purple_timeout_add(1000 * (time_until_next_idle_event + 1), check_idleness_timer, NULL); + return FALSE; } static void @@ -205,10 +258,26 @@ set_account_unidle(account); } +static void +idle_reporting_cb(const char *name, PurplePrefType type, gconstpointer val, gpointer data) +{ + if (idle_timer) + purple_timeout_remove(idle_timer); + idle_timer = 0; + check_idleness_timer(); +} + void purple_idle_touch() { time(&last_active_time); + if (!no_away) + { + if (idle_timer) + purple_timeout_remove(idle_timer); + idle_timer = 0; + check_idleness_timer(); + } } void @@ -241,7 +310,7 @@ purple_idle_init() { /* Add the timer to check if we're idle */ - idle_timer = purple_timeout_add(IDLE_CHECK_INTERVAL * 1000, check_idleness, NULL); + idle_timer = purple_timeout_add(1000 * (IDLEMARK + 1), check_idleness_timer, NULL); purple_signal_connect(purple_conversations_get_handle(), "sent-im-msg", purple_idle_get_handle(), @@ -253,6 +322,9 @@ purple_idle_get_handle(), PURPLE_CALLBACK(signing_off_cb), NULL); + purple_prefs_connect_callback(purple_idle_get_handle(), "/purple/away/idle_reporting", + idle_reporting_cb, NULL); + purple_idle_touch(); } @@ -260,6 +332,7 @@ purple_idle_uninit() { purple_signals_disconnect_by_handle(purple_idle_get_handle()); + purple_prefs_disconnect_by_handle(purple_idle_get_handle()); /* Remove the idle timer */ if (idle_timer > 0) diff -r e42309469a4a -r 618a3748ff64 libpurple/log.c --- a/libpurple/log.c Mon May 21 20:02:18 2007 +0000 +++ b/libpurple/log.c Mon May 21 20:58:23 2007 +0000 @@ -778,7 +778,7 @@ if (tz_off != PURPLE_NO_TZ_OFF) tm.tm_gmtoff = tz_off - tm.tm_gmtoff; - if (rest == NULL || (end = strchr(rest, '.')) == NULL || strchr(rest, ' ') != NULL) + if (stamp == 0 || rest == NULL || (end = strchr(rest, '.')) == NULL || strchr(rest, ' ') != NULL) { log = purple_log_new(type, name, account, NULL, stamp, NULL); } @@ -792,7 +792,7 @@ #else time_t stamp = purple_str_to_time(filename, FALSE, &tm, NULL, NULL); - log = purple_log_new(type, name, account, NULL, stamp, &tm); + log = purple_log_new(type, name, account, NULL, stamp, (stamp != 0) ? &tm : NULL); #endif log->logger = logger; diff -r e42309469a4a -r 618a3748ff64 libpurple/notify.c --- a/libpurple/notify.c Mon May 21 20:02:18 2007 +0000 +++ b/libpurple/notify.c Mon May 21 20:58:23 2007 +0000 @@ -22,6 +22,8 @@ * 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 "dbus-maybe.h" #include "notify.h" static PurpleNotifyUiOps *notify_ui_ops = NULL; @@ -481,6 +483,7 @@ PurpleNotifyUserInfoEntry *user_info_entry; user_info_entry = g_new0(PurpleNotifyUserInfoEntry, 1); + PURPLE_DBUS_REGISTER_POINTER(user_info_entry, PurpleNotifyUserInfoEntry); user_info_entry->label = g_strdup(label); user_info_entry->value = g_strdup(value); user_info_entry->type = PURPLE_NOTIFY_USER_INFO_ENTRY_PAIR; @@ -495,6 +498,7 @@ g_free(user_info_entry->label); g_free(user_info_entry->value); + PURPLE_DBUS_UNREGISTER_POINTER(user_info_entry); g_free(user_info_entry); } @@ -504,6 +508,7 @@ PurpleNotifyUserInfo *user_info; user_info = g_new0(PurpleNotifyUserInfo, 1); + PURPLE_DBUS_REGISTER_POINTER(user_info, PurpleNotifyUserInfo); user_info->user_info_entries = NULL; return user_info; @@ -521,6 +526,7 @@ } g_list_free(user_info->user_info_entries); + PURPLE_DBUS_UNREGISTER_POINTER(user_info); g_free(user_info); } diff -r e42309469a4a -r 618a3748ff64 libpurple/plugins/joinpart.c --- a/libpurple/plugins/joinpart.c Mon May 21 20:02:18 2007 +0000 +++ b/libpurple/plugins/joinpart.c Mon May 21 20:58:23 2007 +0000 @@ -156,7 +156,7 @@ static gboolean check_expire_time(struct joinpart_key *key, time_t *last_said, time_t *limit) { - purple_debug_info("joinpart", "Removing key for %s/%s\n", key->conv->name, key->user); + purple_debug_info("joinpart", "Removing key for %s\n", key->user); return (*last_said < *limit); } diff -r e42309469a4a -r 618a3748ff64 libpurple/plugins/perl/Makefile.am --- a/libpurple/plugins/perl/Makefile.am Mon May 21 20:02:18 2007 +0000 +++ b/libpurple/plugins/perl/Makefile.am Mon May 21 20:58:23 2007 +0000 @@ -78,7 +78,8 @@ # common/fallback/const-xs.inc perl_scripts = \ - scripts/function_list.pl + scripts/function_list.pl \ + scripts/signals-test.pl EXTRA_DIST = \ Makefile.mingw \ diff -r e42309469a4a -r 618a3748ff64 libpurple/plugins/perl/common/SavedStatuses.xs --- a/libpurple/plugins/perl/common/SavedStatuses.xs Mon May 21 20:02:18 2007 +0000 +++ b/libpurple/plugins/perl/common/SavedStatuses.xs Mon May 21 20:58:23 2007 +0000 @@ -1,41 +1,129 @@ #include "module.h" +/* I can't get this to work, both with and without the const on the return + * type I get errors from gcc. One way about ignoring types in a cast, and the + * other about assigning to read-only variables. +const Purple::StatusType +purple_savedstatus_substatus_get_type(substatus) + const Purple::SavedStatus::Sub substatus +*/ + MODULE = Purple::SavedStatus PACKAGE = Purple::SavedStatus PREFIX = purple_savedstatus_ PROTOTYPES: ENABLE -gboolean -purple_savedstatus_delete(title) - const char *title - -Purple::SavedStatus -purple_savedstatus_find(title) - const char *title - -const char * -purple_savedstatus_get_message(saved_status) - Purple::SavedStatus saved_status - -const char * -purple_savedstatus_get_title(saved_status) - Purple::SavedStatus saved_status - -Purple::StatusPrimitive -purple_savedstatus_get_type(saved_status) - Purple::SavedStatus saved_status - Purple::SavedStatus purple_savedstatus_new(title, type) const char *title Purple::StatusPrimitive type void +purple_savedstatus_set_title(status, title) + Purple::SavedStatus status + const char *title + +void +purple_savedstatus_set_type(status, type) + Purple::SavedStatus status + Purple::StatusPrimitive type + +void purple_savedstatus_set_message(status, message) Purple::SavedStatus status const char *message +void +purple_savedstatus_set_substatus(status, account, type, message) + Purple::SavedStatus status + Purple::Account account + Purple::StatusType type + const char *message + +void +purple_savedstatus_unset_substatus(status, account) + Purple::SavedStatus status + Purple::Account account + +gboolean +purple_savedstatus_delete(title) + const char *title + Purple::SavedStatus purple_savedstatus_get_current() +Purple::SavedStatus +purple_savedstatus_get_default() + +Purple::SavedStatus +purple_savedstatus_get_idleaway() + +gboolean +purple_savedstatus_is_idleaway() + +void +purple_savedstatus_set_idleaway(idleaway) + gboolean idleaway + +Purple::SavedStatus +purple_savedstatus_get_startup() + +Purple::SavedStatus +purple_savedstatus_find(title) + const char *title + +Purple::SavedStatus +purple_savedstatus_find_by_creation_time(creation_time) + time_t creation_time + +Purple::SavedStatus +purple_savedstatus_find_transient_by_type_and_message(type, message) + Purple::StatusPrimitive type + const char *message + +gboolean +purple_savedstatus_is_transient(saved_status) + const Purple::SavedStatus saved_status + +const char * +purple_savedstatus_get_title(saved_status) + const Purple::SavedStatus saved_status + +Purple::StatusPrimitive +purple_savedstatus_get_type(saved_status) + const Purple::SavedStatus saved_status + +const char * +purple_savedstatus_get_message(saved_status) + const Purple::SavedStatus saved_status + +time_t +purple_savedstatus_get_creation_time(saved_status) + const Purple::SavedStatus saved_status + +gboolean +purple_savedstatus_has_substatuses(saved_status) + const Purple::SavedStatus saved_status + +Purple::SavedStatus::Sub +purple_savedstatus_get_substatus(saved_status, account) + Purple::SavedStatus saved_status + Purple::Account account + +void +purple_savedstatus_activate(saved_status) + Purple::SavedStatus saved_status + +void +purple_savedstatus_activate_for_account(saved_status, account) + const Purple::SavedStatus saved_status + Purple::Account account + +MODULE = Purple::SavedStatus::Sub PACKAGE = Purple::SavedStatus::Sub PREFIX = purple_savedstatus_substatus_ +PROTOTYPES: ENABLE + +const char * +purple_savedstatus_substatus_get_message(substatus) + const Purple::SavedStatus::Sub substatus + MODULE = Purple::SavedStatus PACKAGE = Purple::SavedStatuses PREFIX = purple_savedstatuses_ PROTOTYPES: ENABLE @@ -48,6 +136,16 @@ XPUSHs(sv_2mortal(purple_perl_bless_object(l->data, "Purple::SavedStatus"))); } +void +purple_savedstatuses_get_popular(how_many) + unsigned int how_many +PREINIT: + const GList *l; +PPCODE: + for (l = purple_savedstatuses_get_popular(how_many); l != NULL; l = l->next) { + XPUSHs(sv_2mortal(purple_perl_bless_object(l->data, "Purple::SavedStatus"))); + } + Purple::Handle purple_savedstatuses_get_handle() diff -r e42309469a4a -r 618a3748ff64 libpurple/plugins/perl/common/module.h --- a/libpurple/plugins/perl/common/module.h Mon May 21 20:02:18 2007 +0000 +++ b/libpurple/plugins/perl/common/module.h Mon May 21 20:58:23 2007 +0000 @@ -236,7 +236,7 @@ /* savedstatuses.h */ typedef PurpleSavedStatus * Purple__SavedStatus; -typedef PurpleSavedStatusSub * Purple__SavedStatusSub; +typedef PurpleSavedStatusSub * Purple__SavedStatus__Sub; /* sound.h */ typedef PurpleSoundEventID Purple__SoundEventID; diff -r e42309469a4a -r 618a3748ff64 libpurple/plugins/perl/common/typemap --- a/libpurple/plugins/perl/common/typemap Mon May 21 20:02:18 2007 +0000 +++ b/libpurple/plugins/perl/common/typemap Mon May 21 20:58:23 2007 +0000 @@ -137,7 +137,9 @@ Purple::RoomlistRoomType T_IV Purple::SavedStatus T_PurpleObj -Purple::SavedStatusSub T_PurpleObj +const Purple::SavedStatus T_PurpleObj +Purple::SavedStatus::Sub T_PurpleObj +const Purple::SavedStatus::Sub T_PurpleObj Purple::SoundEventID T_IV Purple::Sound::UiOps T_PurpleObj diff -r e42309469a4a -r 618a3748ff64 libpurple/plugins/perl/perl-common.c --- a/libpurple/plugins/perl/perl-common.c Mon May 21 20:02:18 2007 +0000 +++ b/libpurple/plugins/perl/perl-common.c Mon May 21 20:58:23 2007 +0000 @@ -80,7 +80,7 @@ stash = gv_stashpv(stash_name, 1); hv = newHV(); - hv_store(hv, "_purple", 5, create_sv_ptr(object), 0); + hv_store(hv, "_purple", 7, create_sv_ptr(object), 0); return sv_bless(newRV_noinc((SV *)hv), stash); } @@ -94,7 +94,7 @@ hv = hvref(o); if (hv != NULL) { - sv = hv_fetch(hv, "_purple", 5, 0); + sv = hv_fetch(hv, "_purple", 7, 0); if (sv != NULL) return TRUE; @@ -118,7 +118,7 @@ if (hv == NULL) return NULL; - sv = hv_fetch(hv, "_purple", 5, 0); + sv = hv_fetch(hv, "_purple", 7, 0); if (sv == NULL) croak("variable is damaged"); diff -r e42309469a4a -r 618a3748ff64 libpurple/plugins/perl/scripts/signals-test.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/plugins/perl/scripts/signals-test.pl Mon May 21 20:58:23 2007 +0000 @@ -0,0 +1,80 @@ +$MODULE_NAME = "Signals Test Script in Perl"; + +use Purple; + +%PLUGIN_INFO = ( + perl_api_version => 2, + name => "Perl: $MODULE_NAME", + version => "0.1", + summary => "Signals Test plugin for the Perl interpreter.", + description => "Demonstrate the user of purple signals from " . + "a perl plugin.", + author => "Sadrul Habib Chowdhury ", + url => "http://developer.pidgin.im/wiki/sadrul/", + + load => "plugin_load", + unload => "plugin_unload" +); + +# Accounts +sub account_connecting_cb +{ + my $account = shift; + Purple::Debug::misc("signals test in perl", "account-connecting (" . $account->get_username() . ")\n"); +} + +# Buddylist +sub buddy_signed_on +{ + my $buddy = shift; + Purple::Debug::misc("signals test in perl", "buddy-signed-on (" . $buddy->get_name() . ")\n"); +} + +# Connections +sub signed_on +{ + my $conn = shift; + Purple::Debug::misc("signals test in perl", "signed-on (" . $conn->get_account()->get_username() . ")\n"); +} + +# Conversations +sub conv_received_msg +{ + my ($account, $sender, $message, $conv, $flags, $data) = @_; + Purple::Debug::misc("signals test in perl", "$data (" . $account->get_username() . ", $sender, $message, $flags)\n"); +} + +sub plugin_load +{ + my $plugin = shift; + + # Hook to the signals + + # Accounts + $act_handle = Purple::Accounts::get_handle(); + Purple::Signal::connect($act_handle, "account-connecting", $plugin, + \&account_connecting_cb, 0); + + # Buddy List + $blist = Purple::BuddyList::get_handle(); + Purple::Signal::connect($blist, "buddy-signed-on", $plugin, + \&buddy_signed_on, 0); + + # Connections + $conn = Purple::Connections::get_handle(); + Purple::Signal::connect($conn, "signed-on", $plugin, + \&signed_on, 0); + + # Conversations + $conv = Purple::Conversations::get_handle(); + Purple::Signal::connect($conv, "received-im-msg", $plugin, + \&conv_received_msg, "received im message"); + Purple::Signal::connect($conv, "received-chat-msg", $plugin, + \&conv_received_msg, "received chat message"); +} + +sub plugin_unload +{ + # Nothing to do here for this plugin. +} + diff -r e42309469a4a -r 618a3748ff64 libpurple/prefs.c --- a/libpurple/prefs.c Mon May 21 20:02:18 2007 +0000 +++ b/libpurple/prefs.c Mon May 21 20:58:23 2007 +0000 @@ -937,7 +937,7 @@ if(pref->type != PURPLE_PREF_PATH_LIST) { purple_debug_error("prefs", - "purple_prefs_set_path_list: %s not a string list pref\n", + "purple_prefs_set_path_list: %s not a path list pref\n", name); return; } @@ -1355,6 +1355,7 @@ purple_prefs_remove("/plugins/core/autorecon/hide_reconnecting_dialog"); purple_prefs_remove("/plugins/core/autorecon/restore_state"); purple_prefs_remove("/plugins/core/autorecon"); + purple_prefs_remove("/purple/debug/timestamps"); /* Convert old sounds while_away pref to new 3-way pref. */ if (purple_prefs_exists("/purple/sound/while_away") && diff -r e42309469a4a -r 618a3748ff64 libpurple/protocols/bonjour/jabber.c --- a/libpurple/protocols/bonjour/jabber.c Mon May 21 20:02:18 2007 +0000 +++ b/libpurple/protocols/bonjour/jabber.c Mon May 21 20:58:23 2007 +0000 @@ -242,7 +242,7 @@ if (cbba->bj->account == gb->account) { bb = gb->proto_data; - if ((bb != NULL) && (g_strcasecmp(bb->ip, cbba->address) == 0)) + if ((bb != NULL) && (g_ascii_strcasecmp(bb->ip, cbba->address) == 0)) *(cbba->gb) = gb; } } diff -r e42309469a4a -r 618a3748ff64 libpurple/protocols/irc/irc.c --- a/libpurple/protocols/irc/irc.c Mon May 21 20:02:18 2007 +0000 +++ b/libpurple/protocols/irc/irc.c Mon May 21 20:58:23 2007 +0000 @@ -146,10 +146,10 @@ purple_signal_emit(_irc_plugin, "irc-sending-text", purple_account_get_connection(irc->account), &tosend); if (tosend == NULL) return 0; - + buflen = strlen(tosend); - - + + /* If we're not buffering writes, try to send immediately */ if (!irc->writeh) ret = do_send(irc, tosend, buflen); @@ -342,7 +342,7 @@ } static gboolean do_login(PurpleConnection *gc) { - char *buf; + char *buf, *tmp = NULL; char hostname[256]; const char *username, *realname; struct irc_conn *irc = gc->proto_data; @@ -358,12 +358,26 @@ g_free(buf); } + gethostname(hostname, sizeof(hostname)); hostname[sizeof(hostname) - 1] = '\0'; + realname = purple_account_get_string(irc->account, "realname", ""); username = purple_account_get_string(irc->account, "username", ""); - realname = purple_account_get_string(irc->account, "realname", ""); - buf = irc_format(irc, "vvvv:", "USER", strlen(username) ? username : g_get_user_name(), hostname, irc->server, + + if (username == NULL || *username == '\0') { + username = g_get_user_name(); + } + + if (username != NULL && strchr(username, ' ') != NULL) { + tmp = g_strdup(username); + while ((buf = strchr(tmp, ' ')) != NULL) { + *buf = '_'; + } + } + + buf = irc_format(irc, "vvvv:", "USER", tmp ? tmp : username, hostname, irc->server, strlen(realname) ? realname : IRC_DEFAULT_ALIAS); + g_free(tmp); if (irc_send(irc, buf) < 0) { /* purple_connection_error(gc, "Error registering with server");*/ g_free(buf); @@ -548,13 +562,13 @@ irc->inbuf[irc->inbufused] = '\0'; cur = irc->inbuf; - + /* This is a hack to work around the fact that marv gets messages * with null bytes in them while using some weird irc server at work */ while ((cur < (irc->inbuf + irc->inbufused)) && !*cur) cur++; - + while (cur < irc->inbuf + irc->inbufused && ((end = strstr(cur, "\r\n")) || (end = strstr(cur, "\n")))) { int step = (*end == '\r' ? 2 : 1); @@ -643,7 +657,7 @@ return g_strdup(g_hash_table_lookup(data, "channel")); } -static void irc_chat_invite(PurpleConnection *gc, int id, const char *message, const char *name) +static void irc_chat_invite(PurpleConnection *gc, int id, const char *message, const char *name) { struct irc_conn *irc = gc->proto_data; PurpleConversation *convo = purple_find_chat(gc, id); diff -r e42309469a4a -r 618a3748ff64 libpurple/protocols/irc/irc.h --- a/libpurple/protocols/irc/irc.h Mon May 21 20:02:18 2007 +0000 +++ b/libpurple/protocols/irc/irc.h Mon May 21 20:58:23 2007 +0000 @@ -142,8 +142,8 @@ void irc_msg_ping(struct irc_conn *irc, const char *name, const char *from, char **args); void irc_msg_pong(struct irc_conn *irc, const char *name, const char *from, char **args); void irc_msg_privmsg(struct irc_conn *irc, const char *name, const char *from, char **args); +void irc_msg_quit(struct irc_conn *irc, const char *name, const char *from, char **args); void irc_msg_regonly(struct irc_conn *irc, const char *name, const char *from, char **args); -void irc_msg_quit(struct irc_conn *irc, const char *name, const char *from, char **args); void irc_msg_time(struct irc_conn *irc, const char *name, const char *from, char **args); void irc_msg_topic(struct irc_conn *irc, const char *name, const char *from, char **args); void irc_msg_unavailable(struct irc_conn *irc, const char *name, const char *from, char **args); diff -r e42309469a4a -r 618a3748ff64 libpurple/protocols/irc/msgs.c --- a/libpurple/protocols/irc/msgs.c Mon May 21 20:02:18 2007 +0000 +++ b/libpurple/protocols/irc/msgs.c Mon May 21 20:58:23 2007 +0000 @@ -35,6 +35,7 @@ static char *irc_mask_userhost(const char *mask); static void irc_chat_remove_buddy(PurpleConversation *convo, char *data[2]); static void irc_buddy_status(char *name, struct irc_buddy *ib, struct irc_conn *irc); +static void irc_connected(struct irc_conn *irc, const char *nick); static void irc_msg_handle_privmsg(struct irc_conn *irc, const char *name, const char *from, const char *to, @@ -70,6 +71,52 @@ g_free(message); } +static void irc_connected(struct irc_conn *irc, const char *nick) +{ + PurpleConnection *gc; + PurpleStatus *status; + PurpleBlistNode *gnode, *cnode, *bnode; + + if ((gc = purple_account_get_connection(irc->account)) == NULL + || PURPLE_CONNECTION_IS_CONNECTED(gc)) + return; + + purple_connection_set_display_name(gc, nick); + purple_connection_set_state(gc, PURPLE_CONNECTED); + + /* If we're away then set our away message */ + status = purple_account_get_active_status(irc->account); + if (!purple_status_get_type(status) != PURPLE_STATUS_AVAILABLE) { + PurplePluginProtocolInfo *prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl); + prpl_info->set_status(irc->account, status); + } + + /* this used to be in the core, but it's not now */ + 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) { + PurpleBuddy *b; + if(!PURPLE_BLIST_NODE_IS_BUDDY(bnode)) + continue; + b = (PurpleBuddy *)bnode; + if(b->account == gc->account) { + struct irc_buddy *ib = g_new0(struct irc_buddy, 1); + ib->name = g_strdup(b->name); + g_hash_table_insert(irc->buddies, ib->name, ib); + } + } + } + } + + irc_blist_timeout(irc); + if (!irc->timer) + irc->timer = purple_timeout_add(45000, (GSourceFunc)irc_blist_timeout, (gpointer)irc); +} + void irc_msg_default(struct irc_conn *irc, const char *name, const char *from, char **args) { purple_debug(PURPLE_DEBUG_INFO, "irc", "Unrecognized message: %s\n", args[0]); @@ -95,56 +142,16 @@ void irc_msg_luser(struct irc_conn *irc, const char *name, const char *from, char **args) { - PurpleConnection *gc; - PurpleStatus *status; - PurpleBlistNode *gnode, *cnode, *bnode; - - if (!args || !args[0] || !args[1]) - return; - - gc = purple_account_get_connection(irc->account); - if (!gc) + if (!args || !args[0]) return; if (!strcmp(name, "251")) { - /* 251 is required, so we pluck our nick from here */ - purple_connection_set_display_name(gc, args[0]); + /* 251 is required, so we pluck our nick from here and + * finalize connection */ + irc_connected(irc, args[0]); /* Some IRC servers seem to not send a 255 numeric, so * I guess we can't require it; 251 will do. */ /* } else if (!strcmp(name, "255")) { */ - purple_connection_set_state(gc, PURPLE_CONNECTED); - - /* If we're away then set our away message */ - status = purple_account_get_active_status(irc->account); - if (!purple_status_get_type(status) != PURPLE_STATUS_AVAILABLE) { - PurplePluginProtocolInfo *prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl); - prpl_info->set_status(irc->account, status); - } - - /* this used to be in the core, but it's not now */ - 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) { - PurpleBuddy *b; - if(!PURPLE_BLIST_NODE_IS_BUDDY(bnode)) - continue; - b = (PurpleBuddy *)bnode; - if(b->account == gc->account) { - struct irc_buddy *ib = g_new0(struct irc_buddy, 1); - ib->name = g_strdup(b->name); - g_hash_table_insert(irc->buddies, ib->name, ib); - } - } - } - } - - irc_blist_timeout(irc); - if (!irc->timer) - irc->timer = purple_timeout_add(45000, (GSourceFunc)irc_blist_timeout, (gpointer)irc); } } @@ -523,6 +530,9 @@ { char *escaped; + if (!args || !args[0]) + return; + if (!irc->motd) irc->motd = g_string_new(""); @@ -532,7 +542,9 @@ irc->motd = g_string_new(""); return; } else if (!strcmp(name, "376")) { - /* We no longer have to do anything for ENDMOTD */ + /* dircproxy 1.0.5 does not send 251 on reconnection, so + * finalize the connection here if it is not already done. */ + irc_connected(irc, args[0]); return; } @@ -541,6 +553,9 @@ return; } + if (!args[1]) + return; + escaped = g_markup_escape_text(args[1], -1); g_string_append_printf(irc->motd, "%s
", escaped); g_free(escaped); @@ -1079,7 +1094,7 @@ if (!args || !args[1] || !args[2] || !gc) return; - msg = g_strdup_printf(_("Cannot join %s:"), args[1]); + msg = g_strdup_printf(_("Cannot join %s: Registration is required."), args[1]); purple_notify_error(gc, _("Cannot join channel"), msg, args[2]); g_free(msg); } diff -r e42309469a4a -r 618a3748ff64 libpurple/protocols/irc/parse.c --- a/libpurple/protocols/irc/parse.c Mon May 21 20:02:18 2007 +0000 +++ b/libpurple/protocols/irc/parse.c Mon May 21 20:58:23 2007 +0000 @@ -91,6 +91,7 @@ { "442", "nc:", irc_msg_notinchan }, /* Not in channel */ { "473", "nc:", irc_msg_inviteonly }, /* Tried to join invite-only */ { "474", "nc:", irc_msg_banned }, /* Banned from channel */ + { "477", "nc:", irc_msg_regonly }, /* Registration Required */ { "478", "nct:", irc_msg_banfull }, /* Banlist is full */ { "482", "nc:", irc_msg_notop }, /* Need to be op to do that */ { "501", "n:", irc_msg_badmode }, /* Unknown mode flag */ @@ -226,7 +227,7 @@ enclist = purple_account_get_string(irc->account, "encoding", IRC_DEFAULT_CHARSET); encodings = g_strsplit(enclist, ",", 2); - if (encodings[0] == NULL || !strcasecmp("UTF-8", encodings[0])) { + if (encodings[0] == NULL || !g_ascii_strcasecmp("UTF-8", encodings[0])) { g_strfreev(encodings); return g_strdup(string); } @@ -263,7 +264,7 @@ while (*charset == ' ') charset++; - if (!strcasecmp("UTF-8", charset)) { + if (!g_ascii_strcasecmp("UTF-8", charset)) { if (g_utf8_validate(string, -1, NULL)) utf8 = g_strdup(string); } else { diff -r e42309469a4a -r 618a3748ff64 libpurple/protocols/jabber/auth.c --- a/libpurple/protocols/jabber/auth.c Mon May 21 20:02:18 2007 +0000 +++ b/libpurple/protocols/jabber/auth.c Mon May 21 20:58:23 2007 +0000 @@ -291,12 +291,15 @@ * plaintext auth */ } else if (!plaintext) { + char *msg = g_strdup_printf(_("%s requires plaintext authentication over an unencrypted connection. Allow this and continue authentication?"), + js->gc->account->username); purple_request_yes_no(js->gc, _("Plaintext Authentication"), _("Plaintext Authentication"), - _("This server requires plaintext authentication over an unencrypted connection. Allow this and continue authentication?"), + msg, 2, js->gc->account, NULL, NULL, NULL, allow_cyrus_plaintext_auth, disallow_plaintext_auth); + g_free(msg); return; /* Everything else has failed, so fail the * connection. Should probably have a better @@ -477,13 +480,16 @@ js->auth_type = JABBER_AUTH_PLAIN; if(js->gsc == NULL && !purple_account_get_bool(js->gc->account, "auth_plain_in_clear", FALSE)) { + char *msg = g_strdup_printf(_("%s requires plaintext authentication over an unencrypted connection. Allow this and continue authentication?"), + js->gc->account->username); purple_request_yes_no(js->gc, _("Plaintext Authentication"), _("Plaintext Authentication"), - _("This server requires plaintext authentication over an unencrypted connection. Allow this and continue authentication?"), + msg, 2, purple_connection_get_account(js->gc), NULL, NULL, purple_connection_get_account(js->gc), allow_plaintext_auth, disallow_plaintext_auth); + g_free(msg); return; } finish_plaintext_authentication(js); diff -r e42309469a4a -r 618a3748ff64 libpurple/protocols/jabber/buddy.c --- a/libpurple/protocols/jabber/buddy.c Mon May 21 20:02:18 2007 +0000 +++ b/libpurple/protocols/jabber/buddy.c Mon May 21 20:58:23 2007 +0000 @@ -1118,6 +1118,24 @@ return FALSE; } +static gboolean _client_is_blacklisted(JabberBuddyResource *jbr, const char *ns) +{ + /* can't be blacklisted if we don't know what you're running yet */ + if(!jbr->client.name) + return FALSE; + + if(!strcmp(ns, "jabber:iq:last")) { + if(!strcmp(jbr->client.name, "Trillian")) { + if(!strcmp(jbr->client.version, "3.1.0.121")) { + /* verified by nwalp 2007/05/09 */ + return TRUE; + } + } + } + + return FALSE; +} + static void jabber_buddy_get_info_for_jid(JabberStream *js, const char *jid) { JabberIq *iq; @@ -1175,11 +1193,18 @@ jabber_iq_send(iq); } - iq = jabber_iq_new_query(js, JABBER_IQ_GET, "jabber:iq:last"); - xmlnode_set_attrib(iq->node, "to", full_jid); - jabber_iq_set_callback(iq, jabber_last_parse, jbi); - jbi->ids = g_slist_prepend(jbi->ids, g_strdup(iq->id)); - jabber_iq_send(iq); + /* this is to fix the feeling of irritation I get when trying + * to get info on a friend running Trillian, which doesn't + * respond (with an error or otherwise) to jabber:iq:last + * requests. There are a number of Trillian users in my + * office. */ + if(!_client_is_blacklisted(jbr, "jabber:iq:last")) { + iq = jabber_iq_new_query(js, JABBER_IQ_GET, "jabber:iq:last"); + xmlnode_set_attrib(iq->node, "to", full_jid); + jabber_iq_set_callback(iq, jabber_last_parse, jbi); + jbi->ids = g_slist_prepend(jbi->ids, g_strdup(iq->id)); + jabber_iq_send(iq); + } g_free(full_jid); } @@ -1793,7 +1818,7 @@ purple_request_input(gc, _("Enter a User Directory"), _("Enter a User Directory"), _("Select a user directory to search"), - js->user_directories ? js->user_directories->data : "users.jabber.org", + js->user_directories ? js->user_directories->data : NULL, FALSE, FALSE, NULL, _("Search Directory"), PURPLE_CALLBACK(jabber_user_search_ok), _("Cancel"), NULL, diff -r e42309469a4a -r 618a3748ff64 libpurple/protocols/jabber/chat.c --- a/libpurple/protocols/jabber/chat.c Mon May 21 20:02:18 2007 +0000 +++ b/libpurple/protocols/jabber/chat.c Mon May 21 20:58:23 2007 +0000 @@ -75,8 +75,6 @@ if (js->chat_servers) g_hash_table_insert(defaults, "server", g_strdup(js->chat_servers->data)); - else - g_hash_table_insert(defaults, "server", g_strdup("conference.jabber.org")); if (chat_name != NULL) { JabberID *jid = jabber_id_new(chat_name); @@ -782,7 +780,7 @@ purple_request_input(gc, _("Enter a Conference Server"), _("Enter a Conference Server"), _("Select a conference server to query"), - js->chat_servers ? js->chat_servers->data : "conference.jabber.org", + js->chat_servers ? js->chat_servers->data : NULL, FALSE, FALSE, NULL, _("Find Rooms"), PURPLE_CALLBACK(roomlist_ok_cb), _("Cancel"), PURPLE_CALLBACK(roomlist_cancel_cb), diff -r e42309469a4a -r 618a3748ff64 libpurple/protocols/jabber/jabber.c --- a/libpurple/protocols/jabber/jabber.c Mon May 21 20:02:18 2007 +0000 +++ b/libpurple/protocols/jabber/jabber.c Mon May 21 20:58:23 2007 +0000 @@ -508,13 +508,13 @@ jabber_login_callback_ssl, jabber_ssl_connect_failure, js->gc); } -static void jabber_login_connect(JabberStream *js, const char *server, int port) +static void jabber_login_connect(JabberStream *js, const char *fqdn, const char *host, int port) { #ifdef HAVE_CYRUS_SASL - js->serverFQDN = g_strdup(server); + js->serverFQDN = g_strdup(fqdn); #endif - if (purple_proxy_connect(js->gc, js->gc->account, server, + if (purple_proxy_connect(js->gc, js->gc->account, host, port, jabber_login_callback, js->gc) == NULL) purple_connection_error(js->gc, _("Unable to create socket")); } @@ -527,10 +527,10 @@ js->srv_query_data = NULL; if(results) { - jabber_login_connect(js, resp->hostname, resp->port); + jabber_login_connect(js, resp->hostname, resp->hostname, resp->port); g_free(resp); } else { - jabber_login_connect(js, js->user->domain, + jabber_login_connect(js, js->user->domain, js->user->domain, purple_account_get_int(js->gc->account, "port", 5222)); } } @@ -556,7 +556,6 @@ g_free, (GDestroyNotify)jabber_buddy_free); js->chats = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)jabber_chat_free); - js->chat_servers = g_list_append(NULL, g_strdup("conference.jabber.org")); js->user = jabber_id_new(purple_account_get_username(account)); js->next_id = g_random_int(); js->write_buffer = purple_circ_buffer_new(512); @@ -565,7 +564,12 @@ purple_connection_error(gc, _("Invalid XMPP ID")); return; } - + + if (!js->user->domain || *(js->user->domain) == '\0') { + purple_connection_error(gc, _("Invalid XMPP ID. Domain must be set.")); + return; + } + if(!js->user->resource) { char *me; js->user->resource = g_strdup("Home"); @@ -600,7 +604,7 @@ * invoke the magic of SRV lookups, to figure out host and port */ if(!js->gsc) { if(connect_server[0]) { - jabber_login_connect(js, connect_server, purple_account_get_int(account, "port", 5222)); + jabber_login_connect(js, js->user->domain, connect_server, purple_account_get_int(account, "port", 5222)); } else { js->srv_query_data = purple_srv_resolve("xmpp-client", "tcp", js->user->domain, srv_resolved_cb, js); @@ -945,7 +949,7 @@ if(!js->gsc) { if (connect_server[0]) { - jabber_login_connect(js, server, + jabber_login_connect(js, js->user->domain, server, purple_account_get_int(account, "port", 5222)); } else { diff -r e42309469a4a -r 618a3748ff64 libpurple/protocols/jabber/libxmpp.c --- a/libpurple/protocols/jabber/libxmpp.c Mon May 21 20:02:18 2007 +0000 +++ b/libpurple/protocols/jabber/libxmpp.c Mon May 21 20:58:23 2007 +0000 @@ -191,7 +191,8 @@ PurpleAccountUserSplit *split; PurpleAccountOption *option; - split = purple_account_user_split_new(_("Server"), "jabber.org", '@'); + /* Translators: 'domain' is used here in the context of Internet domains, e.g. pidgin.im */ + split = purple_account_user_split_new(_("Domain"), NULL, '@'); prpl_info.user_splits = g_list_append(prpl_info.user_splits, split); split = purple_account_user_split_new(_("Resource"), "Home", '/'); diff -r e42309469a4a -r 618a3748ff64 libpurple/protocols/jabber/presence.c --- a/libpurple/protocols/jabber/presence.c Mon May 21 20:02:18 2007 +0000 +++ b/libpurple/protocols/jabber/presence.c Mon May 21 20:58:23 2007 +0000 @@ -391,7 +391,7 @@ static int i = 1; char *room_jid = g_strdup_printf("%s@%s", jid->node, jid->domain); - if(state == JABBER_BUDDY_STATE_ERROR && jid->resource == NULL) { + if(state == JABBER_BUDDY_STATE_ERROR) { char *title, *msg = jabber_parse_error(js, packet); if(chat->conv) { diff -r e42309469a4a -r 618a3748ff64 libpurple/protocols/msn/msn.c --- a/libpurple/protocols/msn/msn.c Mon May 21 20:02:18 2007 +0000 +++ b/libpurple/protocols/msn/msn.c Mon May 21 20:58:23 2007 +0000 @@ -73,6 +73,15 @@ } MsnGetInfoStepTwoData; +typedef struct +{ + PurpleConnection *gc; + const char *who; + char *msg; + PurpleMessageFlags flags; + time_t when; +} MsnIMData; + static const char * msn_normalize(const PurpleAccount *account, const char *str) { @@ -409,33 +418,7 @@ static void t_msn_xfer_init(PurpleXfer *xfer) { - MsnSlpLink *slplink; - const char *filename; - FILE *fp; - - filename = purple_xfer_get_local_filename(xfer); - - slplink = xfer->data; - - if ((fp = g_fopen(filename, "rb")) == NULL) - { - PurpleAccount *account; - const char *who; - char *msg; - - account = slplink->session->account; - who = slplink->remote_user; - - msg = g_strdup_printf(_("Error reading %s: \n%s.\n"), - filename, strerror(errno)); - purple_xfer_error(purple_xfer_get_type(xfer), account, xfer->who, msg); - purple_xfer_cancel_local(xfer); - g_free(msg); - - return; - } - fclose(fp); - + MsnSlpLink *slplink = xfer->data; msn_slplink_request_ft(slplink, xfer); } @@ -636,7 +619,8 @@ account = purple_connection_get_account(gc); user = msn_normalize(account, purple_account_get_username(account)); - if (strstr(user, "@hotmail.com") != NULL) + if ((strstr(user, "@hotmail.") != NULL) || + (strstr(user, "@msn.com") != NULL)) { m = g_list_append(m, NULL); act = purple_plugin_action_new(_("Open Hotmail Inbox"), @@ -753,6 +737,16 @@ gc->proto_data = NULL; } +static gboolean +msn_send_me_im(gpointer data) +{ + MsnIMData *imdata = data; + serv_got_im(imdata->gc, imdata->who, imdata->msg, imdata->flags, imdata->when); + g_free(imdata->msg); + g_free(imdata); + return FALSE; +} + static int msn_send_im(PurpleConnection *gc, const char *who, const char *message, PurpleMessageFlags flags) @@ -805,6 +799,7 @@ { char *body_str, *body_enc, *pre, *post; const char *format; + MsnIMData *imdata = g_new0(MsnIMData, 1); /* * In MSN, you can't send messages to yourself, so * we'll fake like we received it ;) @@ -822,8 +817,12 @@ g_free(post); serv_got_typing_stopped(gc, who); - serv_got_im(gc, who, body_str, flags, time(NULL)); - g_free(body_str); + imdata->gc = gc; + imdata->who = who; + imdata->msg = body_str; + imdata->flags = flags; + imdata->when = time(NULL); + g_idle_add(msn_send_me_im, imdata); } msn_message_destroy(msg); diff -r e42309469a4a -r 618a3748ff64 libpurple/protocols/msn/notification.c --- a/libpurple/protocols/msn/notification.c Mon May 21 20:02:18 2007 +0000 +++ b/libpurple/protocols/msn/notification.c Mon May 21 20:58:23 2007 +0000 @@ -589,6 +589,23 @@ } static void +qng_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) +{ + static int count = 0; + MsnSession *session = cmdproc->session; + + if (session->passport_info.file == NULL) + return; + + if (count++ < 26) + return; + + count = 0; + msn_cmdproc_send(cmdproc, "URL", "%s", "INBOX"); +} + + +static void fln_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) { MsnSlpLink *slplink; @@ -982,7 +999,8 @@ } else { - fputs("\n" + fputs("\n" + "\n" "\n" "