Sat, 10 Nov 2007 04:52:20 +0000
propagate from branch 'im.pidgin.pidgin.next.minor' (head 2f91b326b3f073672c2475a8c30a06826da9b82f)
to branch 'im.pidgin.pidgin' (head 326d5b91950b3d78c445722f6d726cfa6b1c525d)
--- a/AUTHORS Sat Nov 10 01:18:15 2007 +0000 +++ b/AUTHORS Sat Nov 10 04:52:20 2007 +0000 @@ -17,6 +17,7 @@ Gadu-Gadu: 1511497 Daniel 'datallah' Atallah - Developer +John 'rekkanoryo' Bailey - Developer Ethan 'Paco-Paco' Blanton - Developer Thomas Butter - Developer Ka-Hing Cheung - Developer @@ -39,8 +40,10 @@ Crazy Patch Writers: ------------------- -John 'rekkanoryo' Bailey -Peter 'Bleeter' Lawler +Dennis 'EvilDennisR' Ristuccia +Peter 'Fmoo' Ruibal +Gabriel 'Nix' Schulhof +Will 'resiak' Thompson Retired Developers: ------------------ @@ -58,6 +61,7 @@ --------------------------- Felipe 'shx' Contreras Decklin Foster +Peter 'Bleeter' Lawler Robert 'Robot101' McQueen Benjamin Miller @@ -71,9 +75,9 @@ GtkSpell <http://gtkspell.sourceforge.net> responsible for the "Highlight misspelled words" feature and for gtk-nativewin <http://bunny.darktech.org/cvs/gtk-nativewin/> the default GTK+-2.0 -engine used in our win32 port. +engine originally used in our win32 port. -** LOGO DESIGNED BY: Naru Sundar ** +** ORIGINAL LOGO DESIGNED BY: Naru Sundar ** Peter Teichiman <peter@helixcode.com> Larry Ewing
--- a/ChangeLog Sat Nov 10 01:18:15 2007 +0000 +++ b/ChangeLog Sat Nov 10 04:52:20 2007 +0000 @@ -26,11 +26,10 @@ is ctrl+t. * 'yank' operation for the entry boxes. The default binding is ctrl+y. -version 2.2.2: - http://developer.pidgin.im/query?status=closed&milestone=2.2.2 - NOTE: Due to 2.2.1 being a security fix release, some bugs - marked fixed in 2.2.1 may not have been fixed until - this release (2.2.2). +version 2.2.3: + http://developer.pidgin.im/query?status=closed&milestone=2.2.3 + NOTE: Some bugs marked fixed in 2.2.1 may not have been fixed + until this release (2.2.3). libpurple: * Real usernames are now shown in the system log. @@ -59,6 +58,20 @@ * ICQ Birthday notifications are shown as buddy list emblems. * Plugin actions are now available from the docklet context menu in addition to the Tool menu of the buddy list. + * The manual page has been heavily rewritten to bring it in line + with current functionality. + +version 2.2.2 (10/23/2007): + http://developer.pidgin.im/query?status=closed&milestone=2.2.2 + NOTE: Due to the way this release was made, it is possible that + bugs marked as fixed in 2.2.1 or 2.2.2 will not be fixed + until the next release. + + * Various bug and memory leak fixes + * Look for a default prefs.xml in the CSIDL_COMMON_APPDATA directory + (e.g. c:\Documents and Settings\All Users\ + Application Data\purple\prefs.xml) on Windows, similarly to + how this is done on other platforms. version 2.2.1 (09/29/2007): http://developer.pidgin.im/query?status=closed&milestone=2.2.1 @@ -92,7 +105,7 @@ * New protocol plugin: MySpaceIM (Jeff Connelly, Google Summer of Code) * XMPP enhancements. See - http://www.adiumx.com/blog/2007/07/soc-xmpp-update.php (Andreas + http://www.adiumx.com/blog/2007/07/soc-xmpp-update.php (Andreas Monitzer, Google Summer of Code for Adium) * Certificate management. Libpurple will validate certificates on SSL-encrypted protocols (William Ehlhardt, Google Summer of Code) @@ -2326,6 +2339,6 @@ * Add/Remove buddy from conversation window * Scroll-Wheel Mice work in Conversation Window * Fixed WindowMaker Appicon - * Version Number in About Box + * version Number in About Box * Gaim Slogan in about box :) * Created Changelog File :)
--- a/ChangeLog.API Sat Nov 10 01:18:15 2007 +0000 +++ b/ChangeLog.API Sat Nov 10 04:52:20 2007 +0000 @@ -114,6 +114,10 @@ * The size parameter of purple_util_write_data_to_file_absolute has been changed to gssize instead of a size_t to correctly indicate that -1 can be used for a nul-delimited string. + * The documentation for purple_savedstatuses_get_popular used to + incorrectly claim that the active status is excluded from the + returned list. The documentation has been corrected. Also, the + function now returns a correct list when called with a value of 0. version 2.2.0 (09/13/2007): libpurple:
--- a/ChangeLog.win32 Sat Nov 10 01:18:15 2007 +0000 +++ b/ChangeLog.win32 Sat Nov 10 04:52:20 2007 +0000 @@ -1,3 +1,20 @@ +version 2.2.3: + * No changes + +version 2.2.2 (10/23/2007): + * Updated gtkspell to include a patch to share Aspell dictionaries + among all the input fields to avoid excessive memory usage. + * Update libxml2 to 2.6.30 + * Bonjour protocol now appears even if Bonjour for Windows isn't + present (displays message indicating Bonjour for Windows must be + installed if you try to log in and it isn't installed). + * libpurple now looks for a default prefs.xml in the COMMON_APPDATA + directory (e.g. \Documents and Settings\All Users\Application Data\purple\prefs.xml) + similarly to how this is done on other platforms. + +version 2.2.1 (09/29/2007): + * No changes + version 2.2.0 (09/13/2007): * Updated gtkspell to 2.0.11 * Upgrade SILC to use the 1.1.2 toolkit
--- a/Makefile.mingw Sat Nov 10 01:18:15 2007 +0000 +++ b/Makefile.mingw Sat Nov 10 04:52:20 2007 +0000 @@ -36,22 +36,36 @@ echo $$gtk_version \ ) +STRIPPED_RELEASE_DIR = $(PIDGIN_TREE_TOP)/pidgin-$(PIDGIN_VERSION)-win32bin + + # Any *.dll or *.exe files included in win32-install-dir that we don't compile # should be included in this list so they don't get stripped EXTERNAL_DLLS = \ + comerr32.dll \ freebl3.dll \ + gssapi32.dll \ + k5sprt32.dll \ + krb5_32.dll \ libgtkspell.dll \ libmeanwhile-1.dll \ + libsasl.dll \ libxml2.dll \ nspr4.dll \ nss3.dll \ nssckbi.dll \ plc4.dll \ plds4.dll \ + saslANONYMOUS.dll \ + saslCRAMMD5.dll \ + saslDIGESTMD5.dll \ + saslGSSAPI.dll \ + saslLOGIN.dll \ + saslPLAIN.dll \ silc.dll \ silcclient.dll \ + smime3.dll \ softokn3.dll \ - smime3.dll \ ssl3.dll #build an expression for `find` to use to ignore the above files @@ -62,33 +76,41 @@ all: $(PIDGIN_CONFIG_H) $(MAKE) -C $(PURPLE_TOP) -f $(MINGW_MAKEFILE) $(MAKE) -C $(PIDGIN_TOP) -f $(MINGW_MAKEFILE) +ifndef DISABLE_NLS $(MAKE) -C $(PURPLE_PO_TOP) -f $(MINGW_MAKEFILE) +endif install: all $(PIDGIN_INSTALL_DIR) $(MAKE) -C $(PURPLE_TOP) -f $(MINGW_MAKEFILE) install $(MAKE) -C $(PIDGIN_TOP) -f $(MINGW_MAKEFILE) install +ifndef DISABLE_NLS $(MAKE) -C $(PURPLE_PO_TOP) -f $(MINGW_MAKEFILE) install +endif $(MAKE) -C share -f $(MINGW_MAKEFILE) install create_release_install_dir: install - rm -rf $(PIDGIN_INSTALL_DIR).release - cp -R $(PIDGIN_INSTALL_DIR) $(PIDGIN_INSTALL_DIR).release - find $(PIDGIN_INSTALL_DIR).release \( -name '*.dll' -o -name '*.exe' \) \ + rm -rf $(STRIPPED_RELEASE_DIR) + cp -R $(PIDGIN_INSTALL_DIR) $(STRIPPED_RELEASE_DIR) + find $(STRIPPED_RELEASE_DIR) \( -name '*.dll' -o -name '*.exe' \) \ -not \( -false $(EXTERNAL_DLLS_FIND_EXP) \) -exec $(STRIP) --strip-unneeded {} ';' installer: create_release_install_dir - $(MAKENSIS) /V3 /DPIDGIN_VERSION="$(PIDGIN_VERSION)" /DPIDGIN_PRODUCT_VERSION="$(PIDGIN_PRODUCT_VERSION)" /DWITH_GTK /DPIDGIN_INSTALL_DIR="$(PIDGIN_INSTALL_DIR).release" /DGTK_INSTALL_VERSION="$(GTK_INSTALL_VERSION)" pidgin/win32/nsis/pidgin-installer.nsi + $(MAKENSIS) /V3 /DPIDGIN_VERSION="$(PIDGIN_VERSION)" /DPIDGIN_PRODUCT_VERSION="$(PIDGIN_PRODUCT_VERSION)" /DWITH_GTK /DPIDGIN_INSTALL_DIR="$(STRIPPED_RELEASE_DIR)" /DGTK_INSTALL_VERSION="$(GTK_INSTALL_VERSION)" pidgin/win32/nsis/pidgin-installer.nsi mv pidgin/win32/nsis/pidgin*.exe ./ installer_nogtk: create_release_install_dir - $(MAKENSIS) /V3 /DPIDGIN_VERSION="$(PIDGIN_VERSION)" /DPIDGIN_PRODUCT_VERSION="$(PIDGIN_PRODUCT_VERSION)" /DPIDGIN_INSTALL_DIR="$(PIDGIN_INSTALL_DIR).release" /DGTK_INSTALL_VERSION="$(GTK_INSTALL_VERSION)" pidgin/win32/nsis/pidgin-installer.nsi + $(MAKENSIS) /V3 /DPIDGIN_VERSION="$(PIDGIN_VERSION)" /DPIDGIN_PRODUCT_VERSION="$(PIDGIN_PRODUCT_VERSION)" /DPIDGIN_INSTALL_DIR="$(STRIPPED_RELEASE_DIR)" /DGTK_INSTALL_VERSION="$(GTK_INSTALL_VERSION)" pidgin/win32/nsis/pidgin-installer.nsi mv pidgin/win32/nsis/pidgin*.exe ./ installer_debug: install $(MAKENSIS) /V3 /DPIDGIN_VERSION="$(PIDGIN_VERSION)" /DPIDGIN_PRODUCT_VERSION="$(PIDGIN_PRODUCT_VERSION)" /DPIDGIN_INSTALL_DIR="$(PIDGIN_INSTALL_DIR)" /DDEBUG /DGTK_INSTALL_VERSION="$(GTK_INSTALL_VERSION)" pidgin/win32/nsis/pidgin-installer.nsi mv pidgin/win32/nsis/pidgin*.exe ./ -installers: installer installer_nogtk installer_debug +installer_zip: create_release_install_dir + rm -f pidgin-$(PIDGIN_VERSION)-win32-bin.zip + zip -9 -r pidgin-$(PIDGIN_VERSION)-win32-bin.zip $(STRIPPED_RELEASE_DIR) + +installers: installer installer_nogtk installer_debug installer_zip Doxyfile.mingw: Doxyfile.in sed -e "s/@PACKAGE@/pidgin/" -e "s/@VERSION@/$(PIDGIN_VERSION)/" -e "s/@top_srcdir@/$(PIDGIN_TREE_TOP)/g" -e "s/@enable_dot@/NO/" Doxyfile.in > Doxyfile.mingw
--- a/NEWS Sat Nov 10 01:18:15 2007 +0000 +++ b/NEWS Sat Nov 10 04:52:20 2007 +0000 @@ -1,5 +1,11 @@ Pidgin and Finch: The Pimpin' Penguin IM Clients That're Good for the Soul +2.2.2 (10/23/2007): + Luke: Because the main branch of pidgin development is still not + ready for public consumption, I have taken some time to try to + pull the many bug fixes that have happened since then into a + separate branch. This release is the result of that effort. + 2.2.1 (9/28/2007): Richard: We have some new code in the pipeline, but it's not quite ready for a general release. Instead, this is basically a bug fix
--- a/config.h.mingw Sat Nov 10 01:18:15 2007 +0000 +++ b/config.h.mingw Sat Nov 10 04:52:20 2007 +0000 @@ -377,7 +377,8 @@ /* #define USE_SM 1 */ /* Version number of package */ -/* #define VERSION "2.0.0dev" */ +#define VERSION "@VERSION@" +#define DISPLAY_VERSION "@VERSION@" /* Define to 1 if your processor stores words with the most significant byte first (like Motorola and SPARC, unlike Intel and VAX). */ @@ -409,3 +410,6 @@ */ #define HAVE_VSNPRINTF 1 +#define HAVE_FILENO 1 + +
--- a/configure.ac Sat Nov 10 01:18:15 2007 +0000 +++ b/configure.ac Sat Nov 10 04:52:20 2007 +0000 @@ -55,7 +55,7 @@ m4_define([gnt_lt_current], [2]) m4_define([gnt_major_version], [2]) m4_define([gnt_minor_version], [2]) -m4_define([gnt_micro_version], [2]) +m4_define([gnt_micro_version], [3]) m4_define([gnt_version_suffix], []) m4_define([gnt_version], [gnt_major_version.gnt_minor_version.gnt_micro_version]) @@ -233,6 +233,30 @@ dnl FreeBSD doesn't have libdl, dlopen is provided by libc AC_CHECK_FUNC(dlopen, LIBDL="", [AC_CHECK_LIB(dl, dlopen, LIBDL="-ldl")]) +AC_MSG_CHECKING(for fileno()) +AC_TRY_RUN([ +#include <stdio.h> + +int main(int argc, char *argv[]) +{ + int fd; + + fd = fileno(stdout); + + return !(fd > 0); +} +], [ + AC_MSG_RESULT(yes) + AC_DEFINE([HAVE_FILENO], [1], + [Define to 1 if your stdio has int fileno(FILE *).]) +], [ + AC_MSG_RESULT(no) +], [ + # Fallback for Cross Compiling... + # This will enable the compatibility code. + AC_MSG_RESULT(no) +]) + AC_MSG_CHECKING(for the %z format string in strftime()) AC_TRY_RUN([ #ifdef HAVE_SYS_TIME_H @@ -283,6 +307,17 @@ AC_SUBST(GLIB_CFLAGS) AC_SUBST(GLIB_LIBS) +AC_ARG_WITH([extraversion], + AC_HELP_STRING([--with-extraversion=STRING], + [extra version number to be displayed in Help->About and --help (for packagers)]), + EXTRA_VERSION=$withval) + +if test x"$EXTRA_VERSION" != "x" ; then + AC_DEFINE_UNQUOTED(DISPLAY_VERSION, "$VERSION-$EXTRA_VERSION", [display version info]) +else + AC_DEFINE_UNQUOTED(DISPLAY_VERSION, "$VERSION", [display version info]) +fi + AC_ARG_WITH(x, [], with_x="$withval", with_x="yes") AC_ARG_ENABLE(gtkui, [AC_HELP_STRING([--disable-gtkui], @@ -2167,66 +2202,34 @@ pidgin/pidgin.pc pidgin/pidgin-uninstalled.pc pidgin/pixmaps/Makefile - pidgin/pixmaps/animations/Makefile - pidgin/pixmaps/animations/16/Makefile - pidgin/pixmaps/buddy_icons/Makefile pidgin/pixmaps/buddy_icons/qq/Makefile - pidgin/pixmaps/dialogs/Makefile pidgin/pixmaps/dialogs/16/Makefile - pidgin/pixmaps/dialogs/16/scalable/Makefile pidgin/pixmaps/dialogs/64/Makefile - pidgin/pixmaps/dialogs/64/scalable/Makefile - pidgin/pixmaps/emblems/Makefile pidgin/pixmaps/emblems/16/Makefile - pidgin/pixmaps/emblems/16/scalable/Makefile - pidgin/pixmaps/emotes/Makefile - pidgin/pixmaps/emotes/default/Makefile pidgin/pixmaps/emotes/default/24/Makefile - pidgin/pixmaps/emotes/default/24/scalable/Makefile pidgin/pixmaps/emotes/none/Makefile - pidgin/pixmaps/icons/Makefile pidgin/pixmaps/icons/16/Makefile - pidgin/pixmaps/icons/16/scalable/Makefile pidgin/pixmaps/icons/22/Makefile - pidgin/pixmaps/icons/22/scalable/Makefile pidgin/pixmaps/icons/24/Makefile - pidgin/pixmaps/icons/24/scalable/Makefile pidgin/pixmaps/icons/32/Makefile - pidgin/pixmaps/icons/32/scalable/Makefile pidgin/pixmaps/icons/48/Makefile - pidgin/pixmaps/icons/48/scalable/Makefile - pidgin/pixmaps/protocols/Makefile pidgin/pixmaps/protocols/16/Makefile - pidgin/pixmaps/protocols/16/scalable/Makefile pidgin/pixmaps/protocols/22/Makefile - pidgin/pixmaps/protocols/22/scalable/Makefile pidgin/pixmaps/protocols/48/Makefile - pidgin/pixmaps/protocols/48/scalable/Makefile - pidgin/pixmaps/status/Makefile pidgin/pixmaps/status/11/Makefile - pidgin/pixmaps/status/11/scalable/Makefile pidgin/pixmaps/status/11/rtl/Makefile pidgin/pixmaps/status/16/Makefile pidgin/pixmaps/status/16/rtl/Makefile - pidgin/pixmaps/status/16/scalable/Makefile pidgin/pixmaps/status/22/Makefile pidgin/pixmaps/status/22/rtl/Makefile - pidgin/pixmaps/status/22/scalable/Makefile pidgin/pixmaps/status/32/Makefile pidgin/pixmaps/status/32/rtl/Makefile - pidgin/pixmaps/status/32/scalable/Makefile pidgin/pixmaps/status/48/Makefile pidgin/pixmaps/status/48/rtl/Makefile - pidgin/pixmaps/toolbar/Makefile pidgin/pixmaps/toolbar/16/Makefile - pidgin/pixmaps/toolbar/16/scalable/Makefile pidgin/pixmaps/toolbar/22/Makefile - pidgin/pixmaps/toolbar/22/scalable/Makefile - pidgin/pixmaps/tray/Makefile pidgin/pixmaps/tray/16/Makefile - pidgin/pixmaps/tray/16/scalable/Makefile pidgin/pixmaps/tray/22/Makefile - pidgin/pixmaps/tray/22/scalable/Makefile pidgin/pixmaps/tray/32/Makefile pidgin/pixmaps/tray/48/Makefile pidgin/plugins/Makefile
--- a/doc/pidgin.1.in Sat Nov 10 01:18:15 2007 +0000 +++ b/doc/pidgin.1.in Sat Nov 10 04:52:20 2007 +0000 @@ -32,7 +32,7 @@ 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 +Pidgin is not endorsed by or affiliated with America Online, ICQ, Microsoft, or Yahoo. .SH OPTIONS @@ -49,6 +49,9 @@ .B \-h, \-\-help Print a summary of command line options and exit. .TP +.B \-m, \-\-multiple +Allow multiple instances of Pidgin to run. +.TP .B \-n, \-\-nologin Don't automatically login when Pidgin starts. Sets the global status to \fBOffline\fR. @@ -68,9 +71,9 @@ The \fBBuddy List\fR window contains a list of your buddies who are online and have allowed you to be notified of their presence. The icon to the -left of each buddy indicates the buddy's current state and the protocol -they are using. Double clicking a buddy will open a new \fBConversation\fR -window. Right clicking will pop up a menu: +left of each buddy indicates the buddy's current status. Double clicking +a buddy will open a new \fBConversation\fR window. Right clicking will +pop up a menu: .TP .B Get Info Retrieves and displays information about the buddy. This information is @@ -89,16 +92,17 @@ discussed later. .TP .B View Log -Pidgin is capable of automatically log its activities. These logs are +Pidgin is capable of automatically logging messages. These logs are either plain text files (with a .txt extension) or html files (with a \&.html extension) located under the \fI~/.purple/logs\fR directory. This menu command will display Pidgin's log viewer with logs loaded for that buddy or chat. .TP .B Alias -Create an alias for this buddy. This will open up a new dialog in which -one can give this buddy an alternate name to appear on the buddy list and -in conversations. +Create an alias for this buddy. This will show an editable text field where +the buddy's screen name was displayed. In this field one can give this +buddy an alternate, more friendly name to appear on the buddy list and in +conversations. For example, if a buddy's name screen name was jsmith1281xx and his real name was 'John Q. Smith,' one could create an alias as to identify the @@ -106,39 +110,27 @@ .LP The remainder of the menu will consist of protocol specific commands. These commands vary depending on the protocol. -.LP -At the bottom of the \fBBuddy List\fR are several buttons (if enabled in -\fBPreferences\fR): .TP -.B IM -Opens a new \fBConversation\fR window to to the selected buddy, or brings -up the \fBNew Message\fR dialog box if no buddy is selected. -.TP -.B Info -Retrieves and display information about the selected buddy, or brings up -the \fBGet User Info\fR dialog box if no buddy is selected. -.TP -.B Chat -Brings up the \fBJoin Chat\fR dialog box, prompting the user to select -which username to use and what chat group to join. -.TP -.B Away -Brings up a menu of all available \fBAway Messages\fR. If an item is -selected, all online accounts will use this item as their away message. +.B Status Selector +At the bottom of the \fBBuddy List\fR is a status selector which allows one to +change his/her status. This will be discussed further in the \fBSTATUS +MESSAGES\fR section below. .SH ACCOUNT EDITOR The account editor consists of a list of accounts and information about -them. Clicking \fIDelete\fR will delete the currently selected account. +them. It can be accessed by selecting \fBManage\fR from the Tools menu. +Clicking \fIDelete\fR will delete the currently selected account. Clicking \fIAdd\fR or \fIModify\fR will invoke a \fBModify Account\fR window. Here, you can add or alter account information. When creating a new account, you will submit your screen name and password. You will also choose your protocol. If \fIRemember Password\fR is chosen, the password will be saved in -Pidgin's configuration file. +Pidgin's \fI~/.purple/accounts.xml\fR configuration file. -If \fIAuto-Login\fR is chosen, this account will automatically login upon -starting Pidgin. +If \fIEnabled\fR is checked in the accounts dialog, this account will +follow the status currently selected in the status selector. If it is +not checked, the account will always be offline. Each protocol has its own specific options that can be found in the modify screen. @@ -149,120 +141,84 @@ .SH Interface -\fIDisplay remote nicknames if no alias is set\fR: Toggles whether server -nickname data should be used if no local alias exists. - -.SH Buddy List -\fISorting\fR: Toggles the order in which buddies are shown in your -\fBBuddy List\fR between none, alphabetical, by status and by log size. +.TP +.B Show system tray icon +Specifies when to show a Pidgin icon in the notification area of your +panel (commonly referred to as the System Tray). -\fIShow buttons as\fR: Toggles between picture-only, text-only, picture and -text or no buttons view of the buttons on the \fBBuddy List\fR. - -\fIRaise window on events\fR: Tells Pidgin to bring the \fBBuddy -List\fR window to the top when buddies sign in or out. - -\fIShow numbers in groups\fR: The number of buddies from each group -currently logged in will be shown along with the total number of buddies in -the group. +.TP +.B Hide new IM conversations +Specifies when to hide new IM messages. Messages will queue under the +specified condition until shown. Clicking the Pidgin icon in the +notification area or system tray will display the queued messages. An +icon also appears in the buddy list's menu bar; this icon may also be +used to display queued messages. -\fIShow buddy icons\fR: Toggles the display of buddies' custom icons. - -\fIShow warning levels\fR: Each buddy's warning level will be displayed -next to the screen name. As a buddy's warning level increases, outgoing -messages are more and more severely rate-limited. +.TP +.B Show IMs and chats in tabbed windows +When checked, this option will cause IM and chat sessions to appear in +windows with multiple tabs. One tab will represent one conversation or +chat. Where tabs are placed will be dictated by the preferences below. -\fIShow idle times\fR: The amount of time each buddy has been idle will be -displayed next to the screen name (if the buddy has opted to have their -client report this information). +.TP +.B Show close buttons on tabs +When checked, this option will cause a clickable "U+2715 MULTIPLICATION X" +unicode character to appear at the right edge of each tab. Clicking this +will cause the tab to be closed. -\fIDim idle buddies\fR: If enabled, idle buddies will be displayed in grey -text instead of black text. +.TP +.B Placement +Specifies where to place tabs in the window. Some tab orientations may +allow some users to fit more tabs into a single window comfortably. -\fIAutomatically expand contacts\fR: If enabled, contacts will -automatically expand to show the associated buddies when the mouse is held -over the contact for a short period. +.TP +.B New conversations +Specifies under which conditions tabs are placed into existing windows or +into new windows. For a single window, select \fILast created window\fR here. .SH Conversations -\fIShow buttons as...\fR: The selected item will determine whether -picture-only, text-only, combined picture/text, or no buttons will be used -for \fBConversation\fR windows. - -\fIShow formatting toolbar\fR: Display the formatting toolbar between the -upper and lower text boxes in conversations. - -\fIShow aliases in tabs/titles\fR: Displays buddy alias instead of screen -name in window tabs and titles. - -\fIShow buddy icons\fR: For protocols that support it, buddy icons allow -buddies to send small pictures to be displayed during the course of a -conversation. Turning this option off hides those pictures. - -\fIEnable buddy icon animation\fR: If these pictures happen to be animated, -this option will enable the animation, otherwise only the first frame will -be displayed. - -\fINotify buddies that you are typing to them\fR: Some protocols allow -clients to tell their buddies when they are typing. This option enables -this feature for protocols that supports it. - -\fIRaise IM windows on events\fR: If enabled, IM \fBConversation\fR windows -will be brought to the top when new messages are received. - -\fIRaise Chat windows on events\fR: If enabled, chat \fBConversation\fR windows -will be brought to the top when new messages are received. - -\fIUse multi-colored screen names in chats\fR: Color code the screen names of -users in chat rooms. +.TP +.B Enable buddy icon animation +If a buddy's icon happens to be animated, this option will enable the +animation, otherwise only the first frame will be displayed. .TP -.B Tab Options -\fIShow IMs and chats in tabbed windows\fR: Tabbed chatting allows one to -have multiple conversations without multiple windows. - -\fIShow close buttons on tabs\fR: Adds a close button to each tab. - -\fITab Placement...\fR: Specifies where tabs are shown in the conversation -window. - -\fI New conversation placement...\fR: Determines where new conversations will -be placed (Last created window / New window / windows grouped by group or -account / separate windows for IMs and Chats). +.B Notify buddies that you are typing to them +Some protocols allow clients to tell their buddies when they are typing. +This option enables this feature for protocols that supports it. For XMPP, +this also enables sending the "User has left the conversation" message +when ending the conversation. .TP -.B Message Text -\fIShow timestamp on messages\fR: Toggles the timestamp behavior for -conversations. Per-conversation behavior can be changed by pressing -\fIF2\fR in the \fBConversation\fR window. - -\fIHighlight misspelled words\fR: Toggles highlighting of misspelled words -as you type. - -\fIIgnore colors/font faces/font sizes\fR: Tells Pidgin to disregard -buddies' color/font/size information in displaying IMs or Chats. +.B Default Formatting +Allows specifying the default formatting to apply to all outgoing messages +(only applicable to protocols that support formatting in messages). -\fIDefault Formatting\fR: Allows specifying the default formatting to apply -to all outgoing messages (only applicable to protocols that support -formatting in messages). - -.TP -.B Shortcuts -Allows the user to determine which keyboard shortcuts are available. - -.TP -.B Smiley Themes +.SH Smiley Themes Allows the user to choose between different smiley themes. The "none" theme will disable graphical emoticons - they will be displayed as text instead. +The \fBAdd\fR and \fBRemove\fR buttons may be used to install or uninstall +smiley themes. Themes may also be installed by dragging and dropping them +onto the list of themes. .SH Sounds -\fISounds while away\fR: Determines whether sounds are played when an away -message is up. +.TP +.B Method +Lets the user choose between different playback methods. The user can also +manually enter a command to be executed when a sound is to be played\ +(\fI%s\fR expands to the full path to the file name). -\fISound Method\fR lets the user choose between different playback methods. -The user can also manually enter a command to be executed when a sound is -to be played (\fI%s\fR expands to the full path to the file name). +.TP +.B Sounds when conversation has focus +When checked, sounds will play for events in the active conversation if +the window is focused. When unchecked, sounds will not play for the +active conversation when the window is focused. + +.TP +.B Enable Sounds +Determines when to play sounds. .TP .B Sound Events @@ -271,17 +227,28 @@ .SH Network .TP -.B IP Address -\fIAutodetect IP Address\fR: Pidgin will attempt to automatically determine -your IP address for use in file transfers and Direct IMs. - -\fIPublic IP\fR: What IP address to use for file transfer and Direct IMs. This -is mainly useful for users with multiple network interfaces or behind NAT. +.B STUN server +This allows specifying a server which uses the STUN protocol to determine +a host's public IP address. This can be particularly useful for some +protocols. .TP -.B Ports -\fIManually specify range of ports to listen on\fR: Specify specific ports to -listen on, overriding any defaults. +.B Autodetect IP address +When checked, causes Pidign to attempt to determine the public IP address +of the host on which Pidgin is running and disables the \fBPublic IP\fR +text field listed below. + +.TP +.B Public IP +If \fBAutodetect IP address\fR is disabled, this field allows manually +specifying the public IP address for the host on which Pidgin is running. +This is mainly useful for users with multiple network interfaces or behind +NATs. + +.TP +.B Manually specify range of ports to listen on +Specify a range ports to listen on, overriding any defaults. This is +sometimes useful for file transfers and Direct IM. .TP .B Proxy Server @@ -290,132 +257,107 @@ .SH Browser +.TP +.B Browser Allows the user to select Pidgin's default web browser. Firefox, Galeon, Konqueror, Mozilla, Netscape and Opera are supported natively. The user can also manually enter a command to be executed when a link is clicked (\fI%s\fR expands to the URL). For example, \fIxterm -e lynx "%s"\fR will -open the link with lynx. \fIOpen new window by default\fR makes the -browser use a new window instead of using the current window (or spawning a -new tab). +open the link with lynx. + +.TP +.B Open link in +Allows the user to specify whether to use an existing window, a new tab, a +new window, or to let the browser to decide what to do when calling the +browser to open a link. Which options are available will depend on which +browser is selected. .SH Logging -\fIMessage Logs\fR lets the user choose whether \fBConversations\fR and/or -\fBBuddy Chats\fR will be logged as well as whether logs will be in HTML or -plain text format. \fISystem Logs\fR describes the types of events to be -logged. +.TP +.B Log format +Specifies how to log. Pidgin supports HTML and plain text, but plugins can +provide other logging methods. -.SH Away / Idle - -\fIQueue new messages when away\fR: Messages received since going Away will -not be shown until away status is removed. +.TP +.B Log all instant messages +When enabled, all IM conversations are logged. This can be overridden on a +per-conversation basis in the conversation window. -\fISend auto-response\fR: If someone messages you while away, your -auto-response will be sent. +.TP +.B Log all chats +When enabled, all chat conversations are logged. This can be overridden on a +per-conversation basis in the conversation window. -\fIOnly send auto-response when idle\fR: If someone messages you while -away, your auto-response will only be sent if Pidgin decides that the -connection is idle. +.TP +.B Log all status changes to system log +When enabled, status changes are logged. -\fIIdle time reporting\fR: If \fINone\fR is selected, account idle time -will not be reported. \fIPidgin usage\fR infers your idle time from your -usage of Pidgin. \fIX usage\fR infers your idle time from \fBX\fR -(this option may not be universally available). +.SH Status / Idle -\fIAuto-away\fR: Determines if and under what conditions Pidgin will -automatically turn on the Away status. +.TP +.B Report idle time +Determines under which conditions to report idle time. \fBBased on keyboard +and mouse use\fR uses keyboard and mouse activity to determine idle time. +\fBFrom last sent message\fR uses the time at which you last sent a message +in Pidgin to determine idle. \fBNever\fR disables idle reporting. .TP -.B Away Messages -Lets the user add/edit/remove available \fBAway Messages\fR. +.B Auto-reply +Determines when to send an auto-reply on protocols which support it +(currently only AIM). -.SH Plugins +.TP +.B Change status when idle +When enabled, this uses the \fBMinutes before becoming idle\fR and \fBChange +status to\fR preferences described below to set status on idle. + +.TP +.B Minutes before becoming idle +Specifies how many minutes of inactivity are required before considering the +user to be idle. -Allows the user to enable add-on plugins for Pidgin. Several of these -come with Pidgin, while others must be downloaded separately. The -\fIDescription\fR field gives the plugin author's description of the -plugin, while the \fIDetails\fR field gives the plugin's authorship, URL, -and file name/location information. +.TP +.B Change status to +Specifies which "primitive" or "saved" status to use when setting status on +idle. -Some plugins can be configured. If you load such a plugin, its -configuration preferences will appear as a submenu to \fBPlugins\fR, with -the submenu title determined by the plugin's name. +.TP +.B Use status from last exit at startup +If this is checked, Pidgin will remember what status was active when the +user closed Pidgin and restore it at the next run. When disabled, Pidgin +will always set the status selected in \fBStatus to apply at startup\fR +at startup. -.SH Protocols - -Protocols provide protocol specific preferences here. +.TP +.B Status to apply at startup +When \fBUse status from last exit at startup\fR is disabled, this specifies +which "primitive" or "saved" status to use at startup. .SH CONVERSATIONS When starting a new conversation, the user is presented with the \fBConversation\fR window. The conversation appears in the upper text box and the user types his/her message in the lower text box. Between the two -is a row of settings, represented by icons. Some or all buttons may not be +is a row of options, represented by icons. Some or all buttons may not be active if the protocol does not support the specific formatting. From left to right: .TP -.B Bold -Turns on/off bold. -.TP -.B Italics -Turns on/off italics. -.TP -.B Underline -Turns on/off underline. -.TP -.B Decrease font size -Increases the size of the message text. -.TP -.B Increase font size -Decreases the size of the message text. +.B Font +This menu provides font control options for the current conversation. Size, +style, and face may be configured here. .TP -.B Select a foreground color -Changes the foreground color of the message text. -.TP -.B Select a background color -Changes the background color of the message text. -.TP -.B Add image -Inserts an in-line image in the message. -.TP -.B Add hyperlink -Adds a clickable link to the message. -.TP -.B Add smiley -Adds an emoticon (smiley) to your message. - -Beneath the lower text box is a row of buttons that execute commands: +.B Insert +This menu provides the ability to insert images, horizontal rules, and links +where the protocol supports each of these features. .TP -.B Warn -This issues a warning to the other person in the conversation (not -available in all protocols). -.TP -.B Block -This adds the other person to your deny list (not available in all -protocols). -.TP -.B Send File -Send a file to this user. This option is only available on protocols where -Pidgin supports file transfer. -.TP -.B Add -This adds this user to your buddy list. This option is not available if -the user is already on your list. -.TP -.B Remove -This removes this user from your buddy list. This option is not available -if the user is not on your list. -.TP -.B Info -This gets information (a profile) about the other person in the -conversation (not available in all protocols). -.TP -.B Send -This sends what's currently in the lower text box +.B Smile! +Allows the insertion of graphical smileys via the mouse. This button shows +the user a dialog with the available smileys for the current conversation. -.SH BUDDY CHATS -For protocols that allow it, \fBBuddy Chats\fR can be entered through the -\fIFile\fR menu or the \fIChat\fR button at the bottom of the \fBBuddy -List\fR's \fBOnline\fR tab. +.SH CHATS +For protocols that allow it, \fBChats\fR can be entered through the +\fIBuddies\fR menu. + Additional commands available in chat, depending on the protocol are: .TP @@ -433,77 +375,151 @@ Set the topic of the chat room. This is usually a brief sentence describing the nature of the chat--an explanation of the chat room's name. -.SH AWAY MESSAGES -Most protocols allow for away messages. When a user is \fIAway\fR, he can -leave an informative message for others to see. The \fBAway\fR submenu of -the \fBTools\fR menu is used to add and remove away messages. +.SH STATUS MESSAGES +Most protocols allow for status messages. By using status messages, a user +can leave an informative message for others to see. Status and status +messages are configured via the status selector at the bottom of the Buddy +List window. By default the menu shown here is divided into sections for +"primitive" status types, such as \fIAvailable\fR, \fIAway\fR, etc.; a few +"popular" statuses (including "transient" statuses) which have been +recently used, and a section which shows \fBNew Status...\fR and \fBSaved +Statuses...\fR options for more advanced status manipulation. + +.TP +.B Primitive Statuses +A primitive status is a basic status supported by the protocol. Examples of +primitive statuses would be Available, Away, Invisible, etc. A primitive +status can be used to create a \fBTransient Status\fB or a \fBSaved Status\fR, +both explained below. Essentially, primitive statuses are building blocks +of more complicated statuses. + +.TP +.B Transient Statuses +When one of the statuses from the topmost section of the status selector's +menu is selected, this creates a transient, or temporary, status. The status +will show in the "popular statuses" section in the menu until it has not been +used for a sufficiently long time. A transient status may also be created by +selecting \fINew Status...\fR from the status selector's menu, then clicking +\fIUse\fR once the user has entered the message. -\fINew Away Message\fR provides space for one to enter an away message and -a title for that message. If \fISave\fR or \fISave & Use\fR are chosen, -this message will be saved. It can later be referred to by the title given -to it. +.TP +.B Saved Statuses +Saved statuses are permanent--once created, they will exist until deleted. +Saved statuses are useful for statuses and status messages that will be used +on a regular basis. They are also useful for creating complex statuses in +which some accounts should always have a different status from others. For +example, one might wish to create a status called "Sleeping" that has all +accounts set to "Away", then create another status called "Working" that +has three accounts set to "Away" and another account set to "Available." + +.TP +.B New Status Window +When the user selects \fINew Status...\fR from the status selector menu, +Pidgin presents the user with a dialog asking for status-related information. +That information is discussed below: + +\fITitle\fR - The name of the status that will appear in the status selctor's +menu. If the user clicks the \fISave\fR or \fISave & Use\fR button, this +name will also be shown in the \fBSaved Status Window\fR. The title should +be a short description of the status. + +\fIStatus\fR - The type of status being created, such as Available, Away, etc. -\fIRemove Away Message\fR is a submenu containing the titles of saved away -messages. Clicking on one of these titles will remove the away message -associated with it. +\fIMessage\fR - The content of the status message. This is what is visible +to other users. Some protocols will allow formatting in some status messages; +where formatting is not supported it will be stripped to the bare text entered. -The rest of the \fIaway\fR menu provides the user with a way to assign -different away messages to different connections. Choosing \fISet All -Away\fR will set away all the connections capable of the away state. +\fIUse a different status for some accounts\fR - This allows the creation of +complex statuses in which some accounts' status differs from that of other +accounts. To use this, the user will click the expander to the left of the +text, then select individual accounts which will have a different status +and/or status message. When the user selects an account, Pidgin will present +another status dialog asking for a status and a message just for the selected +account. + +.TP +.B Saved Status Window +When the user selects \fISaved Statuses...\fR from the status selector's menu, +Pidgin presents a dialog that lists all saved statuses. "Transient" statuses, +discussed above, are \fB\fINOT\fR\fR shown here. This window provides the +ability to manage saved statuses by allowing the creation, modification, and +deletion of saved statuses. The \fIUse\fR, \fIModify\fR, and \fIDelete\fR +buttons here allow operation on the status selected from the list; the \fAdd\fR +button allows creation of a new saved status, and the \fIClose\fR button closes +the window. .SH BUDDY POUNCE A Buddy Pounce is an automated trigger that occurs when a buddy returns to -a normal state from an away state. The \fBNew Buddy Pounce\fR dialog box -can be activated by selecting the \fIBuddy Pounce\fR submenu from the -\fBTools\fR menu. A pounce can be set to occur on any combination of the -events listed, and any combination of actions can result. If \fISave this -pounce after activation\fR is checked, the trigger will remain until it is -removed from the \fIRemove Buddy Pounce\fR menu. +a normal state from an away state. The \fBBuddy Pounce\fR dialog box +can be activated by selecting the \fIBuddy Pounce\fR option from the +\fBTools\fR menu. From this dialog, new pounces can be created with the +\fBAdd\fR button and existing pounces can be removed with the \fBDelete\fR +button. A pounce can be set to occur on any combination of the +events listed, and any combination of actions can result. If \fIPounce +only when my status is not Available\fR is checked, the pounce will occur +only if you are set to a non-available status, such as invisible, do not +disturb, away, etc. If \fIRecurring\fR is checked, the pounce will remain +until removed by the \fBDelete\fR button. .SH PLUGINS Pidgin allows for dynamic loading of plugins to add extra functionality -to Pidgin. Plugins can be enabled and configured from the -\fBPreferences\fR window. See \fIplugins/HOWTO\fR for more information on -writing plugins. +to Pidgin. See \fIplugins/HOWTO\fR or +\fIhttp://developer.pidgin.im/wiki/CHowTo\fR for information on writing +plugins. + +The plugins dialog can be accessed by selecting Plugins from the Tools menu. +Each plugin available appears in this dialog with its name, version, and a +short summary of its functionality. Plugins can be enabled with the checkbox +beside the name and short description. More information on the currently +selected plugin is available by clicking the expander beside the text +\fIPlugin Details\fR. If the selected plugin has preferences or configuration +options, the \fIConfigure Plugin\fR button will present the plugin's +preferences dialog. .SH PERL -Pidgin allows for perl scripting. See \fIPerl Scripting HOWTO\fR in -the Pidgin documentation for more information about perl scripting. +Pidgin allows for plugins to be written in the perl scripting language. See +\fIPerl Scripting HOWTO\fR in the Pidgin documentation for more information +about perl scripting. .SH TCL -Pidgin allows for Tcl scripting. See \fIplugins/tcl/TCL-HOWTO\fR for -more information about Tcl scripting. +Pidgin allows for plugins to be written in the Tcl scripting language. See +\fIplugins/tcl/TCL-HOWTO\fR for more information about Tcl scripting. + +.SH D-Bus +Pidgin allows for interaction via D-Bus. Currently very little documentation +on this interaction exists. .SH FILES -\fI@prefix@/bin/pidgin\fR: Pidgin's location. + \fI@prefix@/bin/pidgin\fR: Pidgin's location. .br -\fI@prefix@/lib/pidgin/\fR: Pidgin's plugins directory. + \fI~/.purple/blist.xml\fR: the buddy list. .br -\fI~/.purple/prefs.xml\fR: Pidgin's configuration file. + \fI~/.purple/accounts.xml\fR: information about your accounts. .br -\fI~/.purple/accounts.xml\fR: information about your accounts. + \fI~/.purple/pounces.xml\fR: stores your buddy pounces. +.br + \fI~/.purple/prefs.xml\fR: Pidgin's configuration file. .br -\fI~/.purple/status.xml\fR: stores your away messages. -.br -\fI~/.purple/pounces.xml\fR: stores your buddy pounces. + \fI~/.purple/status.xml\fR: stores your away messages. .br -\fI~/.purple/logs/PROTOCOL/ACCOUNT/SCREENNAME/DATE.{html,txt}\fR: conversation logs. + \fI~/.purple/logs/PROTOCOL/ACCOUNT/SCREENNAME/DATE.{html,txt}\fR: conversation logs. + +.SH DIRECTORIES + \fI@prefix@/lib/pidgin/\fR: Pidgin's plugins directory. .br -\fI~/.purple/blist.xml\fR: the buddy list. + \fI@prefix@/lib/purple-2/\fR: libpurple's plugins directory. .br -\fI~/.purple/plugins/\fR: users local plugins + \fI~/.purple\fR: users' local settings +.br + \fI~/.purple/plugins/\fR: users' local plugins .SH BUGS -The bug tracker can be reached by visiting: -.br -\fIhttp://developer.pidgin.im/report\fR +The bug tracker can be reached by visiting \fIhttp://developer.pidgin.im/query\fR .SH PATCHES If you fix a bug in Pidgin (or otherwise enhance it), please submit a patch (using \fImtn diff > my.diff\fR against the latest version from the -Monotone repository) at -.br -\fIhttp://developer.pidgin.im/newticket\fR +Monotone repository) at \fIhttp://developer.pidgin.im/simpleticket\fR Before sending a bug report, please verify that you have the latest version of Pidgin. Many bugs (major and minor) are fixed @@ -530,86 +546,109 @@ .SH AUTHORS Pidgin's active developers are: - - Sean Egan (lead developer) <\fIseanegan@gmail.com\fR> +.br + Sean Egan (lead developer) <\fIseanegan@gmail.com\fR> .br - Daniel 'datallah' Atallah (developer) + Daniel 'datallah' Atallah (developer) .br - Ethan 'Paco-Paco' Blanton (developer) + John 'rekkanoryo' Bailey (developer) .br - Thomas Butter (developer) + Ethan 'Paco-Paco' Blanton (developer) .br - Ka-Hing Cheung (developer) + Thomas Butter (developer) .br - Sadrul Habib Chowdhury (developer) + Ka-Hing Cheung (developer) +.br + Sadrul Habib Chowdhury (developer) .br - Mark 'KingAnt' Doliner (developer) <\fIthekingant@users.sourceforge.net\fR> + Mark 'KingAnt' Doliner (developer) <\fIthekingant@users.sourceforge.net\fR> .br - Christian 'ChipX86' Hammond (developer & webmaster) <\fIchipx86@chipx86.com\fR> + Casey Harkins (developer) .br - Gary 'grim' Kramlich (developer) + Gary 'grim' Kramlich (developer) .br - Richard 'rlaager' Laager (developer) <\fIrlaager@pidgin.im\fR> + Richard 'rlaager' Laager (developer) <\fIrlaager@pidgin.im\fR> .br - Richard 'wabz' Nelson (developer) + Richard 'wabz' Nelson (developer) +.br + Christopher 'siege' O'Brien (developer) .br - Christopher 'siege' O'Brien (developer) + Bartosz Oler (developer) .br - Bartosz Oler (developer) + Etan 'deryni' Reisner (developer) .br - Etan 'deryni' Reisner (developer) + Tim 'marv' Ringenbach (developer) <\fImarv_sf@users.sf.net\fR> .br - Tim 'marv' Ringenbach (developer) <\fImarv_sf@users.sf.net\fR> + Luke 'LSchiere' Schierer (support) .br - Luke 'LSchiere' Schierer (support) + Megan 'Cae' Schneider (support/QA) .br - Megan 'Cae' Schneider (support/QA) + Evan Schoenberg (developer) .br - Evan Schoenberg (developer) + Kevin 'SimGuy' Stange (developer and webmaster) .br - Stu 'nosnilmot' Tomlinson (developer) + Stu 'nosnilmot' Tomlinson (developer) .br - Nathan 'faceprint' Walp (developer) + Nathan 'faceprint' Walp (developer) .br Our crazy patch writers include: - -John 'rekkanoryo' Bailey +.br + Dennis 'EvilDennisR' Ristuccia .br -Felipe 'shx' Contreras + Peter 'fmoo' Ruibal .br -Decklin Foster + Gabriel 'Nix' Schulhof .br -Casey Harkins -.br -Peter 'Bleeter' Lawler + Will 'resiak' Thompson .br -Robert 'Robot101' McQueen + + +Our artists are: .br -Benjamin Miller -.br -Kevin 'SimGuy' Stange + Hylke Bons <\fIh.bons@student.rug.nl\fR> .br -The retired developers of \fBgaim\fR are: - - Herman Bloggs (win32 port) <\fIherman@bluedigits.com\fR> +Our retired developers are: +.br + Herman Bloggs (win32 port) <\fIherman@bluedigits.com\fR> .br - Jim Duchek <\fIjim@linuxpimps.com\fR> (maintainer) + Jim Duchek <\fIjim@linuxpimps.com\fR> (maintainer) .br - Rob Flynn <\fIgaim@robflynn.com\fR> (maintainer) + Rob Flynn <\fIgaim@robflynn.com\fR> (maintainer) +.br + Adam Fritzler (libfaim maintainer) .br - Adam Fritzler (libfaim maintainer) + Christian 'ChipX86' Hammond (developer & webmaster) <\fIchipx86@chipx86.com\fR> .br - Syd Logan (hacker and designated driver [lazy bum]) + Syd Logan (hacker and designated driver [lazy bum]) .br - Jim Seymour (Jabber developer) + Jim Seymour (XMPP developer) .br - Mark Spencer (original author) <\fImarkster@marko.net\fR> + Mark Spencer (original author) <\fImarkster@marko.net\fR> .br - Eric Warmenhoven (former lead developer) <\fIeric@warmenhoven.org\fR> + Eric Warmenhoven (former lead developer) <\fIeric@warmenhoven.org\fR> .br -This manpage was originally written by Dennis Ristuccia <\fIdennis@dennisr.net\fR>. It has been updated and largely rewritten by Sean Egan <\fIseanegan@gmail.com\fR> and Ben Tegarden <\fItegarden@uclink.berkeley.edu\fR>. + +Our retired crazy patch writers include: +.br + Felipe 'shx' Contreras +.br + Decklin Foster +.br + Peter 'Bleeter' Lawler +.br + Robert 'Robot101' McQueen +.br + Benjamin Miller +.br + + +This manpage was originally written by Dennis Ristuccia +<\fIdennis@dennisr.net\fR>. It has been updated and largely rewritten by +Sean Egan <\fIseanegan@gmail.com\fR>, +Ben Tegarden <\fItegarden@uclink.berkeley.edu\fR>, +and John Bailey <\fIrekkanoryo@pidgin.im\fR>.
--- a/finch/finch.c Sat Nov 10 01:18:15 2007 +0000 +++ b/finch/finch.c Sat Nov 10 04:52:20 2007 +0000 @@ -203,7 +203,7 @@ char *text; if (terse) { - text = g_strdup_printf(_("%s. Try `%s -h' for more information.\n"), VERSION, name); + text = g_strdup_printf(_("%s. Try `%s -h' for more information.\n"), DISPLAY_VERSION, name); } else { text = g_strdup_printf(_("%s\n" "Usage: %s [OPTION]...\n\n" @@ -211,7 +211,7 @@ " -d, --debug print debugging messages to stdout\n" " -h, --help display this help and exit\n" " -n, --nologin don't automatically login\n" - " -v, --version display the current version and exit\n"), VERSION, name); + " -v, --version display the current version and exit\n"), DISPLAY_VERSION, name); } purple_print_utf8_to_console(stdout, text); @@ -298,7 +298,7 @@ /* Translators may want to transliterate the name. It is not to be translated. */ gnt_quit(); - printf("%s %s\n", _("Finch"), VERSION); + printf("%s %s\n", _("Finch"), DISPLAY_VERSION); return 0; }
--- a/finch/gntconv.c Sat Nov 10 01:18:15 2007 +0000 +++ b/finch/gntconv.c Sat Nov 10 04:52:20 2007 +0000 @@ -1033,7 +1033,7 @@ PurpleCmdStatus status; if (!g_ascii_strcasecmp(args[0], "version")) { - tmp = g_strdup_printf("me is using Finch v%s.", VERSION); + tmp = g_strdup_printf("me is using Finch v%s.", DISPLAY_VERSION); markup = g_markup_escape_text(tmp, -1); status = purple_cmd_do_command(conv, tmp, markup, error);
--- a/finch/libgnt/gntfilesel.c Sat Nov 10 01:18:15 2007 +0000 +++ b/finch/libgnt/gntfilesel.c Sat Nov 10 04:52:20 2007 +0000 @@ -265,6 +265,7 @@ } g_free(fp); } + g_dir_close(dir); *files = g_list_reverse(*files); return TRUE;
--- a/finch/libgnt/gntstyle.h Sat Nov 10 01:18:15 2007 +0000 +++ b/finch/libgnt/gntstyle.h Sat Nov 10 04:52:20 2007 +0000 @@ -122,3 +122,4 @@ */ void gnt_uninit_styles(void); +
--- a/finch/plugins/gntclipboard.c Sat Nov 10 01:18:15 2007 +0000 +++ b/finch/plugins/gntclipboard.c Sat Nov 10 04:52:20 2007 +0000 @@ -156,7 +156,7 @@ PURPLE_PRIORITY_DEFAULT, "gntclipboard", N_("GntClipboard"), - VERSION, + DISPLAY_VERSION, N_("Clipboard plugin"), N_("When the gnt clipboard contents change, " "the contents are made available to X, if possible."),
--- a/finch/plugins/gntgf.c Sat Nov 10 01:18:15 2007 +0000 +++ b/finch/plugins/gntgf.c Sat Nov 10 04:52:20 2007 +0000 @@ -375,7 +375,7 @@ PURPLE_PRIORITY_DEFAULT, "gntgf", N_("GntGf"), - VERSION, + DISPLAY_VERSION, N_("Toaster plugin"), N_("Toaster plugin"), "Sadrul H Chowdhury <sadrul@users.sourceforge.net>",
--- a/finch/plugins/gnthistory.c Sat Nov 10 01:18:15 2007 +0000 +++ b/finch/plugins/gnthistory.c Sat Nov 10 04:52:20 2007 +0000 @@ -177,7 +177,7 @@ PURPLE_PRIORITY_DEFAULT, HISTORY_PLUGIN_ID, N_("GntHistory"), - VERSION, + DISPLAY_VERSION, N_("Shows recently logged conversations in new conversations."), N_("When a new conversation is opened this plugin will insert " "the last conversation into the current conversation."),
--- a/finch/plugins/lastlog.c Sat Nov 10 01:18:15 2007 +0000 +++ b/finch/plugins/lastlog.c Sat Nov 10 04:52:20 2007 +0000 @@ -120,7 +120,7 @@ PURPLE_PRIORITY_DEFAULT, "gntlastlog", N_("GntLastlog"), - VERSION, + DISPLAY_VERSION, N_("Lastlog plugin."), N_("Lastlog plugin."), "Sadrul H Chowdhury <sadrul@users.sourceforge.net>",
--- a/libpurple/account.c Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/account.c Sat Nov 10 04:52:20 2007 +0000 @@ -52,7 +52,7 @@ { int integer; char *string; - gboolean bool; + gboolean boolean; } value; @@ -107,7 +107,7 @@ } else if (setting->type == PURPLE_PREF_BOOLEAN) { xmlnode_set_attrib(child, "type", "bool"); - snprintf(buf, sizeof(buf), "%d", setting->value.bool); + snprintf(buf, sizeof(buf), "%d", setting->value.boolean); xmlnode_insert_data(child, buf, -1); } } @@ -1620,7 +1620,7 @@ setting = g_new0(PurpleAccountSetting, 1); setting->type = PURPLE_PREF_BOOLEAN; - setting->value.bool = value; + setting->value.boolean = value; g_hash_table_insert(account->settings, g_strdup(name), setting); @@ -1706,7 +1706,7 @@ setting->type = PURPLE_PREF_BOOLEAN; setting->ui = g_strdup(ui); - setting->value.bool = value; + setting->value.boolean = value; table = get_ui_settings_table(account, ui); @@ -1981,7 +1981,7 @@ g_return_val_if_fail(setting->type == PURPLE_PREF_BOOLEAN, default_value); - return setting->value.bool; + return setting->value.boolean; } int @@ -2047,7 +2047,7 @@ g_return_val_if_fail(setting->type == PURPLE_PREF_BOOLEAN, default_value); - return setting->value.bool; + return setting->value.boolean; } PurpleLog *
--- a/libpurple/buddyicon.c Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/buddyicon.c Sat Nov 10 04:52:20 2007 +0000 @@ -116,7 +116,7 @@ { purple_debug_error("buddyicon", "Unable to create directory %s: %s\n", - dirname, strerror(errno)); + dirname, g_strerror(errno)); } } @@ -125,7 +125,7 @@ if (!fwrite(purple_imgstore_get_data(img), purple_imgstore_get_size(img), 1, file)) { purple_debug_error("buddyicon", "Error writing %s: %s\n", - path, strerror(errno)); + path, g_strerror(errno)); } else purple_debug_info("buddyicon", "Wrote cache file: %s\n", path); @@ -135,7 +135,7 @@ else { purple_debug_error("buddyicon", "Unable to create file %s: %s\n", - path, strerror(errno)); + path, g_strerror(errno)); g_free(path); return; } @@ -163,7 +163,7 @@ if (g_unlink(path)) { purple_debug_error("buddyicon", "Failed to delete %s: %s\n", - path, strerror(errno)); + path, g_strerror(errno)); } else { @@ -505,37 +505,33 @@ purple_buddy_icon_set_data(icon, icon_data, icon_len, checksum); else if (icon_data && icon_len > 0) { - if (icon_data != NULL && icon_len > 0) - { - PurpleBuddyIcon *icon = purple_buddy_icon_new(account, username, icon_data, icon_len, checksum); + PurpleBuddyIcon *icon = purple_buddy_icon_new(account, username, icon_data, icon_len, checksum); - /* purple_buddy_icon_new() calls - * purple_buddy_icon_set_data(), which calls - * purple_buddy_icon_update(), which has the buddy list - * and conversations take references as appropriate. - * This function doesn't return icon, so we can't - * leave a reference dangling. */ - purple_buddy_icon_unref(icon); - } - else + /* purple_buddy_icon_new() calls + * purple_buddy_icon_set_data(), which calls + * purple_buddy_icon_update(), which has the buddy list + * and conversations take references as appropriate. + * This function doesn't return icon, so we can't + * leave a reference dangling. */ + purple_buddy_icon_unref(icon); + } + else + { + /* If the buddy list or a conversation was holding a + * reference, we'd have found the icon in the cache. + * Since we know we're deleting the icon, we only + * need a subset of purple_buddy_icon_update(). */ + + GSList *buddies = purple_find_buddies(account, username); + while (buddies != NULL) { - /* If the buddy list or a conversation was holding a - * reference, we'd have found the icon in the cache. - * Since we know we're deleting the icon, we only - * need a subset of purple_buddy_icon_update(). */ + PurpleBuddy *buddy = (PurpleBuddy *)buddies->data; - GSList *buddies = purple_find_buddies(account, username); - while (buddies != NULL) - { - PurpleBuddy *buddy = (PurpleBuddy *)buddies->data; + unref_filename(purple_blist_node_get_string((PurpleBlistNode *)buddy, "buddy_icon")); + purple_blist_node_remove_setting((PurpleBlistNode *)buddy, "buddy_icon"); + purple_blist_node_remove_setting((PurpleBlistNode *)buddy, "icon_checksum"); - unref_filename(purple_blist_node_get_string((PurpleBlistNode *)buddy, "buddy_icon")); - purple_blist_node_remove_setting((PurpleBlistNode *)buddy, "buddy_icon"); - purple_blist_node_remove_setting((PurpleBlistNode *)buddy, "icon_checksum"); - - buddies = g_slist_delete_link(buddies, buddies); - } - + buddies = g_slist_delete_link(buddies, buddies); } } } @@ -955,7 +951,7 @@ if (!fwrite(icon_data, icon_len, 1, file)) { purple_debug_error("buddyicon", "Error writing %s: %s\n", - path, strerror(errno)); + path, g_strerror(errno)); } else purple_debug_info("buddyicon", "Wrote migrated cache file: %s\n", path); @@ -965,7 +961,7 @@ else { purple_debug_error("buddyicon", "Unable to create file %s: %s\n", - path, strerror(errno)); + path, g_strerror(errno)); g_free(new_filename); g_free(path); @@ -1060,7 +1056,7 @@ { purple_debug_error("buddyicon", "Unable to create directory %s: %s\n", - dirname, strerror(errno)); + dirname, g_strerror(errno)); } } }
--- a/libpurple/cipher.c Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/cipher.c Sat Nov 10 04:52:20 2007 +0000 @@ -616,7 +616,7 @@ /* * The s-box values are permuted according to the 'primitive function P' */ -static guint32 sbox1[64] = +static const guint32 sbox1[64] = { 0x00808200, 0x00000000, 0x00008000, 0x00808202, 0x00808002, 0x00008202, 0x00000002, 0x00008000, 0x00000200, 0x00808200, 0x00808202, 0x00000200, 0x00800202, 0x00808002, 0x00800000, 0x00000002, @@ -628,7 +628,7 @@ 0x00000202, 0x00800200, 0x00800200, 0x00000000, 0x00008002, 0x00008200, 0x00000000, 0x00808002 }; -static guint32 sbox2[64] = +static const guint32 sbox2[64] = { 0x40084010, 0x40004000, 0x00004000, 0x00084010, 0x00080000, 0x00000010, 0x40080010, 0x40004010, 0x40000010, 0x40084010, 0x40084000, 0x40000000, 0x40004000, 0x00080000, 0x00000010, 0x40080010, @@ -640,7 +640,7 @@ 0x00084000, 0x00000000, 0x40004000, 0x00004010, 0x40000000, 0x40080010, 0x40084010, 0x00084000 }; -static guint32 sbox3[64] = +static const guint32 sbox3[64] = { 0x00000104, 0x04010100, 0x00000000, 0x04010004, 0x04000100, 0x00000000, 0x00010104, 0x04000100, 0x00010004, 0x04000004, 0x04000004, 0x00010000, 0x04010104, 0x00010004, 0x04010000, 0x00000104, @@ -652,7 +652,7 @@ 0x04010000, 0x04000104, 0x00000104, 0x04010000, 0x00010104, 0x00000004, 0x04010004, 0x00010100 }; -static guint32 sbox4[64] = +static const guint32 sbox4[64] = { 0x80401000, 0x80001040, 0x80001040, 0x00000040, 0x00401040, 0x80400040, 0x80400000, 0x80001000, 0x00000000, 0x00401000, 0x00401000, 0x80401040, 0x80000040, 0x00000000, 0x00400040, 0x80400000, @@ -664,7 +664,7 @@ 0x80001000, 0x00001040, 0x00400000, 0x80401000, 0x00000040, 0x00400000, 0x00001000, 0x00401040 }; -static guint32 sbox5[64] = +static const guint32 sbox5[64] = { 0x00000080, 0x01040080, 0x01040000, 0x21000080, 0x00040000, 0x00000080, 0x20000000, 0x01040000, 0x20040080, 0x00040000, 0x01000080, 0x20040080, 0x21000080, 0x21040000, 0x00040080, 0x20000000, @@ -676,7 +676,7 @@ 0x00040080, 0x01000080, 0x20000080, 0x00040000, 0x00000000, 0x20040000, 0x01040080, 0x20000080 }; -static guint32 sbox6[64] = +static const guint32 sbox6[64] = { 0x10000008, 0x10200000, 0x00002000, 0x10202008, 0x10200000, 0x00000008, 0x10202008, 0x00200000, 0x10002000, 0x00202008, 0x00200000, 0x10000008, 0x00200008, 0x10002000, 0x10000000, 0x00002008, @@ -688,7 +688,7 @@ 0x00002000, 0x00200008, 0x10002008, 0x00000000, 0x10202000, 0x10000000, 0x00200008, 0x10002008 }; -static guint32 sbox7[64] = +static const guint32 sbox7[64] = { 0x00100000, 0x02100001, 0x02000401, 0x00000000, 0x00000400, 0x02000401, 0x00100401, 0x02100400, 0x02100401, 0x00100000, 0x00000000, 0x02000001, 0x00000001, 0x02000000, 0x02100001, 0x00000401, @@ -700,7 +700,7 @@ 0x00000000, 0x00100401, 0x02100000, 0x00000400, 0x02000001, 0x02000400, 0x00000400, 0x00100001 }; -static guint32 sbox8[64] = +static const guint32 sbox8[64] = { 0x08000820, 0x00000800, 0x00020000, 0x08020820, 0x08000000, 0x08000820, 0x00000020, 0x08000000, 0x00020020, 0x08020000, 0x08020820, 0x00020800, 0x08020800, 0x00020820, 0x00000800, 0x00000020, @@ -718,7 +718,7 @@ * * These two tables are part of the 'permuted choice 1' function. * * In this implementation several speed improvements are done. * */ -static guint32 leftkey_swap[16] = +static const guint32 leftkey_swap[16] = { 0x00000000, 0x00000001, 0x00000100, 0x00000101, 0x00010000, 0x00010001, 0x00010100, 0x00010101, @@ -726,7 +726,7 @@ 0x01010000, 0x01010001, 0x01010100, 0x01010101 }; -static guint32 rightkey_swap[16] = +static const guint32 rightkey_swap[16] = { 0x00000000, 0x01000000, 0x00010000, 0x01010000, 0x00000100, 0x01000100, 0x00010100, 0x01010100, @@ -742,7 +742,7 @@ * ordering of the subkeys so we can omit the table for decryption * subkey schedule. */ -static guint8 encrypt_rotate_tab[16] = +static const guint8 encrypt_rotate_tab[16] = { 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 };
--- a/libpurple/connection.c Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/connection.c Sat Nov 10 04:52:20 2007 +0000 @@ -432,7 +432,7 @@ { g_return_val_if_fail(gc != NULL, NULL); - return gc->password; + return gc->password ? gc->password : gc->account->password; } const char *
--- a/libpurple/conversation.h Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/conversation.h Sat Nov 10 04:52:20 2007 +0000 @@ -171,9 +171,12 @@ void (*write_im)(PurpleConversation *conv, const char *who, const char *message, PurpleMessageFlags flags, time_t mtime); - /** Write a message to a conversation. This is used rather than - * the chat- or im-specific ops for generic messages, such as system - * messages like "x is now know as y". + /** Write a message to a conversation. This is used rather than the + * chat- or im-specific ops for errors, system messages (such as "x is + * now know as y"), and as the fallback if #write_im and #write_chat + * are not implemented. It should be implemented, or the UI will miss + * conversation error messages and your users will hate you. + * * @see purple_conversation_write() */ void (*write_conv)(PurpleConversation *conv, @@ -1044,7 +1047,7 @@ * * @param chat The chat. * - * @return The list of ignored users. + * @constreturn The list of ignored users. */ GList *purple_conv_chat_get_ignored(const PurpleConvChat *chat);
--- a/libpurple/core.c Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/core.c Sat Nov 10 04:52:20 2007 +0000 @@ -383,7 +383,7 @@ if (g_rename(path, new_name)) { purple_debug_error("core", "Error renaming %s to %s: %s. Please report this at http://developer.pidgin.im\n", - path, new_name, strerror(errno)); + path, new_name, g_strerror(errno)); g_free(new_name); return FALSE; } @@ -396,7 +396,7 @@ if (symlink(new_name, old_name)) { purple_debug_warning("core", "Error symlinking %s to %s: %s. Please report this at http://developer.pidgin.im\n", - old_name, new_name, strerror(errno)); + old_name, new_name, g_strerror(errno)); } g_free(old_name); g_free(new_name); @@ -452,7 +452,7 @@ if (g_mkdir(user_dir, S_IRUSR | S_IWUSR | S_IXUSR) == -1) { purple_debug_error("core", "Error creating directory %s: %s. Please report this at http://developer.pidgin.im\n", - user_dir, strerror(errno)); + user_dir, g_strerror(errno)); g_free(status_file); g_free(old_user_dir); return FALSE; @@ -464,7 +464,7 @@ if (!(fp = g_fopen(status_file, "w"))) { purple_debug_error("core", "Error opening file %s for writing: %s. Please report this at http://developer.pidgin.im\n", - status_file, strerror(errno)); + status_file, g_strerror(errno)); g_free(status_file); g_free(old_user_dir); return FALSE; @@ -522,7 +522,7 @@ { char *name_utf8 = g_filename_to_utf8(name, -1, NULL, NULL, NULL); purple_debug_error("core", "Error reading symlink %s: %s. Please report this at http://developer.pidgin.im\n", - name_utf8, strerror(errno)); + name_utf8, g_strerror(errno)); g_free(name_utf8); g_free(name); g_dir_close(dir); @@ -560,7 +560,7 @@ if (symlink(link, logs_dir)) { purple_debug_error("core", "Error symlinking %s to %s: %s. Please report this at http://developer.pidgin.im\n", - logs_dir, link, strerror(errno)); + logs_dir, link, g_strerror(errno)); g_free(link); g_free(name); g_free(logs_dir); @@ -617,7 +617,7 @@ if (g_mkdir(new_icons_dir, S_IRUSR | S_IWUSR | S_IXUSR) == -1) { purple_debug_error("core", "Error creating directory %s: %s. Please report this at http://developer.pidgin.im\n", - new_icons_dir, strerror(errno)); + new_icons_dir, g_strerror(errno)); g_free(new_icons_dir); g_dir_close(icons_dir); g_free(name); @@ -680,7 +680,7 @@ if (!(fp = g_fopen(name, "rb"))) { purple_debug_error("core", "Error opening file %s for reading: %s. Please report this at http://developer.pidgin.im\n", - name, strerror(errno)); + name, g_strerror(errno)); g_free(name); g_dir_close(dir); g_free(status_file); @@ -692,7 +692,7 @@ if (!(new_file = g_fopen(new_name, "wb"))) { purple_debug_error("core", "Error opening file %s for writing: %s. Please report this at http://developer.pidgin.im\n", - new_name, strerror(errno)); + new_name, g_strerror(errno)); fclose(fp); g_free(new_name); g_free(name); @@ -711,7 +711,7 @@ if (size != sizeof(buf) && !feof(fp)) { purple_debug_error("core", "Error reading %s: %s. Please report this at http://developer.pidgin.im\n", - name, strerror(errno)); + name, g_strerror(errno)); fclose(new_file); fclose(fp); g_free(new_name); @@ -725,7 +725,7 @@ if (!fwrite(buf, size, 1, new_file) && ferror(new_file) != 0) { purple_debug_error("core", "Error writing %s: %s. Please report this at http://developer.pidgin.im\n", - new_name, strerror(errno)); + new_name, g_strerror(errno)); fclose(new_file); fclose(fp); g_free(new_name); @@ -740,12 +740,12 @@ if (fclose(new_file)) { purple_debug_error("core", "Error writing: %s: %s. Please report this at http://developer.pidgin.im\n", - new_name, strerror(errno)); + new_name, g_strerror(errno)); } if (fclose(fp)) { purple_debug_warning("core", "Error closing %s: %s\n", - name, strerror(errno)); + name, g_strerror(errno)); } g_free(new_name); } @@ -759,7 +759,7 @@ if (g_unlink(status_file)) { purple_debug_error("core", "Error unlinking file %s: %s. Please report this at http://developer.pidgin.im\n", - status_file, strerror(errno)); + status_file, g_strerror(errno)); g_free(status_file); return FALSE; }
--- a/libpurple/dbus-analyze-functions.py Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/dbus-analyze-functions.py Sat Nov 10 04:52:20 2007 +0000 @@ -75,7 +75,11 @@ ] pointer = "#pointer#" -myexception = "My Exception" + +class MyException(Exception): + pass + +myexception = MyException() def ctopascal(name): newname = "" @@ -520,7 +524,7 @@ try: self.processfunction(functiontext, paramtexts) - except myexception: + except MyException: sys.stderr.write(myline + "\n") except: sys.stderr.write(myline + "\n")
--- a/libpurple/dbus-server.c Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/dbus-server.c Sat Nov 10 04:52:20 2007 +0000 @@ -674,6 +674,8 @@ int id; gint xint; guint xuint; + gint64 xint64; + guint64 xuint64; gboolean xboolean; gpointer ptr = NULL; gpointer val; @@ -694,6 +696,14 @@ xuint = my_arg(guint); dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT32, &xuint); break; + case PURPLE_TYPE_INT64: + xint64 = my_arg(gint64); + dbus_message_iter_append_basic(iter, DBUS_TYPE_INT64, &xint64); + break; + case PURPLE_TYPE_UINT64: + xuint64 = my_arg(guint64); + dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT64, &xuint64); + break; case PURPLE_TYPE_BOOLEAN: xboolean = my_arg(gboolean); dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &xboolean);
--- a/libpurple/desktopitem.c Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/desktopitem.c Sat Nov 10 04:52:20 2007 +0000 @@ -1155,7 +1155,7 @@ dfile = g_fopen(filename, "r"); if (!dfile) { - printf ("Can't open %s: %s", filename, strerror(errno)); + printf ("Can't open %s: %s", filename, g_strerror(errno)); return NULL; }
--- a/libpurple/dnsquery.c Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/dnsquery.c Sat Nov 10 04:52:20 2007 +0000 @@ -346,7 +346,7 @@ /* Create pipes for communicating with the child process */ if (pipe(child_out) || pipe(child_in)) { purple_debug_error("dns", - "Could not create pipes: %s\n", strerror(errno)); + "Could not create pipes: %s\n", g_strerror(errno)); return NULL; } @@ -374,7 +374,7 @@ if (resolver->dns_pid == -1) { purple_debug_error("dns", "Could not create child process for DNS: %s\n", - strerror(errno)); + g_strerror(errno)); purple_dnsquery_resolver_destroy(resolver); return NULL; } @@ -416,7 +416,7 @@ return FALSE; } else if (pid < 0) { purple_debug_warning("dns", "Wait for DNS child %d failed: %s\n", - resolver->dns_pid, strerror(errno)); + resolver->dns_pid, g_strerror(errno)); purple_dnsquery_resolver_destroy(resolver); return FALSE; } @@ -430,7 +430,7 @@ rc = write(resolver->fd_in, &dns_params, sizeof(dns_params)); if (rc < 0) { purple_debug_error("dns", "Unable to write to DNS child %d: %d\n", - resolver->dns_pid, strerror(errno)); + resolver->dns_pid, g_strerror(errno)); purple_dnsquery_resolver_destroy(resolver); return FALSE; } @@ -571,7 +571,7 @@ purple_dnsquery_resolved(query_data, hosts); } else if (rc == -1) { - g_snprintf(message, sizeof(message), _("Error reading from resolver process:\n%s"), strerror(errno)); + g_snprintf(message, sizeof(message), _("Error reading from resolver process:\n%s"), g_strerror(errno)); purple_dnsquery_failed(query_data, message); } else if (rc == 0) {
--- a/libpurple/example/nullclient.c Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/example/nullclient.c Sat Nov 10 04:52:20 2007 +0000 @@ -269,6 +269,13 @@ PurpleAccount *account; PurpleSavedStatus *status; + /* libpurple's built-in DNS resolution forks processes to perform + * blocking lookups without blocking the main process. It does not + * handle SIGCHLD itself, so if the UI does not you quickly get an army + * of zombie subprocesses marching around. + */ + signal(SIGCHLD, SIG_IGN); + init_libpurple(); printf("libpurple initialized.\n");
--- a/libpurple/ft.c Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/ft.c Sat Nov 10 04:52:20 2007 +0000 @@ -207,15 +207,15 @@ switch(xfer_type) { case PURPLE_XFER_SEND: msg = g_strdup_printf(_("Error reading %s: \n%s.\n"), - utf8, strerror(err)); + utf8, g_strerror(err)); break; case PURPLE_XFER_RECEIVE: msg = g_strdup_printf(_("Error writing %s: \n%s.\n"), - utf8, strerror(err)); + utf8, g_strerror(err)); break; default: msg = g_strdup_printf(_("Error accessing %s: \n%s.\n"), - utf8, strerror(err)); + utf8, g_strerror(err)); break; } g_free(utf8);
--- a/libpurple/log.c Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/log.c Sat Nov 10 04:52:20 2007 +0000 @@ -756,7 +756,7 @@ if (!fwrite(image_data, image_byte_count, 1, image_file)) { purple_debug_error("log", "Error writing %s: %s\n", - path, strerror(errno)); + path, g_strerror(errno)); fclose(image_file); /* Attempt to not leave half-written files around. */ @@ -771,7 +771,7 @@ else { purple_debug_error("log", "Unable to create file %s: %s\n", - path, strerror(errno)); + path, g_strerror(errno)); } } @@ -1108,7 +1108,7 @@ return TRUE; else if (ret == -1) { - purple_debug_error("log", "Failed to delete: %s - %s\n", data->path, strerror(errno)); + purple_debug_error("log", "Failed to delete: %s - %s\n", data->path, g_strerror(errno)); } else { @@ -1143,7 +1143,7 @@ g_free(dirname); return TRUE; } - purple_debug_info("log", "access(%s) failed: %s\n", dirname, strerror(errno)); + purple_debug_info("log", "access(%s) failed: %s\n", dirname, g_strerror(errno)); g_free(dirname); #else /* Unless and until someone writes equivalent win32 code, @@ -1638,7 +1638,7 @@ if (!(index = g_fopen(pathstr, "rb"))) { purple_debug_error("log", "Failed to open index file \"%s\" for reading: %s\n", - pathstr, strerror(errno)); + pathstr, g_strerror(errno)); /* Fall through so that we'll parse the log file. */ } @@ -1675,7 +1675,7 @@ if (!(file = g_fopen(purple_stringref_value(pathref), "rb"))) { purple_debug_error("log", "Failed to open log file \"%s\" for reading: %s\n", - purple_stringref_value(pathref), strerror(errno)); + purple_stringref_value(pathref), g_strerror(errno)); purple_stringref_unref(pathref); g_free(pathstr); return NULL; @@ -1684,7 +1684,7 @@ index_tmp = g_strdup_printf("%s.XXXXXX", pathstr); if ((index_fd = g_mkstemp(index_tmp)) == -1) { purple_debug_error("log", "Failed to open index temp file: %s\n", - strerror(errno)); + g_strerror(errno)); g_free(pathstr); g_free(index_tmp); index = NULL; @@ -1692,7 +1692,7 @@ if ((index = fdopen(index_fd, "wb")) == NULL) { purple_debug_error("log", "Failed to fdopen() index temp file: %s\n", - strerror(errno)); + g_strerror(errno)); close(index_fd); if (index_tmp != NULL) { @@ -1828,7 +1828,7 @@ if (g_rename(index_tmp, pathstr)) { purple_debug_warning("log", "Failed to rename index temp file \"%s\" to \"%s\": %s\n", - index_tmp, pathstr, strerror(errno)); + index_tmp, pathstr, g_strerror(errno)); g_unlink(index_tmp); g_free(index_tmp); }
--- a/libpurple/nat-pmp.c Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/nat-pmp.c Sat Nov 10 04:52:20 2007 +0000 @@ -312,7 +312,7 @@ if (sendto(sendfd, &req, sizeof(req), 0, (struct sockaddr *)(gateway), sizeof(struct sockaddr)) < 0) { - purple_debug_info("nat-pmp", "There was an error sending the NAT-PMP public IP request! (%s)\n", strerror(errno)); + purple_debug_info("nat-pmp", "There was an error sending the NAT-PMP public IP request! (%s)\n", g_strerror(errno)); g_free(gateway); pmp_info.status = PURPLE_PMP_STATUS_UNABLE_TO_DISCOVER; return NULL; @@ -320,7 +320,7 @@ if (setsockopt(sendfd, SOL_SOCKET, SO_RCVTIMEO, &req_timeout, sizeof(req_timeout)) < 0) { - purple_debug_info("nat-pmp", "There was an error setting the socket's options! (%s)\n", strerror(errno)); + purple_debug_info("nat-pmp", "There was an error setting the socket's options! (%s)\n", g_strerror(errno)); g_free(gateway); pmp_info.status = PURPLE_PMP_STATUS_UNABLE_TO_DISCOVER; return NULL; @@ -332,7 +332,7 @@ { if (errno != EAGAIN) { - purple_debug_info("nat-pmp", "There was an error receiving the response from the NAT-PMP device! (%s)\n", strerror(errno)); + purple_debug_info("nat-pmp", "There was an error receiving the response from the NAT-PMP device! (%s)\n", g_strerror(errno)); g_free(gateway); pmp_info.status = PURPLE_PMP_STATUS_UNABLE_TO_DISCOVER; return NULL; @@ -432,13 +432,13 @@ /* TODO: Non-blocking! */ success = (sendto(sendfd, &req, sizeof(req), 0, (struct sockaddr *)(gateway), sizeof(struct sockaddr)) >= 0); if (!success) - purple_debug_info("nat-pmp", "There was an error sending the NAT-PMP mapping request! (%s)\n", strerror(errno)); + purple_debug_info("nat-pmp", "There was an error sending the NAT-PMP mapping request! (%s)\n", g_strerror(errno)); if (success) { success = (setsockopt(sendfd, SOL_SOCKET, SO_RCVTIMEO, &req_timeout, sizeof(req_timeout)) >= 0); if (!success) - purple_debug_info("nat-pmp", "There was an error setting the socket's options! (%s)\n", strerror(errno)); + purple_debug_info("nat-pmp", "There was an error setting the socket's options! (%s)\n", g_strerror(errno)); } if (success) @@ -448,7 +448,7 @@ success = ((recvfrom(sendfd, resp, sizeof(PurplePmpMapResponse), 0, NULL, NULL) >= 0) || (errno == EAGAIN)); if (!success) - purple_debug_info("nat-pmp", "There was an error receiving the response from the NAT-PMP device! (%s)\n", strerror(errno)); + purple_debug_info("nat-pmp", "There was an error receiving the response from the NAT-PMP device! (%s)\n", g_strerror(errno)); } if (success)
--- a/libpurple/network.c Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/network.c Sat Nov 10 04:52:20 2007 +0000 @@ -263,6 +263,7 @@ purple_network_do_listen(unsigned short port, int socket_type, PurpleNetworkListenCallback cb, gpointer cb_data) { int listenfd = -1; + int flags; const int on = 1; PurpleNetworkListenData *listen_data; unsigned short actual_port; @@ -284,7 +285,7 @@ #ifndef _WIN32 purple_debug_warning("network", "getaddrinfo: %s\n", gai_strerror(errnum)); if (errnum == EAI_SYSTEM) - purple_debug_warning("network", "getaddrinfo: system error: %s\n", strerror(errno)); + purple_debug_warning("network", "getaddrinfo: system error: %s\n", g_strerror(errno)); #else purple_debug_warning("network", "getaddrinfo: Error Code = %d\n", errnum); #endif @@ -301,7 +302,7 @@ if (listenfd < 0) continue; if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) != 0) - purple_debug_warning("network", "setsockopt: %s\n", strerror(errno)); + purple_debug_warning("network", "setsockopt: %s\n", g_strerror(errno)); if (bind(listenfd, next->ai_addr, next->ai_addrlen) == 0) break; /* success */ /* XXX - It is unclear to me (datallah) whether we need to be @@ -317,30 +318,31 @@ struct sockaddr_in sockin; if ((listenfd = socket(AF_INET, socket_type, 0)) < 0) { - purple_debug_warning("network", "socket: %s\n", strerror(errno)); + purple_debug_warning("network", "socket: %s\n", g_strerror(errno)); return NULL; } if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) != 0) - purple_debug_warning("network", "setsockopt: %s\n", strerror(errno)); + purple_debug_warning("network", "setsockopt: %s\n", g_strerror(errno)); memset(&sockin, 0, sizeof(struct sockaddr_in)); sockin.sin_family = PF_INET; sockin.sin_port = htons(port); if (bind(listenfd, (struct sockaddr *)&sockin, sizeof(struct sockaddr_in)) != 0) { - purple_debug_warning("network", "bind: %s\n", strerror(errno)); + purple_debug_warning("network", "bind: %s\n", g_strerror(errno)); close(listenfd); return NULL; } #endif if (socket_type == SOCK_STREAM && listen(listenfd, 4) != 0) { - purple_debug_warning("network", "listen: %s\n", strerror(errno)); + purple_debug_warning("network", "listen: %s\n", g_strerror(errno)); close(listenfd); return NULL; } - fcntl(listenfd, F_SETFL, O_NONBLOCK); + flags = fcntl(listenfd, F_GETFL); + fcntl(listenfd, F_SETFL, flags | O_NONBLOCK); actual_port = purple_network_get_port_from_fd(listenfd); @@ -424,7 +426,7 @@ len = sizeof(addr); if (getsockname(fd, (struct sockaddr *) &addr, &len) == -1) { - purple_debug_warning("network", "getsockname: %s\n", strerror(errno)); + purple_debug_warning("network", "getsockname: %s\n", g_strerror(errno)); return 0; }
--- a/libpurple/notify.c Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/notify.c Sat Nov 10 04:52:20 2007 +0000 @@ -688,8 +688,11 @@ void purple_notify_user_info_remove_last_item(PurpleNotifyUserInfo *user_info) { - user_info->user_info_entries = g_list_remove(user_info->user_info_entries, - g_list_last(user_info->user_info_entries)->data); + GList *last = g_list_last(user_info->user_info_entries); + if (last) { + purple_notify_user_info_entry_destroy(last->data); + user_info->user_info_entries = g_list_delete_link(user_info->user_info_entries, last); + } } void *
--- a/libpurple/notify.h Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/notify.h Sat Nov 10 04:52:20 2007 +0000 @@ -546,7 +546,7 @@ void purple_notify_user_info_prepend_pair(PurpleNotifyUserInfo *user_info, const char *label, const char *value); /** - * Remove a PurpleNotifyUserInfoEntry from a PurpleNotifyUserInfo object + * Remove a PurpleNotifyUserInfoEntry from a PurpleNotifyUserInfo object without freeing the entry. * * @param user_info The PurpleNotifyUserInfo * @param user_info_entry The PurpleNotifyUserInfoEntry
--- a/libpurple/plugin.h Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/plugin.h Sat Nov 10 04:52:20 2007 +0000 @@ -637,7 +637,7 @@ /** * Returns a list of all loaded plugins. * - * @return A list of all loaded plugins. + * @constreturn A list of all loaded plugins. */ GList *purple_plugins_get_loaded(void); @@ -647,14 +647,14 @@ * to the PURPLE_INIT_PLUGIN() macro, or if it was compiled * against an incompatable API version. * - * @return A list of all protocol plugins. + * @constreturn A list of all protocol plugins. */ GList *purple_plugins_get_protocols(void); /** * Returns a list of all plugins, whether loaded or not. * - * @return A list of all plugins. + * @constreturn A list of all plugins. */ GList *purple_plugins_get_all(void);
--- a/libpurple/pluginpref.h Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/pluginpref.h Sat Nov 10 04:52:20 2007 +0000 @@ -85,7 +85,7 @@ * Get the plugin preferences from a plugin preference frame * * @param frame The plugin frame to get the plugin preferences from - * @return a GList of plugin preferences + * @constreturn a GList of plugin preferences */ GList *purple_plugin_pref_frame_get_prefs(PurplePluginPrefFrame *frame); @@ -207,7 +207,7 @@ * Get the choices for a choices plugin pref * * @param pref The plugin pref - * @return GList of the choices + * @constreturn GList of the choices */ GList *purple_plugin_pref_get_choices(PurplePluginPref *pref);
--- a/libpurple/plugins/autoaccept.c Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/plugins/autoaccept.c Sat Nov 10 04:52:20 2007 +0000 @@ -252,7 +252,7 @@ PLUGIN_ID, /* plugin id */ PLUGIN_NAME, /* name */ - VERSION, /* version */ + DISPLAY_VERSION, /* version */ PLUGIN_SUMMARY, /* summary */ PLUGIN_DESCRIPTION, /* description */ PLUGIN_AUTHOR, /* author */
--- a/libpurple/plugins/buddynote.c Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/plugins/buddynote.c Sat Nov 10 04:52:20 2007 +0000 @@ -88,7 +88,7 @@ PURPLE_PRIORITY_DEFAULT, /**< priority */ "core-plugin_pack-buddynote", /**< id */ N_("Buddy Notes"), /**< name */ - VERSION, /**< version */ + DISPLAY_VERSION, /**< version */ N_("Store notes on particular buddies."), /**< summary */ N_("Adds the option to store notes for buddies " "on your buddy list."), /**< description */
--- a/libpurple/plugins/ciphertest.c Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/plugins/ciphertest.c Sat Nov 10 04:52:20 2007 +0000 @@ -262,7 +262,7 @@ "core-cipher-test", /**< id */ N_("Cipher Test"), /**< name */ - VERSION, /**< version */ + DISPLAY_VERSION, /**< version */ /** summary */ N_("Tests the ciphers that ship with libpurple."), /** description */
--- a/libpurple/plugins/dbus-example.c Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/plugins/dbus-example.c Sat Nov 10 04:52:20 2007 +0000 @@ -153,7 +153,7 @@ "dbus-example", /**< id */ N_("DBus Example"), /**< name */ - VERSION, /**< version */ + DISPLAY_VERSION, /**< version */ /** summary */ N_("DBus Plugin Example"), /** description */
--- a/libpurple/plugins/debug_example.c Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/plugins/debug_example.c Sat Nov 10 04:52:20 2007 +0000 @@ -109,7 +109,7 @@ PLUGIN_ID, /* id */ "Debug API Example", /* name */ - VERSION, /* version */ + DISPLAY_VERSION, /* version */ "Debug API Example", /* summary */ "Debug API Example", /* description */ PLUGIN_AUTHOR, /* author */
--- a/libpurple/plugins/filectl.c Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/plugins/filectl.c Sat Nov 10 04:52:20 2007 +0000 @@ -246,7 +246,7 @@ FILECTL_PLUGIN_ID, /**< id */ N_("File Control"), /**< name */ - VERSION, /**< version */ + DISPLAY_VERSION, /**< version */ /** summary */ N_("Allows control by entering commands in a file."), /** description */
--- a/libpurple/plugins/helloworld.c Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/plugins/helloworld.c Sat Nov 10 04:52:20 2007 +0000 @@ -114,8 +114,8 @@ "core-hello_world", "Hello World!", - VERSION, /* This constant is defined in version.h, but you shouldn't use it for - your own plugins. We use it here because it's our plugin. */ + DISPLAY_VERSION, /* This constant is defined in config.h, but you shouldn't use it for + your own plugins. We use it here because it's our plugin. And we're lazy. */ "Hello World Plugin", "Hello World Plugin",
--- a/libpurple/plugins/idle.c Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/plugins/idle.c Sat Nov 10 04:52:20 2007 +0000 @@ -316,7 +316,7 @@ /* This is a cultural reference. Dy'er Mak'er is a song by Led Zeppelin. If that doesn't translate well into your language, drop the 's before translating. */ N_("I'dle Mak'er"), - VERSION, + DISPLAY_VERSION, N_("Allows you to hand-configure how long you've been idle"), N_("Allows you to hand-configure how long you've been idle"), "Eric Warmenhoven <eric@warmenhoven.org>",
--- a/libpurple/plugins/ipc-test-client.c Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/plugins/ipc-test-client.c Sat Nov 10 04:52:20 2007 +0000 @@ -85,7 +85,7 @@ IPC_TEST_CLIENT_PLUGIN_ID, /**< id */ N_("IPC Test Client"), /**< name */ - VERSION, /**< version */ + DISPLAY_VERSION, /**< version */ /** summary */ N_("Test plugin IPC support, as a client."), /** description */
--- a/libpurple/plugins/ipc-test-server.c Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/plugins/ipc-test-server.c Sat Nov 10 04:52:20 2007 +0000 @@ -72,7 +72,7 @@ IPC_TEST_SERVER_PLUGIN_ID, /**< id */ N_("IPC Test Server"), /**< name */ - VERSION, /**< version */ + DISPLAY_VERSION, /**< version */ /** summary */ N_("Test plugin IPC support, as a server."), /** description */
--- a/libpurple/plugins/joinpart.c Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/plugins/joinpart.c Sat Nov 10 04:52:20 2007 +0000 @@ -268,7 +268,7 @@ JOINPART_PLUGIN_ID, /**< id */ N_("Join/Part Hiding"), /**< name */ - VERSION, /**< version */ + DISPLAY_VERSION, /**< version */ /** summary */ N_("Hides extraneous join/part messages."), /** description */
--- a/libpurple/plugins/log_reader.c Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/plugins/log_reader.c Sat Nov 10 04:52:20 2007 +0000 @@ -2423,14 +2423,16 @@ static void init_plugin(PurplePlugin *plugin) { + +} + +static void log_reader_init_prefs() { char *path; #ifdef _WIN32 char *folder; gboolean found = FALSE; #endif - g_return_if_fail(plugin != NULL); - purple_prefs_add_none("/plugins/core/log_reader"); @@ -2671,12 +2673,16 @@ /* Calculate default aMSN log directory. */ #ifdef _WIN32 + path = NULL; folder = wpurple_get_special_folder(CSIDL_PROFILE); /* Silly aMSN, not using CSIDL_APPDATA */ - path = g_build_filename(folder, "amsn", NULL); + if (folder) { + path = g_build_filename(folder, "amsn", NULL); + g_free(folder); + } #else path = g_build_filename(purple_home_dir(), ".amsn", NULL); #endif - purple_prefs_add_string("/plugins/core/log_reader/amsn/log_directory", path); + purple_prefs_add_string("/plugins/core/log_reader/amsn/log_directory", path ? path : ""); g_free(path); } @@ -2685,6 +2691,8 @@ { g_return_val_if_fail(plugin != NULL, FALSE); + log_reader_init_prefs(); + /* The names of IM clients are marked for translation at the request of translators who wanted to transliterate them. Many translators choose to leave them alone. Choose what's best for your language. */ @@ -2880,7 +2888,7 @@ PURPLE_PRIORITY_DEFAULT, /**< priority */ "core-log_reader", /**< id */ N_("Log Reader"), /**< name */ - VERSION, /**< version */ + DISPLAY_VERSION, /**< version */ /** summary */ N_("Includes other IM clients' logs in the "
--- a/libpurple/plugins/mono/loader/mono.c Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/plugins/mono/loader/mono.c Sat Nov 10 04:52:20 2007 +0000 @@ -215,7 +215,7 @@ PURPLE_PRIORITY_DEFAULT, MONO_PLUGIN_ID, N_("Mono Plugin Loader"), - VERSION, + DISPLAY_VERSION, N_("Loads .NET plugins with Mono."), N_("Loads .NET plugins with Mono."), "Eoin Coffey <ecoffey@simla.colostate.edu>",
--- a/libpurple/plugins/newline.c Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/plugins/newline.c Sat Nov 10 04:52:20 2007 +0000 @@ -66,7 +66,7 @@ "core-plugin_pack-newline", /**< id */ N_("New Line"), /**< name */ - VERSION, /**< version */ + DISPLAY_VERSION, /**< version */ N_("Prepends a newline to displayed message."), /**< summary */ N_("Prepends a newline to messages so that the " "rest of the message appears below the "
--- a/libpurple/plugins/notify_example.c Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/plugins/notify_example.c Sat Nov 10 04:52:20 2007 +0000 @@ -135,7 +135,7 @@ PLUGIN_ID, /* id */ "Notify API Example", /* name */ - VERSION, /* version */ + DISPLAY_VERSION, /* version */ "Notify API Example", /* summary */ "Notify API Example", /* description */ PLUGIN_AUTHOR, /* author */
--- a/libpurple/plugins/offlinemsg.c Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/plugins/offlinemsg.c Sat Nov 10 04:52:20 2007 +0000 @@ -225,7 +225,7 @@ PLUGIN_ID, /* plugin id */ PLUGIN_NAME, /* name */ - VERSION, /* version */ + DISPLAY_VERSION, /* version */ PLUGIN_SUMMARY, /* summary */ PLUGIN_DESCRIPTION, /* description */ PLUGIN_AUTHOR, /* author */
--- a/libpurple/plugins/perl/perl.c Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/plugins/perl/perl.c Sat Nov 10 04:52:20 2007 +0000 @@ -599,7 +599,7 @@ PERL_PLUGIN_ID, /**< id */ N_("Perl Plugin Loader"), /**< name */ - VERSION, /**< version */ + DISPLAY_VERSION, /**< version */ N_("Provides support for loading perl plugins."), /**< summary */ N_("Provides support for loading perl plugins."), /**< description */ "Christian Hammond <chipx86@gnupdate.org>", /**< author */
--- a/libpurple/plugins/pluginpref_example.c Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/plugins/pluginpref_example.c Sat Nov 10 04:52:20 2007 +0000 @@ -131,7 +131,7 @@ "core-pluginpref_example", /**< id */ "Pluginpref Example", /**< name */ - VERSION, /**< version */ + DISPLAY_VERSION, /**< version */ /** summary */ "An example of how to use pluginprefs", /** description */
--- a/libpurple/plugins/psychic.c Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/plugins/psychic.c Sat Nov 10 04:52:20 2007 +0000 @@ -147,7 +147,7 @@ PLUGIN_ID, /**< id */ PLUGIN_NAME, /**< name */ - VERSION, /**< version */ + DISPLAY_VERSION, /**< version */ PLUGIN_SUMMARY, /**< summary */ PLUGIN_DESC, /**< description */ PLUGIN_AUTHOR, /**< author */
--- a/libpurple/plugins/signals-test.c Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/plugins/signals-test.c Sat Nov 10 04:52:20 2007 +0000 @@ -737,7 +737,7 @@ SIGNAL_TEST_PLUGIN_ID, /**< id */ N_("Signals Test"), /**< name */ - VERSION, /**< version */ + DISPLAY_VERSION, /**< version */ /** summary */ N_("Test to see that all signals are working properly."), /** description */
--- a/libpurple/plugins/simple.c Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/plugins/simple.c Sat Nov 10 04:52:20 2007 +0000 @@ -35,7 +35,7 @@ SIMPLE_PLUGIN_ID, /**< id */ N_("Simple Plugin"), /**< name */ - VERSION, /**< version */ + DISPLAY_VERSION, /**< version */ /** summary */ N_("Tests to see that most things are working."), /** description */
--- a/libpurple/plugins/ssl/ssl-gnutls.c Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/plugins/ssl/ssl-gnutls.c Sat Nov 10 04:52:20 2007 +0000 @@ -993,7 +993,7 @@ SSL_GNUTLS_PLUGIN_ID, /**< id */ N_("GNUTLS"), /**< name */ - VERSION, /**< version */ + DISPLAY_VERSION, /**< version */ /** summary */ N_("Provides SSL support through GNUTLS."), /** description */
--- a/libpurple/plugins/ssl/ssl-nss.c Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/plugins/ssl/ssl-nss.c Sat Nov 10 04:52:20 2007 +0000 @@ -814,7 +814,7 @@ SSL_NSS_PLUGIN_ID, /**< id */ N_("NSS"), /**< name */ - VERSION, /**< version */ + DISPLAY_VERSION, /**< version */ /** summary */ N_("Provides SSL support through Mozilla NSS."), /** description */
--- a/libpurple/plugins/ssl/ssl.c Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/plugins/ssl/ssl.c Sat Nov 10 04:52:20 2007 +0000 @@ -92,7 +92,7 @@ SSL_PLUGIN_ID, /**< id */ N_("SSL"), /**< name */ - VERSION, /**< version */ + DISPLAY_VERSION, /**< version */ /** summary */ N_("Provides a wrapper around SSL support libraries."), /** description */
--- a/libpurple/plugins/statenotify.c Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/plugins/statenotify.c Sat Nov 10 04:52:20 2007 +0000 @@ -146,7 +146,7 @@ STATENOTIFY_PLUGIN_ID, /**< id */ N_("Buddy State Notification"), /**< name */ - VERSION, /**< version */ + DISPLAY_VERSION, /**< version */ /** summary */ N_("Notifies in a conversation window when a buddy goes or returns from " "away or idle."),
--- a/libpurple/plugins/tcl/tcl.c Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/plugins/tcl/tcl.c Sat Nov 10 04:52:20 2007 +0000 @@ -198,7 +198,7 @@ } if (ferror(fp)) { - purple_debug(PURPLE_DEBUG_ERROR, "tcl", "error reading %s (%s)\n", plugin->path, strerror(errno)); + purple_debug(PURPLE_DEBUG_ERROR, "tcl", "error reading %s (%s)\n", plugin->path, g_strerror(errno)); g_free(buf); fclose(fp); return FALSE; @@ -421,7 +421,7 @@ PURPLE_PRIORITY_DEFAULT, "core-tcl", N_("Tcl Plugin Loader"), - VERSION, + DISPLAY_VERSION, N_("Provides support for loading Tcl plugins"), N_("Provides support for loading Tcl plugins"), "Ethan Blanton <eblanton@cs.purdue.edu>",
--- a/libpurple/pounce.h Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/pounce.h Sat Nov 10 04:52:20 2007 +0000 @@ -339,7 +339,7 @@ /** * Returns a list of all registered buddy pounces. * - * @return The list of buddy pounces. + * @constreturn The list of buddy pounces. */ GList *purple_pounces_get_all(void);
--- a/libpurple/prefs.c Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/prefs.c Sat Nov 10 04:52:20 2007 +0000 @@ -297,6 +297,7 @@ g_filename_from_utf8(pref_value, -1, NULL, NULL, NULL)); } } + g_string_free(pref_name_full, TRUE); } else { char *decoded; @@ -382,13 +383,20 @@ purple_debug_info("prefs", "Reading %s\n", filename); if(!g_file_get_contents(filename, &contents, &length, &error)) { -#ifndef _WIN32 +#ifdef _WIN32 + gchar *common_appdata = wpurple_get_special_folder(CSIDL_COMMON_APPDATA); +#endif g_free(filename); g_error_free(error); error = NULL; +#ifdef _WIN32 + filename = g_build_filename(common_appdata ? common_appdata : "", "purple", "prefs.xml", NULL); + g_free(common_appdata); +#else filename = g_build_filename(SYSCONFDIR, "purple", "prefs.xml", NULL); +#endif purple_debug_info("prefs", "Reading %s\n", filename); @@ -401,15 +409,6 @@ return FALSE; } -#else /* _WIN32 */ - purple_debug_error("prefs", "Error reading prefs: %s\n", - error->message); - g_error_free(error); - g_free(filename); - prefs_loaded = TRUE; - - return FALSE; -#endif /* _WIN32 */ } context = g_markup_parse_context_new(&prefs_parser, 0, NULL, NULL);
--- a/libpurple/prefs.h Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/prefs.h Sat Nov 10 04:52:20 2007 +0000 @@ -45,9 +45,20 @@ } PurplePrefType; /** - * Pref change callback type + * The type of callbacks for preference changes. + * + * @param name the name of the preference which has changed. + * @param type the type of the preferenced named @a name + * @param val the new value of the preferencs; should be cast to the correct + * type. For instance, to recover the value of a #PURPLE_PREF_INT + * preference, use <tt>GPOINTER_TO_INT(val)</tt>. Alternatively, + * just call purple_prefs_get_int(), purple_prefs_get_string_list() + * etc. + * @param data Arbitrary data specified when the callback was connected with + * purple_prefs_connect_callback(). + * + * @see purple_prefs_connect_callback() */ - typedef void (*PurplePrefCallback) (const char *name, PurplePrefType type, gconstpointer val, gpointer data); @@ -115,6 +126,9 @@ * * @param name The name of the pref * @param value The initial value to set + * @note This function takes a copy of the strings in the value list. The list + * itself and original copies of the strings are up to the caller to + * free. */ void purple_prefs_add_string_list(const char *name, GList *value); @@ -131,6 +145,9 @@ * * @param name The name of the pref * @param value The initial value to set + * @note This function takes a copy of the strings in the value list. The list + * itself and original copies of the strings are up to the caller to + * free. */ void purple_prefs_add_path_list(const char *name, GList *value);
--- a/libpurple/protocols/bonjour/Makefile.mingw Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/protocols/bonjour/Makefile.mingw Sat Nov 10 04:52:20 2007 +0000 @@ -29,14 +29,13 @@ -I$(GTK_TOP)/include \ -I$(GTK_TOP)/include/glib-2.0 \ -I$(GTK_TOP)/lib/glib-2.0/include \ - -I$(BONJOUR_TOP)/include \ + -I$(BONJOUR_TOP)/Include \ -I$(LIBXML2_TOP)/include \ -I$(PURPLE_TOP) \ -I$(PURPLE_TOP)/win32 \ -I$(PIDGIN_TREE_TOP) LIB_PATHS += -L$(GTK_TOP)/lib \ - -L$(BONJOUR_TOP)/lib/win32 \ -L$(LIBXML2_TOP)/lib \ -L$(PURPLE_TOP) @@ -66,6 +65,7 @@ ifeq ($(LINK_DNS_SD_DIRECTLY), 1) CFLAGS += -DLINK_DNS_SD_DIRECTLY + LIB_PATHS += -L$(BONJOUR_TOP)/lib/win32 -L$(BONJOUR_TOP)/lib LIBS += -ldnssd endif
--- a/libpurple/protocols/bonjour/bonjour.c Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/protocols/bonjour/bonjour.c Sat Nov 10 04:52:20 2007 +0000 @@ -476,7 +476,7 @@ "prpl-bonjour", /**< id */ "Bonjour", /**< name */ - VERSION, /**< version */ + DISPLAY_VERSION, /**< version */ /** summary */ N_("Bonjour Protocol Plugin"), /** description */ @@ -648,7 +648,7 @@ /* TODO: Avoid 'localhost,' if possible */ if (gethostname(hostname, 255) != 0) { purple_debug_warning("bonjour", "Error when getting host name: %s. Using \"localhost.\"\n", - strerror(errno)); + g_strerror(errno)); strcpy(hostname, "localhost"); } default_hostname = g_strdup(hostname);
--- a/libpurple/protocols/bonjour/jabber.c Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/protocols/bonjour/jabber.c Sat Nov 10 04:52:20 2007 +0000 @@ -244,7 +244,7 @@ return; else if (ret <= 0) { PurpleConversation *conv; - const char *error = strerror(errno); + const char *error = g_strerror(errno); purple_debug_error("bonjour", "Error sending message to buddy %s error: %s\n", purple_buddy_get_name(pb), error ? error : "(null)"); @@ -287,7 +287,7 @@ ret = 0; else if (ret <= 0) { PurpleConversation *conv; - const char *error = strerror(errno); + const char *error = g_strerror(errno); purple_debug_error("bonjour", "Error sending message to buddy %s error: %s\n", purple_buddy_get_name(pb), error ? error : "(null)"); @@ -337,7 +337,7 @@ if (errno != EAGAIN) { BonjourBuddy *bb = pb->proto_data; - purple_debug_warning("bonjour", "receive error: %s\n", strerror(errno)); + purple_debug_warning("bonjour", "receive error: %s\n", g_strerror(errno)); bonjour_jabber_close_conversation(bb->conversation); bb->conversation = NULL; @@ -367,7 +367,6 @@ void bonjour_jabber_stream_ended(PurpleBuddy *pb) { BonjourBuddy *bb = pb->proto_data; - PurpleConversation *conv; purple_debug_info("bonjour", "Recieved conversation close notification from %s.\n", pb->name); @@ -375,12 +374,15 @@ /* Inform the user that the conversation has been closed */ if (bb->conversation != NULL) { +#if 0 + PurpleConversation *conv; conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, pb->name, pb->account); if (conv != NULL) { char *tmp = g_strdup_printf(_("%s has closed the conversation."), pb->name); purple_conversation_write(conv, NULL, tmp, PURPLE_MESSAGE_SYSTEM, time(NULL)); g_free(tmp); } +#endif /* Close the socket, clear the watcher and free memory */ bonjour_jabber_close_conversation(bb->conversation); bb->conversation = NULL; @@ -425,7 +427,7 @@ if (ret == -1 && errno == EAGAIN) return; else if (ret <= 0) { - const char *err = strerror(errno); + const char *err = g_strerror(errno); PurpleConversation *conv; purple_debug_error("bonjour", "Error starting stream with buddy %s at %s:%d error: %s\n", @@ -480,7 +482,7 @@ if (ret == -1 && errno == EAGAIN) ret = 0; else if (ret <= 0) { - const char *err = strerror(errno); + const char *err = g_strerror(errno); purple_debug_error("bonjour", "Error starting stream with buddy %s at %s:%d error: %s\n", purple_buddy_get_name(pb), bb->ip ? bb->ip : "(null)", bb->port_p2pj, err ? err : "(null)"); @@ -521,6 +523,7 @@ struct sockaddr_in their_addr; /* connector's address information */ socklen_t sin_size = sizeof(struct sockaddr); int client_socket; + int flags; BonjourBuddy *bb; char *address_text = NULL; PurpleBuddyList *bl = purple_get_blist(); @@ -533,7 +536,8 @@ if ((client_socket = accept(server_socket, (struct sockaddr *)&their_addr, &sin_size)) == -1) return; - fcntl(client_socket, F_SETFL, O_NONBLOCK); + flags = fcntl(client_socket, F_GETFL); + fcntl(client_socket, F_SETFL, flags | O_NONBLOCK); /* Look for the buddy that has opened the conversation and fill information */ address_text = inet_ntoa(their_addr.sin_addr); @@ -579,7 +583,7 @@ /* Open a listening socket for incoming conversations */ if ((data->socket = socket(PF_INET, SOCK_STREAM, 0)) < 0) { - purple_debug_error("bonjour", "Cannot open socket: %s\n", strerror(errno)); + purple_debug_error("bonjour", "Cannot open socket: %s\n", g_strerror(errno)); purple_connection_error(data->account->gc, _("Cannot open socket")); return -1; } @@ -587,7 +591,7 @@ /* Make the socket reusable */ if (setsockopt(data->socket, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) != 0) { - purple_debug_error("bonjour", "Error setting socket options: %s\n", strerror(errno)); + purple_debug_error("bonjour", "Error setting socket options: %s\n", g_strerror(errno)); purple_connection_error(data->account->gc, _("Error setting socket options")); return -1; } @@ -611,7 +615,7 @@ /* On no! We tried 10 ports and could not bind to ANY of them */ if (!bind_successful) { - purple_debug_error("bonjour", "Cannot bind socket: %s\n", strerror(errno)); + purple_debug_error("bonjour", "Cannot bind socket: %s\n", g_strerror(errno)); purple_connection_error(data->account->gc, _("Could not bind socket to port")); return -1; } @@ -619,7 +623,7 @@ /* Attempt to listen on the bound socket */ if (listen(data->socket, 10) != 0) { - purple_debug_error("bonjour", "Cannot listen on socket: %s\n", strerror(errno)); + purple_debug_error("bonjour", "Cannot listen on socket: %s\n", g_strerror(errno)); purple_connection_error(data->account->gc, _("Could not listen on socket")); return -1; } @@ -666,7 +670,7 @@ } if (!bonjour_jabber_stream_init(pb, source)) { - const char *err = strerror(errno); + const char *err = g_strerror(errno); PurpleConversation *conv; purple_debug_error("bonjour", "Error starting stream with buddy %s at %s:%d error: %s\n",
--- a/libpurple/protocols/bonjour/mdns_win32.c Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/protocols/bonjour/mdns_win32.c Sat Nov 10 04:52:20 2007 +0000 @@ -147,10 +147,13 @@ } /* free the hosts list*/ - g_slist_free(hosts); + while (hosts != NULL) { + hosts = g_slist_remove(hosts, hosts->data); + g_free(hosts->data); + hosts = g_slist_remove(hosts, hosts->data); + } /* free the remaining args memory */ - purple_dnsquery_destroy(args->query); g_free(args->full_service_name); g_free(args); }
--- a/libpurple/protocols/gg/gg-utils.c Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/protocols/gg/gg-utils.c Sat Nov 10 04:52:20 2007 +0000 @@ -112,5 +112,36 @@ } /* }}} */ +void ggp_status_fake_to_self(PurpleAccount *account) +{ + PurplePresence *presence; + PurpleStatus *status; + const char *status_id; + const char *msg; + + if (! purple_find_buddy(account, purple_account_get_username(account))) + return; + + presence = purple_account_get_presence(account); + status = purple_presence_get_active_status(presence); + msg = purple_status_get_attr_string(status, "message"); + if (msg && !*msg) + msg = NULL; + + status_id = purple_status_get_id(status); + if (strcmp(status_id, "invisible") == 0) { + status_id = "offline"; + } + + if (msg) { + if (strlen(msg) > GG_STATUS_DESCR_MAXSIZE) { + msg = purple_markup_slice(msg, 0, GG_STATUS_DESCR_MAXSIZE); + } + } + purple_prpl_got_user_status(account, purple_account_get_username(account), + status_id, + msg ? "message" : NULL, msg, NULL); +} + /* vim: set ts=8 sts=0 sw=8 noet: */
--- a/libpurple/protocols/gg/gg-utils.h Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/protocols/gg/gg-utils.h Sat Nov 10 04:52:20 2007 +0000 @@ -92,6 +92,15 @@ char * ggp_buddy_get_name(PurpleConnection *gc, const uin_t uin); +/** + * Manages the display of account's status in the buddylist. + * + * @param account Current account. + */ +void +ggp_status_fake_to_self(PurpleAccount *account); + + #endif /* _PURPLE_GG_UTILS_H */ /* vim: set ts=8 sts=0 sw=8 noet: */
--- a/libpurple/protocols/gg/gg.c Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/protocols/gg/gg.c Sat Nov 10 04:52:20 2007 +0000 @@ -828,6 +828,7 @@ { GGPInfo *info = gc->proto_data; PurpleRequestField *field; + /* TODO: sel may be null. */ GList *sel; field = purple_request_fields_get_field(fields, "name"); @@ -1868,15 +1869,24 @@ gg_change_status_descr(info->session, new_status_descr, new_msg); g_free(new_msg); } + + ggp_status_fake_to_self(account); + } /* }}} */ /* static void ggp_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group) {{{ */ static void ggp_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group) { + PurpleAccount *account; GGPInfo *info = gc->proto_data; gg_add_notify(info->session, ggp_str_to_uin(buddy->name)); + + account = purple_connection_get_account(gc); + if (strcmp(purple_account_get_username(account), buddy->name) == 0) { + ggp_status_fake_to_self(account); + } } /* }}} */ @@ -2148,7 +2158,7 @@ "prpl-gg", /* id */ "Gadu-Gadu", /* name */ - VERSION, /* version */ + DISPLAY_VERSION, /* version */ N_("Gadu-Gadu Protocol Plugin"), /* summary */ N_("Polish popular IM"), /* description */
--- a/libpurple/protocols/irc/dcc_send.c Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/protocols/irc/dcc_send.c Sat Nov 10 04:52:20 2007 +0000 @@ -251,7 +251,7 @@ * to the nonblocking nature of the listening socket, so we'll * just try again next time */ /* Let's print an error message anyway */ - purple_debug_warning("irc", "accept: %s\n", strerror(errno)); + purple_debug_warning("irc", "accept: %s\n", g_strerror(errno)); return; }
--- a/libpurple/protocols/irc/irc.c Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/protocols/irc/irc.c Sat Nov 10 04:52:20 2007 +0000 @@ -910,7 +910,7 @@ "prpl-irc", /**< id */ "IRC", /**< name */ - VERSION, /**< version */ + DISPLAY_VERSION, /**< version */ N_("IRC Protocol Plugin"), /** summary */ N_("The IRC Protocol Plugin that Sucks Less"), /** description */ NULL, /**< author */
--- a/libpurple/protocols/jabber/Makefile.mingw Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/protocols/jabber/Makefile.mingw Sat Nov 10 04:52:20 2007 +0000 @@ -88,6 +88,21 @@ INCLUDE_PATHS += -I$(CYRUS_SASL_TOP)/include LIB_PATHS += -L$(CYRUS_SASL_TOP)/lib LIBS += -llibsasl +CYRUS_SASL_DLLS = \ + $(CYRUS_SASL_TOP)/bin/comerr32.dll \ + $(CYRUS_SASL_TOP)/bin/gssapi32.dll \ + $(CYRUS_SASL_TOP)/bin/k5sprt32.dll \ + $(CYRUS_SASL_TOP)/bin/krb5_32.dll \ + $(CYRUS_SASL_TOP)/bin/libsasl.dll + +CYRUS_SASL_PLUGINS = \ + $(CYRUS_SASL_TOP)/bin/sasl2/saslANONYMOUS.dll \ + $(CYRUS_SASL_TOP)/bin/sasl2/saslCRAMMD5.dll \ + $(CYRUS_SASL_TOP)/bin/sasl2/saslDIGESTMD5.dll \ + $(CYRUS_SASL_TOP)/bin/sasl2/saslGSSAPI.dll \ + $(CYRUS_SASL_TOP)/bin/sasl2/saslLOGIN.dll \ + $(CYRUS_SASL_TOP)/bin/sasl2/saslPLAIN.dll + endif include $(PIDGIN_COMMON_RULES) @@ -102,6 +117,11 @@ install: all $(DLL_INSTALL_DIR) cp $(XMPP_TARGET).dll $(DLL_INSTALL_DIR) cp $(TARGET).dll $(PURPLE_INSTALL_DIR) +ifeq ($(CYRUS_SASL), 1) + mkdir -p $(PURPLE_INSTALL_DIR)/sasl2 + cp $(CYRUS_SASL_DLLS) $(PURPLE_INSTALL_DIR) + cp $(CYRUS_SASL_PLUGINS) $(PURPLE_INSTALL_DIR)/sasl2 +endif $(OBJECTS): $(PURPLE_CONFIG_H)
--- a/libpurple/protocols/jabber/adhoccommands.c Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/protocols/jabber/adhoccommands.c Sat Nov 10 04:52:20 2007 +0000 @@ -109,9 +109,15 @@ xmlnode_set_namespace(command,"http://jabber.org/protocol/commands"); xmlnode_set_attrib(command,"sessionid",actionInfo->sessionid); xmlnode_set_attrib(command,"node",actionInfo->node); - if(actionhandle) - xmlnode_set_attrib(command,"action",actionhandle); - xmlnode_insert_child(command,result); + + /* cancel is handled differently on ad-hoc commands than regular forms */ + if(!strcmp(xmlnode_get_namespace(result),"jabber:x:data") && !strcmp(xmlnode_get_attrib(result, "type"),"cancel")) { + xmlnode_set_attrib(command,"action","cancel"); + } else { + if(actionhandle) + xmlnode_set_attrib(command,"action",actionhandle); + xmlnode_insert_child(command,result); + } for(action = actionInfo->actionslist; action; action = g_list_next(action)) { char *handle = action->data;
--- a/libpurple/protocols/jabber/buddy.c Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/protocols/jabber/buddy.c Sat Nov 10 04:52:20 2007 +0000 @@ -279,7 +279,7 @@ char *tag; /* tag text */ char *ptag; /* parent tag "path" text */ char *url; /* vCard display format if URL */ -} vcard_template_data[] = { +} const vcard_template_data[] = { {N_("Full Name"), NULL, TRUE, TRUE, "FN", NULL, NULL}, {N_("Family Name"), NULL, TRUE, TRUE, "FAMILY", "N", NULL}, {N_("Given Name"), NULL, TRUE, TRUE, "GIVEN", "N", NULL}, @@ -311,7 +311,7 @@ struct tag_attr { char *attr; char *value; -} vcard_tag_attr_list[] = { +} const vcard_tag_attr_list[] = { {"prodid", "-//HandGen//NONSGML vGen v1.0//EN"}, {"version", "2.0", }, {"xmlns", "vcard-temp", }, @@ -337,7 +337,7 @@ * from the vCard template struct. */ if(parent_tag == NULL) { - struct vcard_template *vc_tp = vcard_template_data; + const struct vcard_template *vc_tp = vcard_template_data; while(vc_tp->label != NULL) { if(strcmp(vc_tp->tag, new_tag) == 0) { @@ -395,7 +395,7 @@ JabberIq *iq; JabberStream *js = gc->proto_data; xmlnode *vc_node; - struct tag_attr *tag_attr; + const struct tag_attr *tag_attr; /* if we have't grabbed the remote vcard yet, we can't * assume that what we have here is correct */ @@ -614,7 +614,7 @@ const char *text; char *p; const struct vcard_template *vc_tp; - struct tag_attr *tag_attr; + const struct tag_attr *tag_attr; vc_node = xmlnode_new("vCard"); @@ -2252,6 +2252,16 @@ xmlnode *query; JabberIq *iq; char *dir_server = data; + const char *type; + + /* if they've cancelled the search, we're + * just going to get an error if we send + * a cancel, so skip it */ + type = xmlnode_get_attrib(result, "type"); + if(type && !strcmp(type, "cancel")) { + g_free(dir_server); + return; + } iq = jabber_iq_new_query(js, JABBER_IQ_SET, "jabber:iq:search"); query = xmlnode_get_child(iq->node, "query");
--- a/libpurple/protocols/jabber/jabber.c Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/protocols/jabber/jabber.c Sat Nov 10 04:52:20 2007 +0000 @@ -1640,6 +1640,8 @@ if(type && !strcmp(type, "result")) { purple_notify_info(js->gc, _("Password Changed"), _("Password Changed"), _("Your password has been changed.")); + + purple_account_set_password(js->gc->account, (char *)data); } else { char *msg = jabber_parse_error(js, packet); @@ -1647,6 +1649,8 @@ _("Error changing password"), msg); g_free(msg); } + + g_free(data); } static void jabber_password_change_cb(JabberStream *js, @@ -1675,11 +1679,9 @@ y = xmlnode_new_child(query, "password"); xmlnode_insert_data(y, p1, -1); - jabber_iq_set_callback(iq, jabber_password_change_result_cb, NULL); + jabber_iq_set_callback(iq, jabber_password_change_result_cb, g_strdup(p1)); jabber_iq_send(iq); - - purple_account_set_password(js->gc->account, p1); } static void jabber_password_change(PurplePluginAction *action)
--- a/libpurple/protocols/jabber/libxmpp.c Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/protocols/jabber/libxmpp.c Sat Nov 10 04:52:20 2007 +0000 @@ -165,7 +165,7 @@ "prpl-jabber", /**< id */ "XMPP", /**< name */ - VERSION, /**< version */ + DISPLAY_VERSION, /**< version */ /** summary */ N_("XMPP Protocol Plugin"), /** description */ @@ -193,6 +193,9 @@ init_plugin(PurplePlugin *plugin) { #ifdef HAVE_CYRUS_SASL +#ifdef _WIN32 + gchar *sasldir; +#endif int ret; #endif PurpleAccountUserSplit *split; @@ -237,6 +240,11 @@ /* XXX - If any other plugin wants SASL this won't be good ... */ #ifdef HAVE_CYRUS_SASL +#ifdef _WIN32 + sasldir = g_build_filename(wpurple_install_dir(), "sasl2", NULL); + sasl_set_path(SASL_PATH_TYPE_PLUGIN, sasldir); + g_free(sasldir); +#endif if ((ret = sasl_client_init(NULL)) != SASL_OK) { purple_debug_error("xmpp", "Error (%d) initializing SASL.\n", ret); }
--- a/libpurple/protocols/jabber/si.c Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/protocols/jabber/si.c Sat Nov 10 04:52:20 2007 +0000 @@ -536,7 +536,7 @@ if(acceptfd == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) return; else if(acceptfd == -1) { - purple_debug_warning("jabber", "accept: %s\n", strerror(errno)); + purple_debug_warning("jabber", "accept: %s\n", g_strerror(errno)); return; }
--- a/libpurple/protocols/jabber/usermood.c Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/protocols/jabber/usermood.c Sat Nov 10 04:52:20 2007 +0000 @@ -28,7 +28,7 @@ #include "request.h" #include "debug.h" -static const char *moodstrings[] = { +static const char * const moodstrings[] = { "afraid", "amazed", "angry",
--- a/libpurple/protocols/msn/Makefile.am Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/protocols/msn/Makefile.am Sat Nov 10 04:52:20 2007 +0000 @@ -52,6 +52,8 @@ slpsession.h \ soap.c\ soap.h\ + soap2.c \ + soap2.h \ state.c \ state.h \ switchboard.c \
--- a/libpurple/protocols/msn/Makefile.mingw Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/protocols/msn/Makefile.mingw Sat Nov 10 04:52:20 2007 +0000 @@ -61,6 +61,7 @@ slpmsg.c \ slpsession.c \ soap.c\ + soap2.c\ state.c \ switchboard.c \ sync.c \
--- a/libpurple/protocols/msn/contact.c Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/protocols/msn/contact.c Sat Nov 10 04:52:20 2007 +0000 @@ -28,6 +28,7 @@ #include "contact.h" #include "xmlnode.h" #include "group.h" +#include "soap2.h" const char *MsnSoapPartnerScenarioText[] = { @@ -47,6 +48,11 @@ "Pending" }; +typedef struct { + MsnContact *contact; + MsnSoapPartnerScenario which; +} GetContactListCbData; + /* new a contact */ MsnContact * msn_contact_new(MsnSession *session) @@ -55,7 +61,6 @@ contact = g_new0(MsnContact, 1); contact->session = session; - contact->soapconn = msn_soap_new(session,contact,1); return contact; } @@ -64,15 +69,18 @@ void msn_contact_destroy(MsnContact *contact) { - msn_soap_destroy(contact->soapconn); g_free(contact); } MsnCallbackState * -msn_callback_state_new(void) +msn_callback_state_new(MsnSession *session) { - return g_new0(MsnCallbackState, 1); -} + MsnCallbackState *state = g_new0(MsnCallbackState, 1); + + state->session = session; + + return state; +} void msn_callback_state_free(MsnCallbackState *state) @@ -92,71 +100,56 @@ void msn_callback_state_set_who(MsnCallbackState *state, const gchar *who) { - gchar *new_str = NULL; - + gchar *nval; g_return_if_fail(state != NULL); - if (who != NULL) - new_str = g_strdup(who); - + nval = g_strdup(who); g_free(state->who); - state->who = new_str; + state->who = nval; } void msn_callback_state_set_uid(MsnCallbackState *state, const gchar *uid) { - gchar *new_str = NULL; - + gchar *nval; g_return_if_fail(state != NULL); - if (uid != NULL) - new_str = g_strdup(uid); - + nval = g_strdup(uid); g_free(state->uid); - state->uid = new_str; + state->uid = nval; } void msn_callback_state_set_old_group_name(MsnCallbackState *state, const gchar *old_group_name) { - gchar *new_str = NULL; - + gchar *nval; g_return_if_fail(state != NULL); - if (old_group_name != NULL) - new_str = g_strdup(old_group_name); - + nval = g_strdup(old_group_name); g_free(state->old_group_name); - state->old_group_name = new_str; + state->old_group_name = nval; } void msn_callback_state_set_new_group_name(MsnCallbackState *state, const gchar *new_group_name) { - gchar *new_str = NULL; - + gchar *nval; g_return_if_fail(state != NULL); - if (new_group_name != NULL) - new_str = g_strdup(new_group_name); - + nval = g_strdup(new_group_name); g_free(state->new_group_name); - state->new_group_name = new_str; + state->new_group_name = nval; } void msn_callback_state_set_guid(MsnCallbackState *state, const gchar *guid) { - gchar *new_str = NULL; - + gchar *nval; g_return_if_fail(state != NULL); - if (guid != NULL) - new_str = g_strdup(guid); - + nval = g_strdup(guid); g_free(state->guid); - state->guid = new_str; + state->guid = nval; } @@ -176,36 +169,6 @@ state->action |= action; } -/*contact SOAP server login error*/ -static void -msn_contact_login_error_cb(MsnSoapConn *soapconn, PurpleSslConnection *gsc, PurpleSslErrorType error) -{ - MsnSession *session; - - session = soapconn->session; - g_return_if_fail(session != NULL); - - msn_session_set_error(session, MSN_ERROR_SERV_DOWN, _("Unable to connect to contact server")); -} - -/*msn contact SOAP server connect process*/ -static gboolean -msn_contact_login_connect_cb(MsnSoapConn *soapconn, PurpleSslConnection *gsc) -{ - MsnSession * session; - MsnContact *contact; - - contact = soapconn->parent; - g_return_val_if_fail(contact != NULL, TRUE); - - session = contact->session; - g_return_val_if_fail(session != NULL, FALSE); - - /*login ok!We can retrieve the contact list*/ -// msn_get_contact_list(contact, MSN_PS_INITIAL, NULL); - return TRUE; -} - /*get MSN member role utility*/ static MsnListId msn_get_memberrole(const char *role) @@ -244,37 +207,20 @@ } /* Create the AddressBook in the server, if we don't have one */ -static gboolean -msn_create_address_cb(MsnSoapConn *soapconn) +static void +msn_create_address_cb(MsnSoapMessage *req, MsnSoapMessage *resp, gpointer data) { - MsnContact *contact; - - if (soapconn->body == NULL) - return TRUE; - - contact = soapconn->parent; - g_return_val_if_fail(contact != NULL, TRUE); - - purple_debug_info("MSN AddressBook", "Address Book successfully created!\n"); - msn_get_address_book(contact, MSN_PS_INITIAL, NULL, NULL); - -// msn_soap_free_read_buf(soapconn); - return TRUE; -} - -static void -msn_create_address_written_cb(MsnSoapConn *soapconn) -{ - purple_debug_info("MSN AddressBook","AddressBookAdd written\n"); - soapconn->read_cb = msn_create_address_cb; - - return; + if (resp && msn_soap_xml_get(resp->xml, "Body/Fault") == NULL) { + purple_debug_info("msnab", "Address Book successfully created!\n"); + msn_get_address_book((MsnContact *)data, MSN_PS_INITIAL, NULL, NULL); + } else { + purple_debug_info("msnab", "Address Book creation failed!\n"); + } } static void msn_create_address_book(MsnContact * contact) { - MsnSoapReq *soap_request; gchar *body; g_return_if_fail(contact != NULL); @@ -282,323 +228,185 @@ g_return_if_fail(contact->session->user != NULL); g_return_if_fail(contact->session->user->passport != NULL); - purple_debug_info("MSN AddressBook","Creating an Address Book.\n"); + purple_debug_info("msnab","Creating an Address Book.\n"); body = g_strdup_printf(MSN_ADD_ADDRESSBOOK_TEMPLATE, contact->session->user->passport); - soap_request = msn_soap_request_new(MSN_CONTACT_SERVER, - MSN_ADDRESS_BOOK_POST_URL,MSN_ADD_ADDRESSBOOK_SOAP_ACTION, - body, - NULL, - msn_create_address_cb, - msn_create_address_written_cb, - msn_contact_connect_init); - msn_soap_post(contact->soapconn, soap_request); + msn_soap_message_send(contact->session, + msn_soap_message_new(MSN_ADD_ADDRESSBOOK_SOAP_ACTION, + xmlnode_from_str(body, -1)), + MSN_CONTACT_SERVER, MSN_ADDRESS_BOOK_POST_URL, msn_create_address_cb, + contact); g_free(body); - - return; +} + +static void +msn_parse_each_member(MsnSession *session, xmlnode *member, const char *node, + MsnListId list) +{ + char *passport = xmlnode_get_data(xmlnode_get_child(member, node)); + char *type = xmlnode_get_data(xmlnode_get_child(member, "Type")); + char *member_id = xmlnode_get_data(xmlnode_get_child(member, "MembershipId")); + MsnUser *user = msn_userlist_find_add_user(session->userlist, passport, NULL); + + purple_debug_info("msncl","%s name: %s, Type: %s, MembershipID: %s\n", + node, passport, type, member_id == NULL ? "(null)" : member_id); + + if (member_id) { + user->membership_id[list] = atoi(member_id); + } + + msn_got_lst_user(session, user, 1 << list, NULL); + + g_free(passport); + g_free(type); + g_free(member_id); +} + +static void +msn_parse_each_service(MsnSession *session, xmlnode *service) +{ + xmlnode *type; + + if ((type = msn_soap_xml_get(service, "Info/Handle/Type"))) { + char *type_str = xmlnode_get_data(type); + + if (g_str_equal(type_str, "Profile")) { + /* Process Windows Live 'Messenger Roaming Identity' */ + } else if (g_str_equal(type_str, "Messenger")) { + xmlnode *lastchange = xmlnode_get_child(service, "LastChange"); + char *lastchange_str = xmlnode_get_data(lastchange); + xmlnode *membership; + + purple_debug_info("msncl","last change: %s\n", lastchange_str); + purple_account_set_string(session->account, "CLLastChange", + lastchange_str); + + for (membership = msn_soap_xml_get(service, + "Memberships/Membership"); + membership; membership = xmlnode_get_next_twin(membership)) { + + xmlnode *role = xmlnode_get_child(membership, "MemberRole"); + char *role_str = xmlnode_get_data(role); + MsnListId list = msn_get_memberrole(role_str); + xmlnode *member; + + purple_debug_info("msncl", "MemberRole role: %s, list: %d\n", + role_str, list); + + for (member = msn_soap_xml_get(membership, "Members/Member"); + member; member = xmlnode_get_next_twin(member)) { + const char *member_type = xmlnode_get_attrib(member, "type"); + if (g_str_equal(member_type, "PassportMember")) { + msn_parse_each_member(session, member, "PassportName", + list); + } else if (g_str_equal(member_type, "PhoneMember")) { + + } else if (g_str_equal(member_type, "EmailMember")) { + msn_parse_each_member(session, member, "Email", list); + } + } + + g_free(role_str); + } + + g_free(lastchange_str); + } + + g_free(type_str); + } } /*parse contact list*/ static void -msn_parse_contact_list(MsnContact * contact) +msn_parse_contact_list(MsnContact *contact, xmlnode *node) { - MsnSession * session; - MsnListOp list_op = 0; - MsnListId list; - char * passport, *typedata; - xmlnode *fault, *faultstringnode, *faultdetail, *errorcode; - xmlnode *node, *body, *response, *result, *services; - xmlnode *service, *memberships, *info, *handle, *handletype; - xmlnode *membershipnode, *members, *member, *passportNode; - - session = contact->session; - node = xmlnode_from_str(contact->soapconn->body, contact->soapconn->body_len); - - if (node == NULL) { - purple_debug_error("MSNCL","Unable to parse SOAP data!\n"); - return; - } - - purple_debug_misc("MSNCL","Parsing contact list with size %d\n", contact->soapconn->body_len); + xmlnode *fault, *faultnode; - purple_debug_misc("MSNCL","Root node @ %p: Name: '%s', child: '%s', lastchild: '%s'\n", node, - node->name ? node->name : "(null)", - (node->child && node->child->name) ? node->child->name : "(null)", - (node->lastchild && node->lastchild->name) ? node->lastchild->name : "(null)"); - - body = xmlnode_get_child(node, "Body"); - - if (body == NULL) { - purple_debug_warning("MSNCL", "Failed to parse contact list Body node\n"); - xmlnode_free(node); - return; - } - purple_debug_info("MSNCL","Body @ %p: Name: '%s'\n",body,body->name); - - /* Did we receive a <Fault> ? */ - if ( (fault = xmlnode_get_child(body, "Fault")) != NULL) { - purple_debug_info("MSNCL","Fault received from SOAP server!\n"); - - if ( (faultstringnode = xmlnode_get_child(fault, "faultstring")) != NULL ) { - gchar * faultstring = xmlnode_get_data(faultstringnode); - purple_debug_info("MSNCL", "Faultstring: %s\n", faultstring ? faultstring : "(null)"); + /* we may get a response if our cache data is too old: + * + * <faultstring>Need to do full sync. Can't sync deltas Client + * has too old a copy for us to do a delta sync</faultstring> + * + * this is not handled yet + */ + if ((fault = msn_soap_xml_get(node, "Body/Fault"))) { + if ((faultnode = xmlnode_get_child(fault, "faultstring"))) { + char *faultstring = xmlnode_get_data(faultnode); + purple_debug_info("msncl", "Retrieving contact list failed: %s\n", + faultstring); g_free(faultstring); } - if ( (faultdetail = xmlnode_get_child(fault, "detail")) != NULL ) { - purple_debug_info("MSNCL","detail @ %p, name: %s\n",faultdetail, faultdetail->name); - - if ( (errorcode = xmlnode_get_child(faultdetail, "errorcode")) != NULL ) { - purple_debug_info("MSNCL","errorcode @ %p, name: %s\n", errorcode, errorcode->name); - - if (errorcode->child != NULL) { - gchar *errorcodestring = xmlnode_get_data(errorcode); - purple_debug_info("MSNCL", "Error Code: %s\n", errorcodestring ? errorcodestring : "(null)"); - - if (errorcodestring && !strncmp(errorcodestring, "ABDoesNotExist", 14) ) { - xmlnode_free(node); - g_free(errorcodestring); - msn_create_address_book(contact); - return; - } - g_free(errorcodestring); - } - } - } - xmlnode_free(node); - msn_get_contact_list(contact, MSN_PS_INITIAL, NULL); - return; - } - - response = xmlnode_get_child(body,"FindMembershipResponse"); - - if (response == NULL) { - /* we may get a response if our cache data is too old: - * - * <faultstring>Need to do full sync. Can't sync deltas Client - * has too old a copy for us to do a delta sync</faultstring> - */ - xmlnode_free(node); - msn_get_contact_list(contact, MSN_PS_INITIAL, NULL); - return; - } - purple_debug_info("MSNCL","FindMembershipResponse @ %p: Name: '%s'\n",response,response->name); + if ((faultnode = msn_soap_xml_get(fault, "detail/errorcode"))) { + char *errorcode = xmlnode_get_data(faultnode); - result = xmlnode_get_child(response,"FindMembershipResult"); - if (result == NULL) { - purple_debug_warning("MSNCL","Received No Update!\n"); - xmlnode_free(node); - return; - } - purple_debug_info("MSNCL","Result @ %p: Name: '%s'\n", result, result->name); - - if ( (services = xmlnode_get_child(result,"Services")) == NULL) { - purple_debug_misc("MSNCL","No <Services> received.\n"); - xmlnode_free(node); - return; - } - - purple_debug_info("MSNCL","Services @ %p\n",services); - - for (service = xmlnode_get_child(services, "Service"); service; - service = xmlnode_get_next_twin(service)) { - purple_debug_info("MSNCL","Service @ %p\n",service); + if (g_str_equal(errorcode, "ABDoesNotExist")) { + msn_create_address_book(contact); + g_free(errorcode); + return; + } - if ( (info = xmlnode_get_child(service,"Info")) == NULL ) { - purple_debug_error("MSNCL","Error getting 'Info' child node\n"); - continue; - } - if ( (handle = xmlnode_get_child(info,"Handle")) == NULL ) { - purple_debug_error("MSNCL","Error getting 'Handle' child node\n"); - continue; - } - if ( (handletype = xmlnode_get_child(handle,"Type")) == NULL ) { - purple_debug_error("MSNCL","Error getting 'Type' child node\n"); - continue; - } - - if ( (typedata = xmlnode_get_data(handletype)) == NULL) { - purple_debug_error("MSNCL","Error retrieving data from 'Type' child node\n"); - continue; - } - - purple_debug_info("MSNCL","processing '%s' Service\n", typedata); - - if ( !g_strcasecmp(typedata, "Profile") ) { - /* Process Windows Live 'Messenger Roaming Identity' */ - g_free(typedata); - continue; + g_free(errorcode); } - if ( !g_strcasecmp(typedata, "Messenger") ) { - char *LastChangeStr = NULL; - xmlnode *LastChangeNode; - - /*Last Change Node*/ - if ((LastChangeNode = xmlnode_get_child(service, "LastChange"))) - LastChangeStr = xmlnode_get_data(LastChangeNode); - purple_debug_info("MSNCL","LastChangeNode: '%s'\n",LastChangeStr ? LastChangeStr : "(null)"); - purple_account_set_string(session->account, "CLLastChange", LastChangeStr); - g_free(LastChangeStr); - - memberships = xmlnode_get_child(service,"Memberships"); - if (memberships == NULL) { - purple_debug_warning("MSNCL","Memberships = NULL, cleaning up and returning.\n"); - g_free(typedata); - xmlnode_free(node); - return; - } - purple_debug_info("MSNCL","Memberships @ %p: Name: '%s'\n",memberships,memberships->name); - for (membershipnode = xmlnode_get_child(memberships, "Membership"); membershipnode; - membershipnode = xmlnode_get_next_twin(membershipnode)){ - xmlnode *roleNode; - char *role = NULL; - list = 0; - - if ((roleNode = xmlnode_get_child(membershipnode,"MemberRole"))) { - role = xmlnode_get_data(roleNode); - list = msn_get_memberrole(role); - } - list_op = 1 << list; - - purple_debug_info("MSNCL","MemberRole role: %s, list_op: %d\n", role ? role : "(null)", list_op); - - g_free(role); - - members = xmlnode_get_child(membershipnode, "Members"); - for (member = xmlnode_get_child(members, "Member"); member; - member = xmlnode_get_next_twin(member)){ - MsnUser *user = NULL; - xmlnode *typeNode, *membershipIdNode = NULL; - gchar *type, *membershipId = NULL; - const char *member_type = xmlnode_get_attrib(member, "type"); - - if (!member_type) { - purple_debug_error("msn", "No Member Type specified for Member.\n"); - continue; - } - - if(!g_strcasecmp(member_type, "PassportMember") ) { - passport = type = NULL; - if ((passportNode = xmlnode_get_child(member, "PassportName"))) - passport = xmlnode_get_data(passportNode); - if ((typeNode = xmlnode_get_child(member, "Type"))) - type = xmlnode_get_data(typeNode); - purple_debug_info("MSNCL","Passport name: '%s', Type: %s\n", passport ? passport : "(null)", type ? type : "(null)"); - /* Why do we even bother parsing it just to free it??? */ - g_free(type); - - user = msn_userlist_find_add_user(session->userlist,passport,NULL); - g_free(passport); - - membershipIdNode = xmlnode_get_child(member,"MembershipId"); - if (membershipIdNode != NULL) { - membershipId = xmlnode_get_data(membershipIdNode); - if (membershipId != NULL) { - user->membership_id[list] = atoi(membershipId); - g_free(membershipId); - } - } + msn_get_contact_list(contact, MSN_PS_INITIAL, NULL); + } else { + xmlnode *service; - msn_got_lst_user(session, user, list_op, NULL); - } - else if (!g_strcasecmp(member_type, "PhoneMember")) { - purple_debug_info("msn", "Recieved Phone Member; ignoring.\n"); - } - else if (!g_strcasecmp(member_type, "EmailMember")) { - xmlnode *emailNode; - passport = NULL; - - if ((emailNode = xmlnode_get_child(member, "Email"))) - passport = xmlnode_get_data(emailNode); - purple_debug_info("MSNCL","Email Member: Name: '%s', list_op: %d\n", passport ? passport : "(null)", list_op); - - user = msn_userlist_find_add_user(session->userlist, passport, NULL); - g_free(passport); - - membershipIdNode = xmlnode_get_child(member,"MembershipId"); - if (membershipIdNode != NULL) { - membershipId = xmlnode_get_data(membershipIdNode); - if (membershipId != NULL) { - user->membership_id[list] = atoi(membershipId); - g_free(membershipId); - } - } - - msn_got_lst_user(session, user, list_op, NULL); - } else { - purple_debug_info("msn", "Unknown Member type: %s\n", member_type); - } - } - } + for (service = msn_soap_xml_get(node, "Body/FindMembershipResponse/" + "FindMembershipResult/Services/Service"); + service; service = xmlnode_get_next_twin(service)) { + msn_parse_each_service(contact->session, service); } - g_free(typedata); } - - xmlnode_free(node); /* Free the whole XML tree */ -} - -static gboolean -msn_get_contact_list_cb(MsnSoapConn *soapconn) -{ - MsnContact *contact; - MsnSession *session; - const char *abLastChange; - const char *dynamicItemLastChange; - gchar *partner_scenario; - - if (soapconn->body == NULL) - return TRUE; - - purple_debug_misc("MSNCL","Got the contact list!\n"); - - contact = soapconn->parent; - g_return_val_if_fail(contact != NULL, TRUE); - session = soapconn->session; - g_return_val_if_fail(session != NULL, FALSE); - g_return_val_if_fail(soapconn->data_cb != NULL, TRUE); - - partner_scenario = soapconn->data_cb; - - msn_parse_contact_list(contact); - /*free the read buffer*/ - msn_soap_free_read_buf(soapconn); - - abLastChange = purple_account_get_string(session->account, "ablastChange", NULL); - dynamicItemLastChange = purple_account_get_string(session->account, "dynamicItemLastChange", NULL); - - if (!strcmp(partner_scenario, MsnSoapPartnerScenarioText[MSN_PS_INITIAL])) { - -#ifdef MSN_PARTIAL_LISTS - /* XXX: this should be enabled when we can correctly do partial - syncs with the server. Currently we need to retrieve the whole - list to detect sync issues */ - msn_get_address_book(contact, MSN_PS_INITIAL, abLastChange, dynamicItemLastChange); -#else - msn_get_address_book(contact, MSN_PS_INITIAL, NULL, NULL); -#endif - } else { - msn_soap_free_read_buf(soapconn); - } - - return TRUE; } static void -msn_get_contact_written_cb(MsnSoapConn *soapconn) +msn_get_contact_list_cb(MsnSoapMessage *req, MsnSoapMessage *resp, + gpointer data) { - purple_debug_misc("MSNCL","Sent SOAP request for the contact list.\n"); - soapconn->read_cb = msn_get_contact_list_cb; + GetContactListCbData *cb_data = data; + MsnContact *contact = cb_data->contact; + MsnSession *session = contact->session; + + g_return_if_fail(session != NULL); + + if (resp != NULL) { + const char *abLastChange; + const char *dynamicItemLastChange; + + purple_debug_misc("msncl","Got the contact list!\n"); + + msn_parse_contact_list(cb_data->contact, resp->xml); + abLastChange = purple_account_get_string(session->account, + "ablastChange", NULL); + dynamicItemLastChange = purple_account_get_string(session->account, + "dynamicItemLastChange", NULL); + + if (cb_data->which == MSN_PS_INITIAL) { +#ifdef MSN_PARTIAL_LISTS + /* XXX: this should be enabled when we can correctly do partial + syncs with the server. Currently we need to retrieve the whole + list to detect sync issues */ + msn_get_address_book(contact, MSN_PS_INITIAL, abLastChange, dynamicItemLastChange); +#else + msn_get_address_book(contact, MSN_PS_INITIAL, NULL, NULL); +#endif + } + } + + g_free(cb_data); } -/* SOAP get contact list*/ +/*SOAP get contact list*/ void -msn_get_contact_list(MsnContact * contact, const MsnSoapPartnerScenario partner_scenario, const char *update_time) +msn_get_contact_list(MsnContact * contact, + const MsnSoapPartnerScenario partner_scenario, const char *update_time) { - MsnSoapReq *soap_request; - gchar *body; + gchar *body = NULL; gchar *update_str = NULL; + GetContactListCbData cb_data = { contact, partner_scenario }; const gchar *partner_scenario_str = MsnSoapPartnerScenarioText[partner_scenario]; purple_debug_misc("MSNCL","Getting Contact List.\n"); @@ -609,17 +417,14 @@ } body = g_strdup_printf(MSN_GET_CONTACT_TEMPLATE, partner_scenario_str, update_str ? update_str : ""); - g_free(update_str); - soap_request = msn_soap_request_new(MSN_CONTACT_SERVER, - MSN_GET_CONTACT_POST_URL, - MSN_GET_CONTACT_SOAP_ACTION, - body, - (gpointer) partner_scenario_str, - msn_get_contact_list_cb, - msn_get_contact_written_cb, - msn_contact_connect_init); - msn_soap_post(contact->soapconn,soap_request); + msn_soap_message_send(contact->session, + msn_soap_message_new(MSN_GET_CONTACT_SOAP_ACTION, + xmlnode_from_str(body, -1)), + MSN_CONTACT_SERVER, MSN_GET_CONTACT_POST_URL, + msn_get_contact_list_cb, g_memdup(&cb_data, sizeof(cb_data))); + + g_free(update_str); g_free(body); } @@ -629,7 +434,7 @@ MsnSession *session = contact->session; xmlnode *group; - purple_debug_info("MsnAb","msn_parse_addressbook_groups()\n"); + purple_debug_info("MSNAB","msn_parse_addressbook_groups()\n"); for(group = xmlnode_get_child(node, "Group"); group; group = xmlnode_get_next_twin(group)){ @@ -781,81 +586,48 @@ } static gboolean -msn_parse_addressbook(MsnContact * contact) +msn_parse_addressbook(MsnContact * contact, xmlnode *node) { - MsnSession *session; - xmlnode * node,*body,*response,*result; + MsnSession * session; + xmlnode *result; xmlnode *groups; xmlnode *contacts; xmlnode *abNode; - xmlnode *fault, *faultstringnode, *faultdetail, *errorcode; + xmlnode *fault; session = contact->session; - node = xmlnode_from_str(contact->soapconn->body, contact->soapconn->body_len); - if ( node == NULL ) { - purple_debug_error("MSN AddressBook","Error parsing Address Book with size %d\n", contact->soapconn->body_len); + if ((fault = msn_soap_xml_get(node, "Body/Fault"))) { + xmlnode *faultnode; + + if ((faultnode = xmlnode_get_child(fault, "faultstring"))) { + gchar *faultstring = xmlnode_get_data(faultnode); + purple_debug_info("MSNAB","Faultstring: %s\n", faultstring); + g_free(faultstring); + } + + if ((faultnode = msn_soap_xml_get(fault, "detail/errorcode"))) { + gchar *errorcode = xmlnode_get_data(faultnode); + + purple_debug_info("MSNAB", "Error Code: %s\n", errorcode); + + if (g_str_equal(errorcode, "ABDoesNotExist")) { + g_free(errorcode); + return TRUE; + } + } + return FALSE; } - purple_debug_misc("MSN AddressBook", "Parsing Address Book with size %d\n", contact->soapconn->body_len); - - purple_debug_misc("MSN AddressBook","node{%p},name:%s,child:%s,last:%s\n", node, - node->name ? node->name : "(null)", - (node->child && node->child->name) ? node->child->name : "(null)", - (node->lastchild && node->lastchild->name) ? node->lastchild->name : "(null)"); - - body = xmlnode_get_child(node,"Body"); - purple_debug_misc("MSN AddressBook","body{%p},name:%s\n",body,body->name); - - /* TODO: This appears to be used in a number of places and should be de-duplicated */ - if ( (fault = xmlnode_get_child(body, "Fault")) != NULL) { - purple_debug_info("MSN AddressBook","Fault received from SOAP server!\n"); - - if ( (faultstringnode = xmlnode_get_child(fault, "faultstring")) != NULL ) { - gchar *faultstring = xmlnode_get_data(faultstringnode); - purple_debug_info("MSN AddressBook","Faultstring: %s\n", faultstring ? faultstring : "(null)"); - g_free(faultstring); - } - if ( (faultdetail = xmlnode_get_child(fault, "detail")) != NULL ) { - purple_debug_info("MSN AddressBook","detail @ %p, name: %s\n",faultdetail, faultdetail->name); - - if ( (errorcode = xmlnode_get_child(faultdetail, "errorcode")) != NULL ) { - gchar *errorcodestring; - purple_debug_info("MSN AddressBook","errorcode @ %p, name: %s\n",errorcode, errorcode->name); - - errorcodestring = xmlnode_get_data(errorcode); - purple_debug_info("MSN AddressBook", "Error Code: %s\n", errorcodestring ? errorcodestring : "(null)"); - - if (errorcodestring && !strncmp(errorcodestring, "ABDoesNotExist", 14) ) { - g_free(errorcodestring); - xmlnode_free(node); - return TRUE; - } - g_free(errorcodestring); - } - } - xmlnode_free(node); - return FALSE; + result = msn_soap_xml_get(node, "Body/ABFindAllResponse/ABFindAllResult"); + if(result == NULL){ + purple_debug_misc("MSNAB","receive no address book update\n"); + return TRUE; } - - response = xmlnode_get_child(body,"ABFindAllResponse"); - - if (response == NULL) { - xmlnode_free(node); - return FALSE; - } - - purple_debug_misc("MSN SOAP","response{%p},name:%s\n",response,response->name); - result = xmlnode_get_child(response,"ABFindAllResult"); - if(result == NULL){ - purple_debug_misc("MSNAB","receive no address book update\n"); - xmlnode_free(node); - return TRUE; - } - purple_debug_info("MSN SOAP","result{%p},name:%s\n",result,result->name); - + /* I don't see this "groups" tag documented on msnpiki, need to find out + if they are really there, and update msnpiki */ /*Process Group List*/ groups = xmlnode_get_child(result,"groups"); if (groups != NULL) { @@ -865,7 +637,7 @@ /*add a default No group to set up the no group Membership*/ msn_group_new(session->userlist, MSN_INDIVIDUALS_GROUP_ID, MSN_INDIVIDUALS_GROUP_NAME); - purple_debug_misc("MsnAB","group_id:%s name:%s\n", + purple_debug_misc("MSNAB","group_id:%s name:%s\n", MSN_INDIVIDUALS_GROUP_ID, MSN_INDIVIDUALS_GROUP_NAME); if ((purple_find_group(MSN_INDIVIDUALS_GROUP_NAME)) == NULL){ PurpleGroup *g = purple_group_new(MSN_INDIVIDUALS_GROUP_NAME); @@ -874,7 +646,7 @@ /*add a default No group to set up the no group Membership*/ msn_group_new(session->userlist, MSN_NON_IM_GROUP_ID, MSN_NON_IM_GROUP_NAME); - purple_debug_misc("MsnAB","group_id:%s name:%s\n", MSN_NON_IM_GROUP_ID, MSN_NON_IM_GROUP_NAME); + purple_debug_misc("MSNAB","group_id:%s name:%s\n", MSN_NON_IM_GROUP_ID, MSN_NON_IM_GROUP_NAME); if ((purple_find_group(MSN_NON_IM_GROUP_NAME)) == NULL){ PurpleGroup *g = purple_group_new(MSN_NON_IM_GROUP_NAME); purple_blist_add_group(g, NULL); @@ -894,7 +666,7 @@ if ((node2 = xmlnode_get_child(abNode, "lastChange"))) tmp = xmlnode_get_data(node2); - purple_debug_info("MsnAB"," lastchanged Time:{%s}\n", tmp ? tmp : "(null)"); + purple_debug_info("MSNAB"," lastchanged Time:{%s}\n", tmp ? tmp : "(null)"); purple_account_set_string(session->account, "ablastChange", tmp); g_free(tmp); tmp = NULL; @@ -905,68 +677,51 @@ g_free(tmp); } - xmlnode_free(node); - msn_soap_free_read_buf(contact->soapconn); return TRUE; } -static gboolean -msn_get_address_cb(MsnSoapConn *soapconn) +static void +msn_get_address_cb(MsnSoapMessage *req, MsnSoapMessage *resp, gpointer data) { - MsnContact *contact; + MsnContact *contact = data; MsnSession *session; - if (soapconn->body == NULL) - return TRUE; + if (resp == NULL) + return; - contact = soapconn->parent; - g_return_val_if_fail(contact != NULL, TRUE); - session = soapconn->session; - g_return_val_if_fail(session != NULL, FALSE); + g_return_if_fail(contact != NULL); + session = contact->session; + g_return_if_fail(session != NULL); - purple_debug_misc("MSN AddressBook", "Got the Address Book!\n"); + purple_debug_misc("MSNAB", "Got the Address Book!\n"); - if ( msn_parse_addressbook(contact) ) { - //msn_soap_free_read_buf(soapconn); - + if (msn_parse_addressbook(contact, resp->xml)) { if (!session->logged_in) { msn_send_privacy(session->account->gc); msn_notification_dump_contact(session); } - - /*free the read buffer*/ - msn_soap_free_read_buf(soapconn); - return TRUE; } else { - /* This is making us loop infinitely when we fail to parse the address book, - disable for now (we should re-enable when we send timestamps) + /* This is making us loop infinitely when we fail to parse the + address book, disable for now (we should re-enable when we + send timestamps) */ /* msn_get_address_book(contact, NULL, NULL); */ msn_session_disconnect(session); purple_connection_error(session->account->gc, _("Unable to retrieve MSN Address Book")); - return FALSE; } } -/**/ -static void -msn_address_written_cb(MsnSoapConn *soapconn) -{ - purple_debug_misc("MSN AddressBook","Sent SOAP request for the Address Book.\n"); - soapconn->read_cb = msn_get_address_cb; -} - /*get the address book*/ void -msn_get_address_book(MsnContact *contact, const MsnSoapPartnerScenario partner_scenario, const char *LastChanged, const char *dynamicItemLastChange) +msn_get_address_book(MsnContact *contact, + MsnSoapPartnerScenario partner_scenario, const char *LastChanged, + const char *dynamicItemLastChange) { - MsnSoapReq *soap_request; - char *body; - char *update_str = NULL; + char *body, *update_str = NULL; - purple_debug_misc("MSN AddressBook","Getting Address Book\n"); + purple_debug_misc("MSNAB","Getting Address Book\n"); /*build SOAP and POST it*/ if (dynamicItemLastChange != NULL) @@ -974,79 +729,58 @@ else if (LastChanged != NULL) update_str = g_strdup_printf(MSN_GET_ADDRESS_UPDATE_XML, LastChanged); - body = g_strdup_printf(MSN_GET_ADDRESS_TEMPLATE, MsnSoapPartnerScenarioText[partner_scenario], update_str ? update_str : ""); - g_free(update_str); - soap_request = msn_soap_request_new(MSN_CONTACT_SERVER, - MSN_ADDRESS_BOOK_POST_URL,MSN_GET_ADDRESS_SOAP_ACTION, - body, - NULL, - msn_get_address_cb, - msn_address_written_cb, - msn_contact_connect_init); - msn_soap_post(contact->soapconn,soap_request); + msn_soap_message_send(contact->session, + msn_soap_message_new(MSN_GET_ADDRESS_SOAP_ACTION, + xmlnode_from_str(body, -1)), + MSN_CONTACT_SERVER, MSN_ADDRESS_BOOK_POST_URL, msn_get_address_cb, + contact); + + g_free(update_str); g_free(body); } -static gboolean -msn_add_contact_read_cb(MsnSoapConn *soapconn) +static void +msn_add_contact_read_cb(MsnSoapMessage *req, MsnSoapMessage *resp, + gpointer data) { - MsnCallbackState *state = NULL; - MsnUserList *userlist; - MsnUser *user; - - g_return_val_if_fail(soapconn->data_cb != NULL, TRUE); - g_return_val_if_fail(soapconn->session != NULL, FALSE); - g_return_val_if_fail(soapconn->session->userlist != NULL, TRUE); + MsnCallbackState *state = data; + MsnSession *session = state->session; - state = (MsnCallbackState *) soapconn->data_cb; + g_return_if_fail(session != NULL); - if (soapconn->body == NULL) { - msn_callback_state_free(state); - return TRUE; - } + if (resp != NULL) { + MsnUserList *userlist = session->userlist; + MsnUser *user; - userlist = soapconn->session->userlist; - - purple_debug_info("MSNCL","Contact added successfully\n"); + purple_debug_info("MSNCL","Contact added successfully\n"); - // the code this block is replacing didn't send ADL for yahoo contacts, - // but i haven't confirmed this is WLM's behaviour wrt yahoo contacts - - if ( !msn_user_is_yahoo(soapconn->session->account, state->who) ) { - - msn_userlist_add_buddy_to_list(userlist, state->who, MSN_LIST_AL); - msn_userlist_add_buddy_to_list(userlist, state->who, MSN_LIST_FL); - } - msn_notification_send_fqy(soapconn->session, state->who); + // the code this block is replacing didn't send ADL for yahoo contacts, + // but i haven't confirmed this is WLM's behaviour wrt yahoo contacts + if ( !msn_user_is_yahoo(session->account, state->who) ) { + msn_userlist_add_buddy_to_list(userlist, state->who, MSN_LIST_AL); + msn_userlist_add_buddy_to_list(userlist, state->who, MSN_LIST_FL); + } - user = msn_userlist_find_add_user(userlist, state->who, state->who); - msn_user_add_group_id(user, state->guid); - - msn_soap_free_read_buf(soapconn); - msn_callback_state_free(state); + msn_notification_send_fqy(session, state->who); - return TRUE; -} + user = msn_userlist_find_add_user(userlist, state->who, state->who); + msn_user_add_group_id(user, state->guid); + } -static void -msn_add_contact_written_cb(MsnSoapConn *soapconn) -{ - purple_debug_info("MSNCL","Add contact request written\n"); - soapconn->read_cb = msn_add_contact_read_cb; + msn_callback_state_free(state); } /* add a Contact in MSN_INDIVIDUALS_GROUP */ void msn_add_contact(MsnContact *contact, MsnCallbackState *state, const char *passport) { - MsnSoapReq *soap_request; gchar *body = NULL; gchar *contact_xml = NULL; - g_return_if_fail(passport != NULL); -/* gchar *escaped_displayname; +#if 0 + gchar *escaped_displayname; if (displayname != NULL) { @@ -1055,87 +789,71 @@ escaped_displayname = passport; } contact_xml = g_strdup_printf(MSN_XML_ADD_CONTACT, escaped_displayname, passport); -*/ +#endif + purple_debug_info("MSNCL","Adding contact %s to contact list\n", passport); -// if ( !strcmp(state->guid, MSN_INDIVIDUALS_GROUP_ID) ) { - contact_xml = g_strdup_printf(MSN_CONTACT_XML, passport); -// } + contact_xml = g_strdup_printf(MSN_CONTACT_XML, passport); body = g_strdup_printf(MSN_ADD_CONTACT_TEMPLATE, contact_xml); + msn_soap_message_send(contact->session, + msn_soap_message_new(MSN_CONTACT_ADD_SOAP_ACTION, + xmlnode_from_str(body, -1)), + MSN_CONTACT_SERVER, MSN_ADDRESS_BOOK_POST_URL, + msn_add_contact_read_cb, state); + g_free(contact_xml); - - /*build SOAP and POST it*/ - - soap_request = msn_soap_request_new(MSN_CONTACT_SERVER, - MSN_ADDRESS_BOOK_POST_URL, - MSN_CONTACT_ADD_SOAP_ACTION, - body, - state, - msn_add_contact_read_cb, - msn_add_contact_written_cb, - msn_contact_connect_init); - msn_soap_post(contact->soapconn,soap_request); - g_free(body); } -static gboolean -msn_add_contact_to_group_read_cb(MsnSoapConn *soapconn) +static void +msn_add_contact_to_group_read_cb(MsnSoapMessage *req, MsnSoapMessage *resp, + gpointer data) { - MsnCallbackState *state; + MsnCallbackState *state = data; MsnUserList *userlist; - g_return_val_if_fail(soapconn->data_cb != NULL, TRUE); - g_return_val_if_fail(soapconn->session != NULL, FALSE); - g_return_val_if_fail(soapconn->session->userlist != NULL, TRUE); + g_return_if_fail(data != NULL); + + userlist = state->session->userlist; - userlist = soapconn->session->userlist; + if (resp != NULL) { + if (msn_userlist_add_buddy_to_group(userlist, state->who, + state->new_group_name)) { + purple_debug_info("MSNCL", "Contact %s added to group %s successfully!\n", state->who, state->new_group_name); + } else { + purple_debug_info("MSNCL","Contact %s added to group %s successfully on server, but failed in the local list\n", state->who, state->new_group_name); + } - state = (MsnCallbackState *) soapconn->data_cb; + if (state->action & MSN_ADD_BUDDY) { + MsnUser *user = msn_userlist_find_user(userlist, state->who); - if (soapconn->body == NULL) { - msn_callback_state_free(state); - return TRUE; - } - - if (msn_userlist_add_buddy_to_group(userlist, state->who, state->new_group_name) == TRUE) { - purple_debug_info("MSNCL", "Contact %s added to group %s successfully!\n", state->who, state->new_group_name); - } else { - purple_debug_info("MSNCL","Contact %s added to group %s successfully on server, but failed in the local list\n", state->who, state->new_group_name); + if ( !msn_user_is_yahoo(state->session->account, state->who) ) { + + msn_userlist_add_buddy_to_list(userlist, state->who, MSN_LIST_AL); + msn_userlist_add_buddy_to_list(userlist, state->who, MSN_LIST_FL); + } + msn_notification_send_fqy(state->session, state->who); + + if (msn_userlist_user_is_in_list(user, MSN_LIST_PL)) { + msn_del_contact_from_list(state->session->contact, NULL, state->who, MSN_LIST_PL); + msn_callback_state_free(state); + return; + } + } + + if (state->action & MSN_MOVE_BUDDY) { + msn_del_contact_from_group(state->session->contact, state->who, state->old_group_name); + } } - if (state->action & MSN_ADD_BUDDY) { - - if ( !msn_user_is_yahoo(soapconn->session->account, state->who) ) { - - msn_userlist_add_buddy_to_list(userlist, state->who, MSN_LIST_AL); - msn_userlist_add_buddy_to_list(userlist, state->who, MSN_LIST_FL); - } - msn_notification_send_fqy(soapconn->session, state->who); - } - - if (state->action & MSN_MOVE_BUDDY) { - msn_del_contact_from_group(soapconn->session->contact, state->who, state->old_group_name); - } else { - msn_callback_state_free(state); - msn_soap_free_read_buf(soapconn); - } - return TRUE; -} - -static void -msn_add_contact_to_group_written_cb(MsnSoapConn *soapconn) -{ - purple_debug_info("MSNCL","Add contact to group request sent!\n"); - soapconn->read_cb = msn_add_contact_to_group_read_cb; + msn_callback_state_free(state); } void msn_add_contact_to_group(MsnContact *contact, MsnCallbackState *state, const char *passport, const char *groupId) { - MsnSoapReq *soap_request; MsnUserList *userlist; MsnUser *user; gchar *body = NULL, *contact_xml; @@ -1168,13 +886,14 @@ return; } - purple_debug_info("MSNCL", "Adding user %s to group %s\n", passport, msn_userlist_find_group_name(userlist, groupId)); user = msn_userlist_find_user(userlist, passport); if (user == NULL) { - purple_debug_warning("MSN CL", "Unable to retrieve user %s from the userlist!\n", passport); + purple_debug_warning("MSNCL", "Unable to retrieve user %s from the userlist!\n", passport); + msn_callback_state_free(state); + return; /* guess this never happened! */ } if (user != NULL && user->uid != NULL) { @@ -1184,60 +903,35 @@ } body = g_strdup_printf(MSN_ADD_CONTACT_GROUP_TEMPLATE, groupId, contact_xml); - g_free(contact_xml); - - /*build SOAP and POST it*/ - soap_request = msn_soap_request_new(MSN_CONTACT_SERVER, - MSN_ADDRESS_BOOK_POST_URL, - MSN_ADD_CONTACT_GROUP_SOAP_ACTION, - body, - state, - msn_add_contact_to_group_read_cb, - msn_add_contact_to_group_written_cb, - msn_contact_connect_init); - msn_soap_post(contact->soapconn,soap_request); + msn_soap_message_send(state->session, + msn_soap_message_new(MSN_ADD_CONTACT_GROUP_SOAP_ACTION, + xmlnode_from_str(body, -1)), + MSN_CONTACT_SERVER, MSN_ADDRESS_BOOK_POST_URL, + msn_add_contact_to_group_read_cb, state); + g_free(contact_xml); g_free(body); } - - -static gboolean -msn_delete_contact_read_cb(MsnSoapConn *soapconn) +static void +msn_delete_contact_read_cb(MsnSoapMessage *req, MsnSoapMessage *resp, + gpointer data) { - MsnUser *user; - MsnCallbackState *state = (MsnCallbackState *) soapconn->data_cb; - MsnUserList *userlist; - - g_return_val_if_fail(soapconn->session != NULL, FALSE); - g_return_val_if_fail(soapconn->session->userlist != NULL, TRUE); + MsnCallbackState *state = data; - userlist = soapconn->session->userlist; + if (resp != NULL) { + MsnUserList *userlist = state->session->userlist; + MsnUser *user = msn_userlist_find_user_with_id(userlist, state->uid); - if (soapconn->body == NULL) { - msn_callback_state_free(state); - return TRUE; - } + purple_debug_info("MSNCL","Delete contact successful\n"); - purple_debug_info("MSNCL","Delete contact successful\n"); - - user = msn_userlist_find_user_with_id(userlist, state->uid); - if (user != NULL) { - msn_userlist_remove_user(userlist, user); + if (user != NULL) { + msn_userlist_remove_user(userlist, user); + } } msn_callback_state_free(state); - msn_soap_free_read_buf(soapconn); - - return TRUE; -} - -static void -msn_delete_contact_written_cb(MsnSoapConn *soapconn) -{ - purple_debug_info("MSNCL","Delete contact request written\n"); - soapconn->read_cb = msn_delete_contact_read_cb; } /*delete a Contact*/ @@ -1246,72 +940,52 @@ { gchar *body = NULL; gchar *contact_id_xml = NULL ; - MsnSoapReq *soap_request; MsnCallbackState *state; g_return_if_fail(contactId != NULL); contact_id_xml = g_strdup_printf(MSN_CONTACT_ID_XML, contactId); - state = msn_callback_state_new(); + state = msn_callback_state_new(contact->session); msn_callback_state_set_uid(state, contactId); /* build SOAP request */ purple_debug_info("MSNCL","Deleting contact with contactId: %s\n", contactId); body = g_strdup_printf(MSN_DEL_CONTACT_TEMPLATE, contact_id_xml); - soap_request = msn_soap_request_new(MSN_CONTACT_SERVER, - MSN_ADDRESS_BOOK_POST_URL, - MSN_CONTACT_DEL_SOAP_ACTION, - body, - state, - msn_delete_contact_read_cb, - msn_delete_contact_written_cb, - msn_contact_connect_init); + msn_soap_message_send(contact->session, + msn_soap_message_new(MSN_CONTACT_DEL_SOAP_ACTION, + xmlnode_from_str(body, -1)), + MSN_CONTACT_SERVER, MSN_ADDRESS_BOOK_POST_URL, + msn_delete_contact_read_cb, state); g_free(contact_id_xml); - - /* POST the SOAP request */ - msn_soap_post(contact->soapconn, soap_request); - g_free(body); } -static gboolean -msn_del_contact_from_group_read_cb(MsnSoapConn *soapconn) +static void +msn_del_contact_from_group_read_cb(MsnSoapMessage *req, MsnSoapMessage *resp, + gpointer data) { - MsnCallbackState *state = (MsnCallbackState *) soapconn->data_cb; + MsnCallbackState *state = data; - if (soapconn->body == NULL) { - msn_callback_state_free(state); - return TRUE; - } - - if (msn_userlist_rem_buddy_from_group(soapconn->session->userlist, state->who, state->old_group_name)) { - purple_debug_info("MSN CL", "Contact %s deleted successfully from group %s\n", state->who, state->old_group_name); - } else { - purple_debug_info("MSN CL", "Contact %s deleted successfully from group %s in the server, but failed in the local list\n", state->who, state->old_group_name); + if (resp != NULL) { + if (msn_userlist_rem_buddy_from_group(state->session->userlist, + state->who, state->old_group_name)) { + purple_debug_info("MSNCL", "Contact %s deleted successfully from group %s\n", state->who, state->old_group_name); + } else { + purple_debug_info("MSNCL", "Contact %s deleted successfully from group %s in the server, but failed in the local list\n", state->who, state->old_group_name); + } } msn_callback_state_free(state); - msn_soap_free_read_buf(soapconn); - - return TRUE; -} - -static void -msn_del_contact_from_group_written_cb(MsnSoapConn *soapconn) -{ - purple_debug_info("MSN CL","Del contact from group request sent!\n"); - soapconn->read_cb = msn_del_contact_from_group_read_cb; } void msn_del_contact_from_group(MsnContact *contact, const char *passport, const char *group_name) { - MsnSoapReq *soap_request; MsnUserList * userlist; MsnUser *user; MsnCallbackState *state; - gchar *body = NULL, *contact_id_xml; + gchar *body, *contact_id_xml; const gchar *groupId; g_return_if_fail(passport != NULL); @@ -1324,16 +998,16 @@ groupId = msn_userlist_find_group_id(userlist, group_name); if (groupId != NULL) { - purple_debug_info("MSN CL", "Deleting user %s from group %s\n", passport, group_name); + purple_debug_info("MSNCL", "Deleting user %s from group %s\n", passport, group_name); } else { - purple_debug_warning("MSN CL", "Unable to retrieve group id from group %s !\n", group_name); + purple_debug_warning("MSNCL", "Unable to retrieve group id from group %s !\n", group_name); return; } user = msn_userlist_find_user(userlist, passport); if (user == NULL) { - purple_debug_warning("MSN CL", "Unable to retrieve user from passport %s!\n", passport); + purple_debug_warning("MSNCL", "Unable to retrieve user from passport %s!\n", passport); return; } @@ -1342,58 +1016,40 @@ return; } - state = msn_callback_state_new(); + state = msn_callback_state_new(contact->session); msn_callback_state_set_who(state, passport); msn_callback_state_set_guid(state, groupId); msn_callback_state_set_old_group_name(state, group_name); contact_id_xml = g_strdup_printf(MSN_CONTACT_ID_XML, user->uid); body = g_strdup_printf(MSN_CONTACT_DEL_GROUP_TEMPLATE, contact_id_xml, groupId); + + msn_soap_message_send(contact->session, + msn_soap_message_new(MSN_CONTACT_DEL_GROUP_SOAP_ACTION, + xmlnode_from_str(body, -1)), + MSN_CONTACT_SERVER, MSN_ADDRESS_BOOK_POST_URL, + msn_del_contact_from_group_read_cb, state); + g_free(contact_id_xml); - - /*build SOAP and POST it*/ - soap_request = msn_soap_request_new(MSN_CONTACT_SERVER, - MSN_ADDRESS_BOOK_POST_URL, - MSN_CONTACT_DEL_GROUP_SOAP_ACTION, - body, - state, - msn_del_contact_from_group_read_cb, - msn_del_contact_from_group_written_cb, - msn_contact_connect_init); - msn_soap_post(contact->soapconn,soap_request); - g_free(body); } -static gboolean -msn_update_contact_read_cb(MsnSoapConn *soapconn) +static void +msn_update_contact_read_cb(MsnSoapMessage *req, MsnSoapMessage *resp, + gpointer data) { - if (soapconn->body == NULL) - return TRUE; - - purple_debug_info("MSN CL","Contact updated successfully\n"); - - return TRUE; -} - -static void -msn_update_contact_written_cb(MsnSoapConn *soapconn) -{ - purple_debug_info("MSN CL","Update contact information request sent\n"); - soapconn->read_cb = msn_update_contact_read_cb; + if (resp) + purple_debug_info("MSN CL","Contact updated successfully\n"); + else + purple_debug_info("MSN CL","Contact updated successfully\n"); } /* Update a contact's nickname */ - void msn_update_contact(MsnContact *contact, const char* nickname) { - MsnSoapReq *soap_request; - gchar *body, *escaped_nickname; - - /* I'm not sure this is right, but if it isn't, the rest of this function will need to be fixed */ - g_return_if_fail(nickname != NULL); + gchar *body = NULL, *escaped_nickname; purple_debug_info("MSN CL","Update contact information with new friendly name: %s\n", nickname); @@ -1401,83 +1057,50 @@ body = g_strdup_printf(MSN_CONTACT_UPDATE_TEMPLATE, escaped_nickname); + msn_soap_message_send(contact->session, + msn_soap_message_new(MSN_CONTACT_UPDATE_SOAP_ACTION, + xmlnode_from_str(body, -1)), + MSN_CONTACT_SERVER, MSN_ADDRESS_BOOK_POST_URL, + msn_update_contact_read_cb, NULL); + g_free(escaped_nickname); - /*build SOAP and POST it*/ - soap_request = msn_soap_request_new(MSN_CONTACT_SERVER, - MSN_ADDRESS_BOOK_POST_URL, - MSN_CONTACT_UPDATE_SOAP_ACTION, - body, - NULL, - msn_update_contact_read_cb, - msn_update_contact_written_cb, - msn_contact_connect_init); - msn_soap_post(contact->soapconn, soap_request); - g_free(body); } - -static gboolean -msn_del_contact_from_list_read_cb(MsnSoapConn *soapconn) +static void +msn_del_contact_from_list_read_cb(MsnSoapMessage *req, MsnSoapMessage *resp, + gpointer data) { - MsnCallbackState *state = NULL; + MsnCallbackState *state = data; + MsnSession *session = state->session; - g_return_val_if_fail(soapconn->data_cb != NULL, TRUE); - g_return_val_if_fail(soapconn->session != NULL, FALSE); - g_return_val_if_fail(soapconn->session->contact != NULL, FALSE); - g_return_val_if_fail(soapconn->session->userlist != NULL, FALSE); - - state = (MsnCallbackState *) soapconn->data_cb; + if (resp != NULL) { + purple_debug_info("MSN CL", "Contact %s deleted successfully from %s list on server!\n", state->who, MsnMemberRole[state->list_id]); - if (soapconn->body == NULL) { - msn_callback_state_free(state); - return TRUE; - } - - purple_debug_info("MSN CL", "Contact %s deleted successfully from %s list on server!\n", state->who, MsnMemberRole[state->list_id]); + if (state->list_id == MSN_LIST_PL) { + MsnUser *user = msn_userlist_find_user(session->userlist, state->who); - if (state->list_id == MSN_LIST_PL) { - MsnUser *user = msn_userlist_find_user(soapconn->session->userlist, state->who); - - if (user != NULL) - msn_user_unset_op(user, MSN_LIST_PL_OP); - - msn_add_contact_to_list(soapconn->session->contact, state, state->who, MSN_LIST_RL); - return TRUE; - } + if (user != NULL) + msn_user_unset_op(user, MSN_LIST_PL_OP); - if (state->list_id == MSN_LIST_AL) { - purple_privacy_permit_remove(soapconn->session->account, state->who, TRUE); - msn_add_contact_to_list(soapconn->session->contact, NULL, state->who, MSN_LIST_BL); - msn_callback_state_free(state); - return TRUE; - } - - if (state->list_id == MSN_LIST_BL) { - purple_privacy_deny_remove(soapconn->session->account, state->who, TRUE); - msn_add_contact_to_list(soapconn->session->contact, NULL, state->who, MSN_LIST_AL); - msn_callback_state_free(state); - return TRUE; + msn_add_contact_to_list(session->contact, state, state->who, MSN_LIST_RL); + return; + } else if (state->list_id == MSN_LIST_AL) { + purple_privacy_permit_remove(session->account, state->who, TRUE); + msn_add_contact_to_list(session->contact, NULL, state->who, MSN_LIST_BL); + } else if (state->list_id == MSN_LIST_BL) { + purple_privacy_deny_remove(session->account, state->who, TRUE); + msn_add_contact_to_list(session->contact, NULL, state->who, MSN_LIST_AL); + } } msn_callback_state_free(state); - msn_soap_free_read_buf(soapconn); - - return TRUE; -} - -static void -msn_del_contact_from_list_written_cb(MsnSoapConn *soapconn) -{ - purple_debug_info("MSN CL","Delete contact from list SOAP request sent!\n"); - soapconn->read_cb = msn_del_contact_from_list_read_cb; } void msn_del_contact_from_list(MsnContact *contact, MsnCallbackState *state, const gchar *passport, const MsnListId list) { - MsnSoapReq *soap_request; gchar *body = NULL, *member = NULL; MsnSoapPartnerScenario partner_scenario; MsnUser *user; @@ -1489,7 +1112,7 @@ purple_debug_info("MSN CL", "Deleting contact %s from %s list\n", passport, MsnMemberRole[list]); if (state == NULL) { - state = msn_callback_state_new(); + state = msn_callback_state_new(contact->session); } msn_callback_state_set_list_id(state, list); msn_callback_state_set_who(state, passport); @@ -1513,79 +1136,55 @@ MsnSoapPartnerScenarioText[partner_scenario], MsnMemberRole[list], member); - g_free(member); - soap_request = msn_soap_request_new( MSN_CONTACT_SERVER, - MSN_SHARE_POST_URL, - MSN_DELETE_MEMBER_FROM_LIST_SOAP_ACTION, - body, - state, - msn_del_contact_from_list_read_cb, - msn_del_contact_from_list_written_cb, - msn_contact_connect_init); + msn_soap_message_send(contact->session, + msn_soap_message_new(MSN_DELETE_MEMBER_FROM_LIST_SOAP_ACTION, + xmlnode_from_str(body, -1)), + MSN_CONTACT_SERVER, MSN_SHARE_POST_URL, + msn_del_contact_from_list_read_cb, state); - msn_soap_post(contact->soapconn,soap_request); - + g_free(member); g_free(body); } -static gboolean -msn_add_contact_to_list_read_cb(MsnSoapConn *soapconn) +static void +msn_add_contact_to_list_read_cb(MsnSoapMessage *req, MsnSoapMessage *resp, + gpointer data) { - MsnCallbackState *state = NULL; + MsnCallbackState *state = data; - g_return_val_if_fail(soapconn->data_cb != NULL, TRUE); - g_return_val_if_fail(soapconn->session != NULL, FALSE); - g_return_val_if_fail(soapconn->session->userlist != NULL, FALSE); - - state = (MsnCallbackState *) soapconn->data_cb; + g_return_if_fail(state != NULL); + g_return_if_fail(state->session != NULL); + g_return_if_fail(state->session->contact != NULL); - if (soapconn->body == NULL) { - msn_callback_state_free(state); - return TRUE; - } - - purple_debug_info("MSN CL", "Contact %s added successfully to %s list on server!\n", state->who, MsnMemberRole[state->list_id]); + if (resp != NULL) { + purple_debug_info("MSN CL", "Contact %s added successfully to %s list on server!\n", state->who, MsnMemberRole[state->list_id]); - if (state->list_id == MSN_LIST_RL) { - MsnUser *user = msn_userlist_find_user(soapconn->session->userlist, state->who); + if (state->list_id == MSN_LIST_RL) { + MsnUser *user = msn_userlist_find_user(state->session->userlist, state->who); - if (user != NULL) { - msn_user_set_op(user, MSN_LIST_RL_OP); - } + if (user != NULL) { + msn_user_set_op(user, MSN_LIST_RL_OP); + } + + if (state->action & MSN_DENIED_BUDDY) { - if (state->action & MSN_DENIED_BUDDY) { - g_return_val_if_fail(soapconn->session->contact != NULL, FALSE); - - msn_add_contact_to_list(soapconn->session->contact, NULL, state->who, MSN_LIST_BL); - return TRUE; + msn_add_contact_to_list(state->session->contact, NULL, state->who, MSN_LIST_BL); + } else if (state->list_id == MSN_LIST_AL) { + purple_privacy_permit_add(state->session->account, state->who, TRUE); + } else if (state->list_id == MSN_LIST_BL) { + purple_privacy_deny_add(state->session->account, state->who, TRUE); + } } } - if (state->list_id == MSN_LIST_AL) { - purple_privacy_permit_add(soapconn->session->account, state->who, TRUE); - } else if (state->list_id == MSN_LIST_BL) { - purple_privacy_deny_add(soapconn->session->account, state->who, TRUE); - } - msn_callback_state_free(state); - msn_soap_free_read_buf(soapconn); - return TRUE; -} - - -static void -msn_add_contact_to_list_written_cb(MsnSoapConn *soapconn) -{ - purple_debug_info("MSN CL","Add contact to list SOAP request sent!\n"); - soapconn->read_cb = msn_add_contact_to_list_read_cb; } void msn_add_contact_to_list(MsnContact *contact, MsnCallbackState *state, const gchar *passport, const MsnListId list) { - MsnSoapReq *soap_request; gchar *body = NULL, *member = NULL; MsnSoapPartnerScenario partner_scenario; @@ -1596,51 +1195,38 @@ purple_debug_info("MSN CL", "Adding contact %s to %s list\n", passport, MsnMemberRole[list]); if (state == NULL) { - state = msn_callback_state_new(); + state = msn_callback_state_new(contact->session); } msn_callback_state_set_list_id(state, list); msn_callback_state_set_who(state, passport); partner_scenario = (list == MSN_LIST_RL) ? MSN_PS_CONTACT_API : MSN_PS_BLOCK_UNBLOCK; - member = g_strdup_printf(MSN_MEMBER_PASSPORT_XML, passport); + member = g_strdup_printf(MSN_MEMBER_PASSPORT_XML, state->who); body = g_strdup_printf(MSN_CONTACT_ADD_TO_LIST_TEMPLATE, MsnSoapPartnerScenarioText[partner_scenario], MsnMemberRole[list], member); - g_free(member); + msn_soap_message_send(contact->session, + msn_soap_message_new(MSN_ADD_MEMBER_TO_LIST_SOAP_ACTION, + xmlnode_from_str(body, -1)), + MSN_CONTACT_SERVER, MSN_SHARE_POST_URL, + msn_add_contact_to_list_read_cb, state); - soap_request = msn_soap_request_new( MSN_CONTACT_SERVER, - MSN_SHARE_POST_URL, - MSN_ADD_MEMBER_TO_LIST_SOAP_ACTION, - body, - state, - msn_add_contact_to_list_read_cb, - msn_add_contact_to_list_written_cb, - msn_contact_connect_init); - - msn_soap_post(contact->soapconn, soap_request); - + g_free(member); g_free(body); } - #if 0 -static gboolean -msn_gleams_read_cb(MsnSoapConn * soapconn) +static void +msn_gleams_read_cb(MsnSoapMessage *req, MsnSoapMessage *resp, gpointer data) { - purple_debug_info("MSN CL","Gleams read done\n"); - return TRUE; -} - -static void -msn_gleams_written_cb(MsnSoapConn * soapconn) -{ - purple_debug_info("MSNP14","finish Group written\n"); - soapconn->read_cb = msn_gleams_read_cb; -// msn_soap_read_cb(data,source,cond); + if (resp != NULL) + purple_debug_info("MSNP14","Gleams read done\n"); + else + purple_debug_info("MSNP14","Gleams read failed\n"); } /*get the gleams info*/ @@ -1650,16 +1236,11 @@ MsnSoapReq *soap_request; purple_debug_info("MSNP14","msn get gleams info...\n"); - /*build SOAP and POST it*/ - soap_request = msn_soap_request_new(MSN_CONTACT_SERVER, - MSN_ADDRESS_BOOK_POST_URL, - MSN_GET_GLEAMS_SOAP_ACTION, - MSN_GLEAMS_TEMPLATE, - NULL, - msn_gleams_read_cb, - msn_gleams_written_cb, - msn_contact_connect_init); - msn_soap_post(contact->soapconn,soap_request); + msn_soap_message_send(contact->session, + msn_soap_message_new(MSN_GET_GLEAMS_SOAP_ACTION, + xmlnode_from_str(MSN_GLEAMS_TEMPLATE, -1)), + MSN_CONTACT_SERVER, MSN_ADDRESS_BOOK_POST_URL, + msn_gleams_read_cb, NULL); } #endif @@ -1668,100 +1249,88 @@ * Group Operations ***************************************************************/ -static gboolean -msn_group_read_cb(MsnSoapConn *soapconn) +static void +msn_group_read_cb(MsnSoapMessage *req, MsnSoapMessage *resp, gpointer data) { - MsnUserList *userlist; - MsnCallbackState *state = NULL; + MsnCallbackState *state = data; - purple_debug_info("MSN CL", "Group request successful.\n"); + purple_debug_info("MSNCL", "Group request successful.\n"); - g_return_val_if_fail(soapconn->session != NULL, FALSE); - g_return_val_if_fail(soapconn->session->userlist != NULL, TRUE); - g_return_val_if_fail(soapconn->session->contact != NULL, FALSE); + g_return_if_fail(state->session != NULL); + g_return_if_fail(state->session->userlist != NULL); + g_return_if_fail(state->session->contact != NULL); - state = (MsnCallbackState *) soapconn->data_cb; - - if (soapconn->body == NULL) { + if (resp == NULL) { msn_callback_state_free(state); - return TRUE; + return; } - + if (state) { - userlist = soapconn->session->userlist; + MsnSession *session = state->session; + MsnUserList *userlist = session->userlist; if (state->action & MSN_RENAME_GROUP) { - msn_userlist_rename_group_id(soapconn->session->userlist, + msn_userlist_rename_group_id(session->userlist, state->guid, state->new_group_name); } if (state->action & MSN_ADD_GROUP) { - gchar *guid, *endguid; - - guid = g_strstr_len(soapconn->read_buf, soapconn->read_len, "<guid>"); - guid += 6; - endguid = g_strstr_len(soapconn->read_buf, soapconn->read_len, "</guid>"); - *endguid = '\0'; - /* create and add the new group to the userlist */ - purple_debug_info("MSN CL", "Adding group %s with guid = %s to the userlist\n", state->new_group_name, guid); - msn_group_new(soapconn->session->userlist, guid, state->new_group_name); + /* the response is taken from + http://telepathy.freedesktop.org/wiki/Pymsn/MSNP/ContactListActions + should copy it to msnpiki some day */ + xmlnode *guid_node = msn_soap_xml_get(resp->xml, + "Body/ABGroupAddResponse/ABGroupAddResult/guid"); + + if (guid_node) { + char *guid = xmlnode_get_data(guid_node); + + /* create and add the new group to the userlist */ + purple_debug_info("MSNCL", "Adding group %s with guid = %s to the userlist\n", state->new_group_name, guid); + msn_group_new(session->userlist, guid, state->new_group_name); - if (state->action & MSN_ADD_BUDDY) { - msn_userlist_add_buddy(soapconn->session->userlist, - state->who, - state->new_group_name); - msn_callback_state_free(state); - return TRUE; - } - - if (state->action & MSN_MOVE_BUDDY) { - msn_add_contact_to_group(soapconn->session->contact, state, state->who, guid); - return TRUE; + g_free(guid); + + if (state->action & MSN_ADD_BUDDY) { + msn_userlist_add_buddy(session->userlist, + state->who, + state->new_group_name); + } else if (state->action & MSN_MOVE_BUDDY) { + msn_add_contact_to_group(session->contact, state, state->who, guid); + return; + } + } else { + purple_debug_info("MSNCL", "Adding group %s failed\n", + state->new_group_name); } } if (state->action & MSN_DEL_GROUP) { GList *l; - msn_userlist_remove_group_id(soapconn->session->userlist, state->guid); + msn_userlist_remove_group_id(session->userlist, state->guid); for (l = userlist->users; l != NULL; l = l->next) { msn_user_remove_group_id( (MsnUser *)l->data, state->guid); } - } msn_callback_state_free(state); } - - msn_soap_free_read_buf(soapconn); - return TRUE; -} - -static void -msn_group_written_cb(MsnSoapConn *soapconn) -{ - purple_debug_info("MSN CL","Sent group request.\n"); - soapconn->read_cb = msn_group_read_cb; } /* add group */ void msn_add_group(MsnSession *session, MsnCallbackState *state, const char* group_name) { - MsnSoapReq *soap_request; - MsnContact *contact; char *body = NULL; - gchar *escaped_group_name; g_return_if_fail(session != NULL); g_return_if_fail(group_name != NULL); - contact = session->contact; - purple_debug_info("MSN CL","Adding group %s to contact list.\n", group_name); + purple_debug_info("MSNCL","Adding group %s to contact list.\n", group_name); if (state == NULL) { - state = msn_callback_state_new(); + state = msn_callback_state_new(session); } msn_callback_state_set_action(state, MSN_ADD_GROUP); @@ -1770,21 +1339,14 @@ /* escape group name's html special chars so it can safely be sent * in a XML SOAP request */ - escaped_group_name = g_markup_escape_text(group_name, -1); - body = g_strdup_printf(MSN_GROUP_ADD_TEMPLATE, escaped_group_name); - g_free(escaped_group_name); + body = g_markup_printf_escaped(MSN_GROUP_ADD_TEMPLATE, group_name); - /*build SOAP and POST it*/ - soap_request = msn_soap_request_new(MSN_CONTACT_SERVER, - MSN_ADDRESS_BOOK_POST_URL, - MSN_GROUP_ADD_SOAP_ACTION, - body, - state, - msn_group_read_cb, - msn_group_written_cb, - msn_contact_connect_init); - msn_soap_post(contact->soapconn,soap_request); - + msn_soap_message_send(session, + msn_soap_message_new(MSN_GROUP_ADD_SOAP_ACTION, + xmlnode_from_str(body, -1)), + MSN_CONTACT_SERVER, MSN_ADDRESS_BOOK_POST_URL, + msn_group_read_cb, state); + g_free(body); } @@ -1792,8 +1354,6 @@ void msn_del_group(MsnSession *session, const gchar *group_name) { - MsnSoapReq *soap_request; - MsnContact *contact; MsnCallbackState *state; char *body = NULL; const gchar *guid; @@ -1801,8 +1361,7 @@ g_return_if_fail(session != NULL); g_return_if_fail(group_name != NULL); - contact = session->contact; - purple_debug_info("MSN CL","Deleting group %s from contact list\n", group_name); + purple_debug_info("MSNCL","Deleting group %s from contact list\n", group_name); guid = msn_userlist_find_group_id(session->userlist, group_name); @@ -1810,7 +1369,7 @@ * we need to delete nothing */ if (guid == NULL) { - purple_debug_info("MSN CL", "Group %s guid not found, returning.\n", group_name); + purple_debug_info("MSNCL", "Group %s guid not found, returning.\n", group_name); return; } @@ -1819,21 +1378,17 @@ return; } - state = msn_callback_state_new(); + state = msn_callback_state_new(session); msn_callback_state_set_action(state, MSN_DEL_GROUP); msn_callback_state_set_guid(state, guid); body = g_strdup_printf(MSN_GROUP_DEL_TEMPLATE, guid); - /*build SOAP and POST it*/ - soap_request = msn_soap_request_new(MSN_CONTACT_SERVER, - MSN_ADDRESS_BOOK_POST_URL, - MSN_GROUP_DEL_SOAP_ACTION, - body, - state, - msn_group_read_cb, - msn_group_written_cb, - msn_contact_connect_init); - msn_soap_post(contact->soapconn, soap_request); + + msn_soap_message_send(session, + msn_soap_message_new(MSN_GROUP_DEL_SOAP_ACTION, + xmlnode_from_str(body, -1)), + MSN_CONTACT_SERVER, MSN_ADDRESS_BOOK_POST_URL, + msn_group_read_cb, state); g_free(body); } @@ -1842,24 +1397,22 @@ void msn_contact_rename_group(MsnSession *session, const char *old_group_name, const char *new_group_name) { - MsnSoapReq *soap_request; - MsnContact *contact; - gchar * escaped_group_name, *body = NULL; + gchar *body = NULL; const gchar * guid; - MsnCallbackState *state = msn_callback_state_new(); + MsnCallbackState *state; g_return_if_fail(session != NULL); g_return_if_fail(session->userlist != NULL); g_return_if_fail(old_group_name != NULL); g_return_if_fail(new_group_name != NULL); - contact = session->contact; purple_debug_info("MSN CL", "Renaming group %s to %s.\n", old_group_name, new_group_name); guid = msn_userlist_find_group_id(session->userlist, old_group_name); if (guid == NULL) return; + state = msn_callback_state_new(session); msn_callback_state_set_guid(state, guid); msn_callback_state_set_new_group_name(state, new_group_name); @@ -1870,31 +1423,14 @@ msn_callback_state_set_action(state, MSN_RENAME_GROUP); - /* escape group name's html special chars so it can safely be sent - * in a XML SOAP request - */ - escaped_group_name = g_markup_escape_text(new_group_name, -1); - - body = g_strdup_printf(MSN_GROUP_RENAME_TEMPLATE, guid, escaped_group_name); + body = g_markup_printf_escaped(MSN_GROUP_RENAME_TEMPLATE, + guid, new_group_name); - soap_request = msn_soap_request_new(MSN_CONTACT_SERVER, - MSN_ADDRESS_BOOK_POST_URL, - MSN_GROUP_RENAME_SOAP_ACTION, - body, - state, - msn_group_read_cb, - msn_group_written_cb, - msn_contact_connect_init); - msn_soap_post(contact->soapconn, soap_request); - - g_free(escaped_group_name); + msn_soap_message_send(session, + msn_soap_message_new(MSN_GROUP_RENAME_SOAP_ACTION, + xmlnode_from_str(body, -1)), + MSN_CONTACT_SERVER, MSN_ADDRESS_BOOK_POST_URL, + msn_group_read_cb, state); + g_free(body); } - -void -msn_contact_connect_init(MsnSoapConn *soapconn) -{ - msn_soap_init(soapconn, MSN_CONTACT_SERVER, TRUE, - msn_contact_login_connect_cb, - msn_contact_login_error_cb); -}
--- a/libpurple/protocols/msn/contact.h Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/protocols/msn/contact.h Sat Nov 10 04:52:20 2007 +0000 @@ -380,6 +380,7 @@ gchar * guid; MsnListId list_id; MsnCallbackAction action; + MsnSession *session; }; typedef enum @@ -397,7 +398,7 @@ MsnContact * msn_contact_new(MsnSession *session); void msn_contact_destroy(MsnContact *contact); -MsnCallbackState * msn_callback_state_new(void); +MsnCallbackState * msn_callback_state_new(MsnSession *session); void msn_callback_state_free(MsnCallbackState *state); void msn_callback_state_set_who(MsnCallbackState *state, const gchar *who); void msn_callback_state_set_uid(MsnCallbackState *state, const gchar *uid);
--- a/libpurple/protocols/msn/directconn.c Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/protocols/msn/directconn.c Sat Nov 10 04:52:20 2007 +0000 @@ -80,6 +80,7 @@ create_listener(int port) { int fd; + int flags; const int on = 1; #if 0 @@ -155,7 +156,8 @@ return -1; } - fcntl(fd, F_SETFL, O_NONBLOCK); + flags = fcntl(fd, F_GETFL); + fcntl(fd, F_SETFL, flags | O_NONBLOCK); return fd; }
--- a/libpurple/protocols/msn/group.c Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/protocols/msn/group.c Sat Nov 10 04:52:20 2007 +0000 @@ -58,6 +58,7 @@ g_return_if_fail(group != NULL); g_return_if_fail(id != NULL); + g_free(group->id); group->id = g_strdup(id); } @@ -67,9 +68,7 @@ g_return_if_fail(group != NULL); g_return_if_fail(name != NULL); - if (group->name != NULL) - g_free(group->name); - + g_free(group->name); group->name = g_strdup(name); }
--- a/libpurple/protocols/msn/httpconn.c Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/protocols/msn/httpconn.c Sat Nov 10 04:52:20 2007 +0000 @@ -169,7 +169,7 @@ /* Now we should be able to process the data. */ if ((s = purple_strcasestr(header, "X-MSN-Messenger: ")) != NULL) { - char *full_session_id, *gw_ip, *session_action; + gchar *full_session_id = NULL, *gw_ip = NULL, *session_action = NULL; char *t, *session_id; char **elems, **cur, **tokens; @@ -196,13 +196,16 @@ { tokens = g_strsplit(*cur, "=", 2); - if (strcmp(tokens[0], "SessionID") == 0) + if (strcmp(tokens[0], "SessionID") == 0) { + g_free(full_session_id); full_session_id = tokens[1]; - else if (strcmp(tokens[0], "GW-IP") == 0) + } else if (strcmp(tokens[0], "GW-IP") == 0) { + g_free(gw_ip); gw_ip = tokens[1]; - else if (strcmp(tokens[0], "Session") == 0) + } else if (strcmp(tokens[0], "Session") == 0) { + g_free(session_action); session_action = tokens[1]; - else + } else g_free(tokens[1]); g_free(tokens[0]); @@ -684,6 +687,17 @@ g_free(httpconn->host); + while (httpconn->queue != NULL) { + MsnHttpQueueData *queue_data; + + queue_data = (MsnHttpQueueData *) httpconn->queue->data; + + httpconn->queue = g_list_delete_link(httpconn->queue, httpconn->queue); + + g_free(queue_data->body); + g_free(queue_data); + } + purple_circ_buffer_destroy(httpconn->tx_buf); if (httpconn->tx_handler > 0) purple_input_remove(httpconn->tx_handler);
--- a/libpurple/protocols/msn/msg.c Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/protocols/msn/msg.c Sat Nov 10 04:52:20 2007 +0000 @@ -60,17 +60,10 @@ purple_debug_info("msn", "message destroy (%p)\n", msg); #endif - if (msg->remote_user != NULL) - g_free(msg->remote_user); - - if (msg->body != NULL) - g_free(msg->body); - - if (msg->content_type != NULL) - g_free(msg->content_type); - - if (msg->charset != NULL) - g_free(msg->charset); + g_free(msg->remote_user); + g_free(msg->body); + g_free(msg->content_type); + g_free(msg->charset); g_hash_table_destroy(msg->attr_table); g_list_free(msg->attr_list); @@ -313,6 +306,7 @@ /* Import the body. */ if (body_len > 0) { msg->body_len = body_len; + g_free(msg->body); msg->body = g_malloc0(msg->body_len + 1); memcpy(msg->body, tmp, msg->body_len); tmp += body_len; @@ -329,6 +323,7 @@ { if (payload_len - (tmp - tmp_base) > 0) { msg->body_len = payload_len - (tmp - tmp_base); + g_free(msg->body); msg->body = g_malloc0(msg->body_len + 1); memcpy(msg->body, tmp, msg->body_len); } @@ -554,10 +549,8 @@ { g_return_if_fail(msg != NULL); - if (msg->content_type != NULL) - g_free(msg->content_type); - - msg->content_type = (type != NULL) ? g_strdup(type) : NULL; + g_free(msg->content_type); + msg->content_type = g_strdup(type); } const char * @@ -573,10 +566,8 @@ { g_return_if_fail(msg != NULL); - if (msg->charset != NULL) - g_free(msg->charset); - - msg->charset = (charset != NULL) ? g_strdup(charset) : NULL; + g_free(msg->charset); + msg->charset = g_strdup(charset); } const char * @@ -664,10 +655,11 @@ tokens = g_strsplit(*cur, ": ", 2); - if (tokens[0] != NULL && tokens[1] != NULL) + if (tokens[0] != NULL && tokens[1] != NULL) { g_hash_table_insert(table, tokens[0], tokens[1]); - - g_free(tokens); + g_free(tokens); + } else + g_strfreev(tokens); } g_strfreev(elems);
--- a/libpurple/protocols/msn/msn.c Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/protocols/msn/msn.c Sat Nov 10 04:52:20 2007 +0000 @@ -254,6 +254,7 @@ trans = msn_transaction_new(cmdproc, "PGD", "%s 1 %d", who, payload_len); msn_transaction_set_payload(trans, payload, payload_len); + g_free(payload); msn_page_destroy(page); @@ -597,14 +598,20 @@ /* We could probably just use user->media.title etc. here */ } - if (!purple_presence_is_available(presence)) { + if (!purple_status_is_available(status)) { name = purple_status_get_name(status); } else { name = NULL; } if (name != NULL && *name) { - char *tmp2 = g_markup_escape_text(name, -1); + char *tmp2; + + if (purple_presence_is_idle(presence)) { + tmp2 = g_markup_printf_escaped("%s/%s", name, _("Idle")); + } else { + tmp2 = g_markup_escape_text(name, -1); + } if (psm != NULL && *psm) { tmp = g_markup_escape_text(psm, -1); @@ -618,8 +625,20 @@ } else { if (psm != NULL && *psm) { tmp = g_markup_escape_text(psm, -1); - purple_notify_user_info_add_pair(user_info, _("Status"), tmp); + if (purple_presence_is_idle(presence)) { + purple_notify_user_info_add_pair(user_info, _("Idle"), tmp); + } else { + purple_notify_user_info_add_pair(user_info, _("Status"), tmp); + } g_free(tmp); + } else { + if (purple_presence_is_idle(presence)) { + purple_notify_user_info_add_pair(user_info, _("Status"), + _("Idle")); + } else { + purple_notify_user_info_add_pair(user_info, _("Status"), + purple_status_get_name(status)); + } } } @@ -635,7 +654,12 @@ * XXX: blocked icon overlay isn't always accurate for MSN. * XXX: This can die as soon as purple_privacy_check() knows that * XXX: this prpl always honors both the allow and deny lists. */ - if (user) + /* While the above comment may be strictly correct (the privacy API needs + * rewriteing), purple_privacy_check() is going to be more accurate at + * indicating whether a particular buddy is going to be able to message + * you, which is the important information that this is trying to convey. + */ + if (full && user) { purple_notify_user_info_add_pair(user_info, _("Blocked"), ((user->list_op & (1 << MSN_LIST_BL)) ? _("Yes") : _("No"))); @@ -971,20 +995,17 @@ }else { /*send Offline Instant Message,only to MSN Passport User*/ MsnSession *session; - MsnOim *oim; char *friendname; purple_debug_info("MSNP14","prepare to send offline Message\n"); session = gc->proto_data; - /* XXX/khc: hack */ - if (!session->oim) - session->oim = msn_oim_new(session); - - oim = session->oim; + friendname = msn_encode_mime(account->username); - msn_oim_prep_send_msg_info(oim, purple_account_get_username(account), - friendname, who, message); - msn_oim_send_msg(oim); + msn_oim_prep_send_msg_info(session->oim, + purple_account_get_username(account), + friendname, who, message); + msn_oim_send_msg(session->oim); + g_free(friendname); } return 1; @@ -1615,7 +1636,6 @@ gboolean sect_info = FALSE; gboolean has_contact_info = FALSE; char *url_buffer; - GString *s, *s2; int stripped_len; #if PHOTO_SUPPORT char *photo_url_text = NULL; @@ -1700,11 +1720,6 @@ purple_debug_misc("msn", "stripped = %p\n", stripped); purple_debug_misc("msn", "url_buffer = %p\n", url_buffer); - /* Gonna re-use the memory we've already got for url_buffer */ - /* No we're not. */ - s = g_string_sized_new(strlen(url_buffer)); - s2 = g_string_sized_new(strlen(url_buffer)); - /* General section header */ if (has_tooltip_text) purple_notify_user_info_add_section_break(user_info); @@ -2009,7 +2024,7 @@ purple_debug_info("MSNP14","photo url:{%s}\n", photo_url_text ? photo_url_text : "(null)"); /* Marshall the existing state */ - info2_data = g_malloc0(sizeof(MsnGetInfoStepTwoData)); + info2_data = g_new0(MsnGetInfoStepTwoData, 1); info2_data->info_data = info_data; info2_data->stripped = stripped; info2_data->url_buffer = url_buffer; @@ -2051,7 +2066,7 @@ purple_debug_warning("msn", "invalid connection. ignoring buddy photo info.\n"); g_free(stripped); g_free(url_buffer); - g_free(user_info); + purple_notify_user_info_destroy(user_info); g_free(info_data->name); g_free(info_data); g_free(photo_url_text); @@ -2285,7 +2300,7 @@ "prpl-msn", /**< id */ "MSN", /**< name */ - VERSION, /**< version */ + DISPLAY_VERSION, /**< version */ /** summary */ N_("Windows Live Messenger Protocol Plugin"), /** description */
--- a/libpurple/protocols/msn/msnutils.c Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/protocols/msn/msnutils.c Sat Nov 10 04:52:20 2007 +0000 @@ -166,10 +166,15 @@ char * msn_encode_mime(const char *str) { - char *base64; + gchar *base64, *retval; + + g_return_val_if_fail(str != NULL, NULL); base64 = purple_base64_encode((guchar *)str, strlen(str)); - return g_strdup_printf("=?utf-8?B?%s?=", base64); + retval = g_strdup_printf("=?utf-8?B?%s?=", base64); + g_free(base64); + + return retval; } /* @@ -445,10 +450,9 @@ *attributes = g_strdup_printf("FN=%s; EF=%s; CO=%s; PF=0; RL=%c", encode_spaces(fontface), fonteffect, fontcolor, direction); - *message = g_strdup(msg); + *message = msg; g_free(fontface); - g_free(msg); } void
--- a/libpurple/protocols/msn/nexus.c Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/protocols/msn/nexus.c Sat Nov 10 04:52:20 2007 +0000 @@ -22,15 +22,12 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ #include "msn.h" -#include "soap.h" +#include "soap2.h" #include "nexus.h" #include "notification.h" #undef NEXUS_LOGIN_TWN -/*Local Function Prototype*/ -static gboolean nexus_login_connect_cb(MsnSoapConn *soapconn, PurpleSslConnection *gsc); - /************************************************************************** * Main **************************************************************************/ @@ -42,8 +39,6 @@ nexus = g_new0(MsnNexus, 1); nexus->session = session; - /*we must use SSL connection to do Windows Live ID authentication*/ - nexus->soapconn = msn_soap_new(session,nexus,1); nexus->challenge_data = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); @@ -57,196 +52,98 @@ if (nexus->challenge_data != NULL) g_hash_table_destroy(nexus->challenge_data); - msn_soap_destroy(nexus->soapconn); g_free(nexus); } -#if 0 /* khc */ -/************************************************************************** - * Util - **************************************************************************/ - -static gssize -msn_ssl_read(MsnNexus *nexus) -{ - gssize len; - char temp_buf[4096]; - - if ((len = purple_ssl_read(nexus->gsc, temp_buf, - sizeof(temp_buf))) > 0) - { - nexus->read_buf = g_realloc(nexus->read_buf, - nexus->read_len + len + 1); - strncpy(nexus->read_buf + nexus->read_len, temp_buf, len); - nexus->read_len += len; - nexus->read_buf[nexus->read_len] = '\0'; - } - - return len; -} - -static void -nexus_write_cb(gpointer data, gint source, PurpleInputCondition cond) -{ - MsnNexus *nexus = data; - int len, total_len; - - total_len = strlen(nexus->write_buf); - - len = purple_ssl_write(nexus->gsc, - nexus->write_buf + nexus->written_len, - total_len - nexus->written_len); - - if (len < 0 && errno == EAGAIN) - return; - else if (len <= 0) { - purple_input_remove(nexus->input_handler); - nexus->input_handler = 0; - /* TODO: notify of the error */ - return; - } - nexus->written_len += len; - - if (nexus->written_len < total_len) - return; - - purple_input_remove(nexus->input_handler); - nexus->input_handler = 0; - - g_free(nexus->write_buf); - nexus->write_buf = NULL; - nexus->written_len = 0; - - nexus->written_cb(nexus, source, 0); -} - -#endif /************************************************************************** * Login **************************************************************************/ + static void -nexus_login_error_cb(MsnSoapConn *soapconn, PurpleSslConnection *gsc, PurpleSslErrorType error) +nexus_got_response_cb(MsnSoapMessage *req, MsnSoapMessage *resp, gpointer data) { - MsnSession *session; + MsnNexus *nexus = data; + MsnSession *session = nexus->session; + xmlnode *node; + + if (resp == NULL) { + msn_session_set_error(session, MSN_ERROR_AUTH, _("Windows Live ID authentication:Unable to connect")); + return; + } + + node = msn_soap_xml_get(resp->xml, "Body/" + "RequestSecurityTokenResponseCollection/RequestSecurityTokenResponse"); + + for (; node; node = node->next) { + xmlnode *token = msn_soap_xml_get(node, + "RequestedSecurityToken/BinarySecurityToken"); + + if (token) { + char *token_str = xmlnode_get_data(token); + char **elems, **cur, **tokens; + char *msn_twn_t, *msn_twn_p, *cert_str; + + if (token_str == NULL) continue; + + elems = g_strsplit(token_str, "&", 0); - session = soapconn->session; - g_return_if_fail(session != NULL); + for (cur = elems; *cur != NULL; cur++){ + tokens = g_strsplit(*cur, "=", 2); + g_hash_table_insert(nexus->challenge_data, tokens[0], tokens[1]); + /* Don't free each of the tokens, only the array. */ + g_free(tokens); + } + + g_free(token_str); + g_strfreev(elems); + + msn_twn_t = g_hash_table_lookup(nexus->challenge_data, "t"); + msn_twn_p = g_hash_table_lookup(nexus->challenge_data, "p"); + + /*setup the t and p parameter for session*/ + if (session->passport_info.t != NULL){ + g_free(session->passport_info.t); + } + session->passport_info.t = g_strdup(msn_twn_t); - soapconn->gsc = NULL; + if (session->passport_info.p != NULL) + g_free(session->passport_info.p); + session->passport_info.p = g_strdup(msn_twn_p); + + cert_str = g_strdup_printf("t=%s&p=%s",msn_twn_t,msn_twn_p); + msn_got_login_params(session, cert_str); - msn_session_set_error(session, MSN_ERROR_AUTH, _("Windows Live ID authentication:Unable to connect")); - /* the above line will result in nexus being destroyed, so we don't want - * to destroy it here, or we'd crash */ + purple_debug_info("MSN Nexus","Close nexus connection!\n"); + g_free(cert_str); + msn_nexus_destroy(nexus); + session->nexus = NULL; + + return; + } + } + + /* we must have failed! */ + msn_session_set_error(session, MSN_ERROR_AUTH, _("Windows Live ID authentication: cannot find authenticate token in server response")); } -/*process the SOAP reply, get the Authentication Info*/ -static gboolean -nexus_login_read_cb(MsnSoapConn *soapconn) +/*when connect, do the SOAP Style windows Live ID authentication */ +void +msn_nexus_connect(MsnNexus *nexus) { - MsnNexus *nexus; - MsnSession *session; - - char *base, *c; - char *msn_twn_t,*msn_twn_p; - char *login_params; - char **elems, **cur, **tokens; - char * cert_str; - - nexus = soapconn->parent; - g_return_val_if_fail(nexus != NULL, TRUE); - session = nexus->session; - g_return_val_if_fail(session != NULL, FALSE); - - /*reply OK, we should process the SOAP body*/ - purple_debug_info("MSN Nexus","TWN Server Windows Live ID Reply OK!\n"); - - //TODO: we should parse it using XML -#ifdef NEXUS_LOGIN_TWN - base = g_strstr_len(soapconn->read_buf, soapconn->read_len, TWN_START_TOKEN); - base += strlen(TWN_START_TOKEN); - c = g_strstr_len(soapconn->read_buf, soapconn->read_len, TWN_END_TOKEN); -#else - base = g_strstr_len(soapconn->read_buf, soapconn->read_len, TWN_LIVE_START_TOKEN); - base += strlen(TWN_LIVE_START_TOKEN); - c = g_strstr_len(soapconn->read_buf, soapconn->read_len, TWN_LIVE_END_TOKEN); -#endif - login_params = g_strndup(base, c - base); - - // purple_debug_info("msn", "TWN Cert: {%s}\n", login_params); - - /* Parse the challenge data. */ - elems = g_strsplit(login_params, "&", 0); - - for (cur = elems; *cur != NULL; cur++){ - tokens = g_strsplit(*cur, "=", 2); - g_hash_table_insert(nexus->challenge_data, tokens[0], tokens[1]); - /* Don't free each of the tokens, only the array. */ - g_free(tokens); - } - - g_strfreev(elems); - - msn_twn_t = (char *)g_hash_table_lookup(nexus->challenge_data, "t"); - msn_twn_p = (char *)g_hash_table_lookup(nexus->challenge_data, "p"); - - /*setup the t and p parameter for session*/ - if (session->passport_info.t != NULL){ - g_free(session->passport_info.t); - } - session->passport_info.t = g_strdup(msn_twn_t); - - if (session->passport_info.p != NULL) - g_free(session->passport_info.p); - session->passport_info.p = g_strdup(msn_twn_p); - - cert_str = g_strdup_printf("t=%s&p=%s",msn_twn_t,msn_twn_p); - msn_got_login_params(session, cert_str); - - purple_debug_info("MSN Nexus","Close nexus connection!\n"); - g_free(cert_str); - g_free(login_params); - msn_nexus_destroy(nexus); - session->nexus = NULL; - - return FALSE; -} - -static void -nexus_login_written_cb(MsnSoapConn *soapconn) -{ - soapconn->read_cb = nexus_login_read_cb; -// msn_soap_read_cb(data,source,cond); -} - - -/*when connect, do the SOAP Style windows Live ID authentication */ -gboolean -nexus_login_connect_cb(MsnSoapConn *soapconn, PurpleSslConnection *gsc) -{ - MsnNexus * nexus; - MsnSession *session; + MsnSession *session = nexus->session; char *ru,*lc,*id,*tw,*ct,*kpp,*kv,*ver,*rn,*tpf; char *fs0,*fs; char *username, *password; - char *request_str, *head, *tail; + char *tail; #ifdef NEXUS_LOGIN_TWN char *challenge_str; #else char *rst1_str,*rst2_str,*rst3_str; #endif - - purple_debug_info("MSN Nexus","Starting Windows Live ID authentication\n"); - - g_return_val_if_fail(soapconn != NULL, FALSE); - nexus = soapconn->parent; - g_return_val_if_fail(nexus != NULL, TRUE); + MsnSoapMessage *soap; - session = soapconn->session; - g_return_val_if_fail(session != NULL, FALSE); - - msn_soap_set_process_step(soapconn, MSN_SOAP_PROCESSING); - + purple_debug_info("MSN Nexus","Starting Windows Live ID authentication\n"); msn_session_set_login_step(session, MSN_LOGIN_STEP_GET_COOKIE); /*prepare the Windows Live ID authentication token*/ @@ -275,10 +172,9 @@ msn_session_set_error(session, MSN_ERROR_AUTH, _("Windows Live ID authentication Failed")); g_free(username); g_free(password); - purple_ssl_close(gsc); msn_nexus_destroy(nexus); session->nexus = NULL; - return FALSE; + return; } /* @@ -298,7 +194,7 @@ ); /*build the SOAP windows Live ID XML body */ - tail = g_strdup_printf(TWN_ENVELOP_TEMPLATE,username,password,challenge_str ); + tail = g_strdup_printf(TWN_ENVELOP_TEMPLATE, username, password, challenge_str); g_free(challenge_str); #else rst1_str = g_strdup_printf( @@ -317,152 +213,9 @@ #endif g_free(fs); - soapconn->login_path = g_strdup(TWN_POST_URL); - head = g_strdup_printf( - "POST %s HTTP/1.1\r\n" - "Accept: text/*\r\n" - "User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)\r\n" - "Host: %s\r\n" - "Content-Length: %" G_GSIZE_FORMAT "\r\n" - "Connection: Keep-Alive\r\n" - "Cache-Control: no-cache\r\n\r\n", - soapconn->login_path, soapconn->login_host, strlen(tail)); - - request_str = g_strdup_printf("%s%s", head,tail); - -#ifdef MSN_SOAP_DEBUG - purple_debug_misc("MSN Nexus", "TWN Sending:\n%s\n", request_str); -#endif - g_free(head); + soap = msn_soap_message_new(NULL, xmlnode_from_str(tail, -1)); g_free(tail); - g_free(username); - g_free(password); - - /*prepare to send the SOAP request*/ - msn_soap_write(soapconn, request_str, nexus_login_written_cb); - - return TRUE; + msn_soap_message_send(nexus->session, soap, MSN_TWN_SERVER, TWN_POST_URL, + nexus_got_response_cb, nexus); } -#if 0 /* khc */ -static void -nexus_connect_written_cb(gpointer data, gint source, PurpleInputCondition cond) -{ - MsnNexus *nexus = data; - int len; - - char *da_login; - char *base, *c; - - if (nexus->input_handler == 0) - /* TODO: Use purple_ssl_input_add()? */ - nexus->input_handler = purple_input_add(nexus->gsc->fd, - PURPLE_INPUT_READ, nexus_connect_written_cb, nexus); - - - /* Get the PassportURLs line. */ - len = msn_ssl_read(nexus); - - if (len < 0 && errno == EAGAIN) - return; - else if (len < 0) { - purple_input_remove(nexus->input_handler); - nexus->input_handler = 0; - g_free(nexus->read_buf); - nexus->read_buf = NULL; - nexus->read_len = 0; - /* TODO: error handling */ - return; - } - - if (g_strstr_len(nexus->read_buf, nexus->read_len, - "\r\n\r\n") == NULL) - return; - - purple_input_remove(nexus->input_handler); - nexus->input_handler = 0; - - base = strstr(nexus->read_buf, "PassportURLs"); - - if (base == NULL) - { - g_free(nexus->read_buf); - nexus->read_buf = NULL; - nexus->read_len = 0; - return; - } - - if ((da_login = strstr(base, "DALogin=")) != NULL) - { - /* skip over "DALogin=" */ - da_login += 8; - - if ((c = strchr(da_login, ',')) != NULL) - *c = '\0'; - - if ((c = strchr(da_login, '/')) != NULL) - { - nexus->login_path = g_strdup(c); - *c = '\0'; - } - - nexus->login_host = g_strdup(da_login); - } - - g_free(nexus->read_buf); - nexus->read_buf = NULL; - nexus->read_len = 0; - - purple_ssl_close(nexus->gsc); - - /* Now begin the connection to the login server. */ - nexus->gsc = purple_ssl_connect(nexus->session->account, - nexus->login_host, PURPLE_SSL_DEFAULT_PORT, - login_connect_cb, login_error_cb, nexus); -} - - -#endif - -/************************************************************************** - * Connect - **************************************************************************/ - -#if 0 /* khc */ -static void -nexus_connect_cb(gpointer data, PurpleSslConnection *gsc, - PurpleInputCondition cond) -{ - MsnNexus *nexus; - MsnSession *session; - - nexus = data; - g_return_if_fail(nexus != NULL); - - session = nexus->session; - g_return_if_fail(session != NULL); - - msn_session_set_login_step(session, MSN_LOGIN_STEP_AUTH); - - nexus->write_buf = g_strdup("GET /rdr/pprdr.asp\r\n\r\n"); - nexus->written_len = 0; - - nexus->read_len = 0; - - nexus->written_cb = nexus_connect_written_cb; - - nexus->input_handler = purple_input_add(gsc->fd, PURPLE_INPUT_WRITE, - nexus_write_cb, nexus); - - nexus_write_cb(nexus, gsc->fd, PURPLE_INPUT_WRITE); -} - -#endif - -void -msn_nexus_connect(MsnNexus *nexus) -{ - /* Authenticate via Windows Live ID. */ - msn_soap_init(nexus->soapconn, MSN_TWN_SERVER, TRUE, nexus_login_connect_cb, nexus_login_error_cb); - msn_soap_connect(nexus->soapconn); -}
--- a/libpurple/protocols/msn/nexus.h Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/protocols/msn/nexus.h Sat Nov 10 04:52:20 2007 +0000 @@ -139,7 +139,6 @@ struct _MsnNexus { MsnSession *session; - MsnSoapConn *soapconn; char * challenge_data_str; GHashTable *challenge_data; };
--- a/libpurple/protocols/msn/notification.c Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/protocols/msn/notification.c Sat Nov 10 04:52:20 2007 +0000 @@ -262,14 +262,15 @@ for (cur = elems; *cur != NULL; cur++) { tokens = g_strsplit(*cur, "=", 2); - if(tokens[0]&&tokens[1]) + if(tokens[0] && tokens[1]) { purple_debug_info("MSNP14","challenge %p,key:%s,value:%s\n", session->nexus->challenge_data,tokens[0],tokens[1]); g_hash_table_insert(session->nexus->challenge_data, tokens[0], tokens[1]); - } - /* Don't free each of the tokens, only the array. */ - g_free(tokens); + /* Don't free each of the tokens, only the array. */ + g_free(tokens); + } else + g_strfreev(tokens); } g_strfreev(elems); @@ -413,7 +414,7 @@ { g_return_if_fail(cmd->payload_cb != NULL); - purple_debug_info("MSNP14","MSG payload:{%s}\n",cmd->payload); + purple_debug_info("MSNP14","MSG payload:{%.*s}\n",cmd->payload_len, cmd->payload); cmd->payload_cb(cmdproc, cmd, cmd->payload, cmd->payload_len); } } @@ -464,15 +465,12 @@ if(!strcmp(content_type,"text/plain")){ const char *value; const char *body; - char *body_str; char *body_enc; char *body_final = NULL; size_t body_len; body = msn_message_get_bin_data(msg, &body_len); - body_str = g_strndup(body, body_len); - body_enc = g_markup_escape_text(body_str, -1); - g_free(body_str); + body_enc = g_markup_escape_text(body, body_len); if ((value = msn_message_get_attr(msg, "X-MMS-IM-Format")) != NULL) { char *pre, *post; @@ -485,6 +483,7 @@ } g_free(body_enc); serv_got_im(gc, passport, body_final, 0, time(NULL)); + g_free(body_final); } if(!strcmp(content_type,"text/x-msmsgscontrol")){ if(msn_message_get_attr(msg, "TypingUser") != NULL){ @@ -735,7 +734,7 @@ msn_cmdproc_send_trans(cmdproc, trans); g_free(payload); - g_free(tokens); + g_strfreev(tokens); } static void @@ -1412,7 +1411,7 @@ { purple_debug_error("msn", "Error opening temp passport file: %s\n", - strerror(errno)); + g_strerror(errno)); } else { @@ -1461,7 +1460,7 @@ { purple_debug_error("msn", "Error closing temp passport file: %s\n", - strerror(errno)); + g_strerror(errno)); g_unlink(session->passport_info.file); g_free(session->passport_info.file); @@ -1790,7 +1789,7 @@ return; /*new a oim session*/ - session->oim = msn_oim_new(session); +// session->oim = msn_oim_new(session); // msn_oim_connect(session->oim); table = msn_message_get_hashtable_from_body(msg);
--- a/libpurple/protocols/msn/object.c Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/protocols/msn/object.c Sat Nov 10 04:52:20 2007 +0000 @@ -154,10 +154,8 @@ { g_return_if_fail(obj != NULL); - if (obj->creator != NULL) - g_free(obj->creator); - - obj->creator = (creator == NULL ? NULL : g_strdup(creator)); + g_free(obj->creator); + obj->creator = g_strdup(creator); } void @@ -181,10 +179,8 @@ { g_return_if_fail(obj != NULL); - if (obj->location != NULL) - g_free(obj->location); - - obj->location = (location == NULL ? NULL : g_strdup(location)); + g_free(obj->location); + obj->location = g_strdup(location); } void @@ -192,10 +188,8 @@ { g_return_if_fail(obj != NULL); - if (obj->friendly != NULL) - g_free(obj->friendly); - - obj->friendly = (friendly == NULL ? NULL : g_strdup(friendly)); + g_free(obj->friendly); + obj->friendly = g_strdup(friendly); } void @@ -203,10 +197,8 @@ { g_return_if_fail(obj != NULL); - if (obj->sha1d != NULL) - g_free(obj->sha1d); - - obj->sha1d = (sha1d == NULL ? NULL : g_strdup(sha1d)); + g_free(obj->sha1d); + obj->sha1d = g_strdup(sha1d); } void @@ -214,10 +206,8 @@ { g_return_if_fail(obj != NULL); - if (obj->sha1c != NULL) - g_free(obj->sha1c); - - obj->sha1c = (sha1c == NULL ? NULL : g_strdup(sha1c)); + g_free(obj->sha1c); + obj->sha1c = g_strdup(sha1c); } const char *
--- a/libpurple/protocols/msn/oim.c Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/protocols/msn/oim.c Sat Nov 10 04:52:20 2007 +0000 @@ -24,24 +24,31 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "msn.h" -#include "soap.h" +#include "soap2.h" #include "oim.h" #include "msnutils.h" +typedef struct _MsnOimSendReq { + char *from_member; + char *friendname; + char *to_member; + char *oim_msg; +} MsnOimSendReq; + +typedef struct { + MsnOim *oim; + char *msg_id; +} MsnOimRecvData; + /*Local Function Prototype*/ -static void msn_oim_post_single_get_msg(MsnOim *oim,const char *msgid); +static void msn_oim_post_single_get_msg(MsnOim *oim, char *msgid); static MsnOimSendReq *msn_oim_new_send_req(const char *from_member, - const char *friendname, - const char* to_member, - gint send_seq, - const char *msg); -static void msn_oim_retrieve_connect_init(MsnSoapConn *soapconn); -static void msn_oim_send_connect_init(MsnSoapConn *soapconn); + const char *friendname, + const char* to_member, + const char *msg); static void msn_oim_free_send_req(MsnOimSendReq *req); -static void msn_oim_report_to_user(MsnOim *oim, const char *msg_str); -static void msn_oim_get_process(MsnOim *oim, const char *oim_msg); +static void msn_oim_report_to_user(MsnOimRecvData *rdata, const char *msg_str); static char *msn_oim_msg_to_str(MsnOim *oim, const char *body); -static void msn_oim_send_process(MsnOim *oim, const char *body, int len); /*new a OIM object*/ MsnOim * @@ -51,10 +58,7 @@ oim = g_new0(MsnOim, 1); oim->session = session; - oim->retrieveconn = msn_soap_new(session, oim, TRUE); - - oim->oim_list = NULL; - oim->sendconn = msn_soap_new(session, oim, TRUE); + oim->oim_list = NULL; oim->run_id = rand_guid(); oim->challenge = NULL; oim->send_queue = g_queue_new(); @@ -69,8 +73,6 @@ MsnOimSendReq *request; purple_debug_info("OIM","destroy the OIM \n"); - msn_soap_destroy(oim->retrieveconn); - msn_soap_destroy(oim->sendconn); g_free(oim->run_id); g_free(oim->challenge); @@ -84,8 +86,7 @@ static MsnOimSendReq * msn_oim_new_send_req(const char *from_member, const char*friendname, - const char* to_member, gint send_seq, - const char *msg) + const char* to_member, const char *msg) { MsnOimSendReq *request; @@ -93,7 +94,6 @@ request->from_member =g_strdup(from_member); request->friendname = g_strdup(friendname); request->to_member = g_strdup(to_member); - request->send_seq = send_seq; request->oim_msg = g_strdup(msg); return request; } @@ -115,7 +115,7 @@ * OIM send SOAP request * **************************************/ /*encode the message to OIM Message Format*/ -static char * +static gchar * msn_oim_msg_to_str(MsnOim *oim, const char *body) { char *oim_body,*oim_base64; @@ -125,139 +125,80 @@ purple_debug_info("MSN OIM","encoded base64 body:{%s}\n",oim_base64); oim_body = g_strdup_printf(MSN_OIM_MSG_TEMPLATE, oim->run_id,oim->send_seq,oim_base64); + g_free(oim_base64); return oim_body; } -/*oim SOAP server login error*/ -static void -msn_oim_send_error_cb(MsnSoapConn *soapconn, PurpleSslConnection *gsc, PurpleSslErrorType error) -{ - MsnSession *session; - - session = soapconn->session; - g_return_if_fail(session != NULL); - - msn_session_set_error(session, MSN_ERROR_SERV_DOWN, _("Unable to connect to OIM server")); -} - -/*msn oim SOAP server connect process*/ -static gboolean -msn_oim_send_connect_cb(MsnSoapConn *soapconn, PurpleSslConnection *gsc) -{ - MsnSession * session; - MsnOim *oim; - - oim = soapconn->parent; - g_return_val_if_fail(oim != NULL, TRUE); - - session = oim->session; - g_return_val_if_fail(session != NULL, FALSE); - - return TRUE; -} - /* * Process the send return SOAP string * If got SOAP Fault,get the lock key,and resend it. */ static void -msn_oim_send_process(MsnOim *oim, const char *body, int len) +msn_oim_send_read_cb(MsnSoapMessage *request, MsnSoapMessage *response, + gpointer data) { - xmlnode *responseNode, *bodyNode; - xmlnode *faultNode = NULL, *faultCodeNode, *faultstringNode; - xmlnode *detailNode, *challengeNode; - char *fault_code, *fault_text; + MsnOim *oim = data; + MsnOimSendReq *msg = g_queue_pop_head(oim->send_queue); + + g_return_if_fail(msg != NULL); - responseNode = xmlnode_from_str(body,len); + if (response == NULL) { + purple_debug_info("MSNP14", "cannot send OIM: %s\n", msg->oim_msg); + } else { + xmlnode *faultNode = msn_soap_xml_get(response->xml, "Body/Fault"); - g_return_if_fail(responseNode != NULL); + if (faultNode == NULL) { + /*Send OK! return*/ + purple_debug_info("MSNP14", "sent OIM: %s\n", msg->oim_msg); + } else { + xmlnode *faultcode = xmlnode_get_child(faultNode, "faultcode"); + + if (faultcode) { + char *faultcode_str = xmlnode_get_data(faultcode); - if ((bodyNode = xmlnode_get_child(responseNode, "Body"))) - faultNode = xmlnode_get_child(bodyNode, "Fault"); + if (g_str_equal(faultcode_str, "q0:AuthenticationFailed")) { + xmlnode *challengeNode = msn_soap_xml_get(faultNode, + "detail/LockKeyChallenge"); - if (faultNode == NULL) { - /*Send OK! return*/ - MsnOimSendReq *request; + if (challengeNode == NULL) { + if (oim->challenge) { + g_free(oim->challenge); + oim->challenge = NULL; - xmlnode_free(responseNode); - request = g_queue_pop_head(oim->send_queue); - msn_oim_free_send_req(request); - /*send next buffered Offline Message*/ - msn_soap_post(oim->sendconn, NULL); - - return; - } + purple_debug_info("msnoim","resending OIM: %s\n", + msg->oim_msg); + g_queue_push_head(oim->send_queue, msg); + msn_oim_send_msg(oim); + return; + } else { + purple_debug_info("msnoim", + "can't find lock key for OIM: %s\n", + msg->oim_msg); + } + } else { + char buf[33]; - /*get the challenge,and repost it*/ - if (faultNode) - faultCodeNode = xmlnode_get_child(faultNode, "faultcode"); + char *challenge = xmlnode_get_data(challengeNode); + msn_handle_chl(challenge, buf); + + g_free(oim->challenge); + oim->challenge = g_strndup(buf, sizeof(buf)); + g_free(challenge); + purple_debug_info("MSNP14","lockkey:{%s}\n",oim->challenge); - if(faultCodeNode == NULL){ - purple_debug_info("MSN OIM", "No faultcode for failed Offline Message.\n"); - xmlnode_free(responseNode); - return; + /*repost the send*/ + purple_debug_info("MSNP14","resending OIM: %s\n", msg->oim_msg); + g_queue_push_head(oim->send_queue, msg); + msn_oim_send_msg(oim); + return; + } + } + } + } } - fault_code = xmlnode_get_data(faultCodeNode); -#if 0 - if(!strcmp(fault_code,"q0:AuthenticationFailed")){ - /*other Fault Reason?*/ - goto oim_send_process_fail; - } -#endif - - faultstringNode = xmlnode_get_child(faultNode, "faultstring"); - fault_text = xmlnode_get_data(faultstringNode); - purple_debug_info("MSN OIM", "Error sending Offline Message: %s (%s)\n", - fault_text ? fault_text : "(null)", fault_code ? fault_code : "(null)"); - - /* lock key fault reason, - * compute the challenge and resend it - */ - if ((detailNode = xmlnode_get_child(faultNode, "detail")) - && (challengeNode = xmlnode_get_child(detailNode, "LockKeyChallenge"))) { - g_free(oim->challenge); - oim->challenge = xmlnode_get_data(challengeNode); - - purple_debug_info("MSN OIM", "Retrying Offline IM with lockkey:{%s}\n", - oim->challenge ? oim->challenge : "(null)"); - - /*repost the send*/ - msn_oim_send_msg(oim); - - /* XXX: This needs to give up eventually (1 retry, maybe?) */ - } - - g_free(fault_text); - g_free(fault_code); - xmlnode_free(responseNode); -} - -static gboolean -msn_oim_send_read_cb(MsnSoapConn *soapconn) -{ - MsnSession *session = soapconn->session; - MsnOim * oim; - - if (soapconn->body == NULL) - return TRUE; - - g_return_val_if_fail(session != NULL, FALSE); - oim = soapconn->session->oim; - g_return_val_if_fail(oim != NULL, TRUE); - - purple_debug_info("MSN OIM","read buffer:{%s}\n", soapconn->body); - msn_oim_send_process(oim,soapconn->body,soapconn->body_len); - - return TRUE; -} - -static void -msn_oim_send_written_cb(MsnSoapConn *soapconn) -{ - soapconn->read_cb = msn_oim_send_read_cb; -// msn_soap_read_cb(data,source,cond); + msn_oim_free_send_req(msg); } void @@ -265,45 +206,36 @@ const char* friendname, const char *tomember, const char * msg) { - MsnOimSendReq *request; - g_return_if_fail(oim != NULL); - request = msn_oim_new_send_req(membername,friendname,tomember,oim->send_seq,msg); - g_queue_push_tail(oim->send_queue,request); + g_queue_push_tail(oim->send_queue, + msn_oim_new_send_req(membername, friendname, tomember, msg)); } /*post send single message request to oim server*/ void msn_oim_send_msg(MsnOim *oim) { - MsnSoapReq *soap_request; MsnOimSendReq *oim_request; char *soap_body,*mspauth; char *msg_body; - char buf[33]; g_return_if_fail(oim != NULL); - oim_request = g_queue_pop_head(oim->send_queue); + oim_request = g_queue_peek_head(oim->send_queue); g_return_if_fail(oim_request != NULL); - purple_debug_info("MSN OIM","send single OIM Message\n"); + purple_debug_info("MSNP14","sending OIM: %s\n", oim_request->oim_msg); mspauth = g_strdup_printf("t=%s&p=%s", oim->session->passport_info.t, oim->session->passport_info.p ); - g_queue_push_head(oim->send_queue,oim_request); /* if we got the challenge lock key, we compute it * else we go for the SOAP fault and resend it. */ - if(oim->challenge != NULL){ - msn_handle_chl(oim->challenge, buf); - }else{ - purple_debug_info("MSN OIM","no lock key challenge,wait for SOAP Fault and Resend\n"); - buf[0]='\0'; + if(oim->challenge == NULL){ + purple_debug_info("MSNP14","no lock key challenge,wait for SOAP Fault and Resend\n"); } - purple_debug_info("MSN OIM","get the lock key challenge {%s}\n",buf); msg_body = msn_oim_msg_to_str(oim, oim_request->oim_msg); soap_body = g_strdup_printf(MSN_OIM_SEND_TEMPLATE, @@ -312,115 +244,71 @@ oim_request->to_member, mspauth, MSNP13_WLM_PRODUCT_ID, - buf, - oim_request->send_seq, + oim->challenge ? oim->challenge : "", + oim->send_seq, msg_body); - soap_request = msn_soap_request_new(MSN_OIM_SEND_HOST, - MSN_OIM_SEND_URL, - MSN_OIM_SEND_SOAP_ACTION, - soap_body, - NULL, - msn_oim_send_read_cb, - msn_oim_send_written_cb, - msn_oim_send_connect_init); + msn_soap_message_send(oim->session, + msn_soap_message_new(MSN_OIM_SEND_SOAP_ACTION, + xmlnode_from_str(soap_body, -1)), + MSN_OIM_SEND_HOST, MSN_OIM_SEND_URL, msn_oim_send_read_cb, oim); + + /*increase the offline Sequence control*/ + if (oim->challenge != NULL) { + oim->send_seq++; + } + g_free(mspauth); g_free(msg_body); g_free(soap_body); - - /*increase the offline Sequence control*/ - if(oim->challenge != NULL){ - oim->send_seq++; - } - msn_soap_post(oim->sendconn,soap_request); } /**************************************** * OIM delete SOAP request * **************************************/ -static gboolean -msn_oim_delete_read_cb(MsnSoapConn *soapconn) +static void +msn_oim_delete_read_cb(MsnSoapMessage *request, MsnSoapMessage *response, + gpointer data) { - if (soapconn->body == NULL) - return TRUE; - purple_debug_info("MSN OIM","OIM delete read buffer:{%s}\n",soapconn->body); + MsnOimRecvData *rdata = data; - msn_soap_free_read_buf(soapconn); - /*get next single Offline Message*/ -// msn_soap_post(soapconn,NULL); /* we already do this in soap.c */ - return TRUE; -} + if (response && msn_soap_xml_get(response->xml, "Body/Fault") == NULL) { + purple_debug_info("msnoim", "delete OIM success\n"); + rdata->oim->oim_list = g_list_remove(rdata->oim->oim_list, + rdata->msg_id); + g_free(rdata->msg_id); + } else { + purple_debug_info("msnoim", "delete OIM failed\n"); + } -static void -msn_oim_delete_written_cb(MsnSoapConn *soapconn) -{ - soapconn->read_cb = msn_oim_delete_read_cb; + g_free(rdata); } /*Post to get the Offline Instant Message*/ static void -msn_oim_post_delete_msg(MsnOim *oim,const char *msgid) +msn_oim_post_delete_msg(MsnOimRecvData *rdata) { - MsnSoapReq *soap_request; - const char *soap_body,*t,*p; + MsnOim *oim = rdata->oim; + char *msgid = rdata->msg_id; + char *soap_body; - g_return_if_fail(oim != NULL); - g_return_if_fail(msgid != NULL); - - purple_debug_info("MSN OIM","Delete single OIM Message {%s}\n",msgid); - t = oim->session->passport_info.t; - p = oim->session->passport_info.p; + purple_debug_info("MSNP14","Delete single OIM Message {%s}\n",msgid); soap_body = g_strdup_printf(MSN_OIM_DEL_TEMPLATE, - t, - p, - msgid - ); - soap_request = msn_soap_request_new(MSN_OIM_RETRIEVE_HOST, - MSN_OIM_RETRIEVE_URL, - MSN_OIM_DEL_SOAP_ACTION, - soap_body, - NULL, - msn_oim_delete_read_cb, - msn_oim_delete_written_cb, - msn_oim_retrieve_connect_init); - msn_soap_post(oim->retrieveconn,soap_request); + oim->session->passport_info.t, oim->session->passport_info.p, msgid); + + msn_soap_message_send(oim->session, + msn_soap_message_new(MSN_OIM_DEL_SOAP_ACTION, + xmlnode_from_str(soap_body, -1)), + MSN_OIM_RETRIEVE_HOST, MSN_OIM_RETRIEVE_URL, + msn_oim_delete_read_cb, rdata); + + g_free(soap_body); } /**************************************** * OIM get SOAP request * **************************************/ -/*oim SOAP server login error*/ -static void -msn_oim_get_error_cb(MsnSoapConn *soapconn, PurpleSslConnection *gsc, PurpleSslErrorType error) -{ - MsnSession *session; - - session = soapconn->session; - g_return_if_fail(session != NULL); - msn_soap_clean_unhandled_requests(soapconn); - -// msn_session_set_error(session, MSN_ERROR_SERV_DOWN, _("Unable to connect to OIM server")); -} - -/*msn oim SOAP server connect process*/ -static gboolean -msn_oim_get_connect_cb(MsnSoapConn *soapconn, PurpleSslConnection *gsc) -{ - MsnSession * session; - MsnOim *oim; - - oim = soapconn->parent; - g_return_val_if_fail(oim != NULL, TRUE); - - session = oim->session; - g_return_val_if_fail(session != NULL, FALSE); - - purple_debug_info("MSN OIM","Connected and ready to get OIM!\n"); - - return TRUE; -} - /* like purple_str_to_time, but different. The format of the timestamp * is like this: 5 Sep 2007 21:42:12 -0700 */ static time_t @@ -432,9 +320,13 @@ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL }; + time_t tval = 0; struct tm t; memset(&t, 0, sizeof(t)); + time(&tval); + localtime_r(&tval, &t); + if (sscanf(timestamp, "%02d %03s %04d %02d:%02d:%02d %05s", &t.tm_mday, month_str, &t.tm_year, &t.tm_hour, &t.tm_min, &t.tm_sec, tz_str) == 7) { @@ -463,14 +355,13 @@ tzoff *= -1; t.tm_year -= 1900; - t.tm_isdst = 0; #ifdef _WIN32 if ((sys_tzoff = wpurple_get_tz_offset()) != -1) tzoff += sys_tzoff; #else #ifdef HAVE_TM_GMTOFF - tzoff += t.tm_gmtoff; + tzoff -= t.tm_gmtoff; #else # ifdef HAVE_TIMEZONE tzset(); /* making sure */ @@ -484,13 +375,13 @@ } } - purple_debug_info("MSN OIM:OIM", "Can't parse timestamp %s\n", timestamp); - return time(NULL); + purple_debug_info("MSNP14:OIM", "Can't parse timestamp %s\n", timestamp); + return tval; } /*Post the Offline Instant Message to User Conversation*/ static void -msn_oim_report_to_user(MsnOim *oim, const char *msg_str) +msn_oim_report_to_user(MsnOimRecvData *rdata, const char *msg_str) { MsnMessage *message; char *date,*from,*decode_msg; @@ -499,14 +390,13 @@ char *start,*end; int has_nick = 0; char *passport_str, *passport; - char *msg_id; time_t stamp; message = msn_message_new(MSN_MSG_UNKNOWN); msn_message_parse_payload(message, msg_str, strlen(msg_str), MSG_OIM_LINE_DEM, MSG_OIM_BODY_DEM); - purple_debug_info("MSN OIM","oim body:{%s}\n",message->body); + purple_debug_info("MSNP14","oim body:{%s}\n",message->body); decode_msg = (char *)purple_base64_decode(message->body,&body_len); date = (char *)g_hash_table_lookup(message->attr_table, "Date"); from = (char *)g_hash_table_lookup(message->attr_table, "From"); @@ -516,12 +406,12 @@ if(has_nick){ tokens = g_strsplit(from , " " , 2); passport_str = g_strdup(tokens[1]); - purple_debug_info("MSN OIM","oim Date:{%s},nickname:{%s},tokens[1]:{%s} passport{%s}\n", + purple_debug_info("MSNP14","oim Date:{%s},nickname:{%s},tokens[1]:{%s} passport{%s}\n", date,tokens[0],tokens[1],passport_str); g_strfreev(tokens); }else{ passport_str = g_strdup(from); - purple_debug_info("MSN OIM","oim Date:{%s},passport{%s}\n", + purple_debug_info("MSNP14","oim Date:{%s},passport{%s}\n", date,passport_str); } start = strstr(passport_str,"<"); @@ -533,66 +423,43 @@ stamp = msn_oim_parse_timestamp(date); - serv_got_im(oim->session->account->gc, passport, decode_msg, 0, stamp); + serv_got_im(rdata->oim->session->account->gc, passport, decode_msg, 0, + stamp); /*Now get the oim message ID from the oim_list. * and append to read list to prepare for deleting the Offline Message when sign out */ - if(oim->oim_list != NULL){ - msg_id = oim->oim_list->data; - msn_oim_post_delete_msg(oim,msg_id); - oim->oim_list = g_list_remove(oim->oim_list, oim->oim_list->data); - g_free(msg_id); - } + msn_oim_post_delete_msg(rdata); g_free(passport); + g_free(decode_msg); } /* Parse the XML data, * prepare to report the OIM to user */ static void -msn_oim_get_process(MsnOim *oim, const char *oim_msg) -{ - xmlnode *oim_node,*bodyNode,*responseNode,*msgNode; - char *msg_str; - - oim_node = xmlnode_from_str(oim_msg, strlen(oim_msg)); - bodyNode = xmlnode_get_child(oim_node,"Body"); - responseNode = xmlnode_get_child(bodyNode,"GetMessageResponse"); - msgNode = xmlnode_get_child(responseNode,"GetMessageResult"); - msg_str = xmlnode_get_data(msgNode); - purple_debug_info("OIM","msg:{%s}\n",msg_str); - msn_oim_report_to_user(oim,msg_str); - - g_free(msg_str); - xmlnode_free(oim_node); -} - -static gboolean -msn_oim_get_read_cb(MsnSoapConn *soapconn) +msn_oim_get_read_cb(MsnSoapMessage *request, MsnSoapMessage *response, + gpointer data) { - MsnOim * oim = soapconn->session->oim; - - if (soapconn->body == NULL) - return TRUE; + MsnOimRecvData *rdata = data; - purple_debug_info("MSN OIM","OIM get read buffer:{%s}\n",soapconn->body); - - /*we need to process the read message!*/ - msn_oim_get_process(oim,soapconn->body); - msn_soap_free_read_buf(soapconn); + if (response != NULL) { + xmlnode *msg_node = msn_soap_xml_get(response->xml, + "Body/GetMessageResponse/GetMessageResult"); - /*get next single Offline Message*/ -// msn_soap_post(soapconn,NULL); /* we already do this in soap.c */ - return TRUE; -} - -static void -msn_oim_get_written_cb(MsnSoapConn *soapconn) -{ - soapconn->read_cb = msn_oim_get_read_cb; -// msn_soap_read_cb(data,source,cond); + if (msg_node) { + char *msg_str = xmlnode_get_data(msg_node); + msn_oim_report_to_user(rdata, msg_str); + g_free(msg_str); + } else { + char *str = xmlnode_to_str(response->xml, NULL); + purple_debug_info("msnoim", "Unknown response: %s\n", str); + g_free(str); + } + } else { + purple_debug_info("msnoim", "Failed to get OIM\n"); + } } /* parse the oim XML data @@ -601,114 +468,88 @@ void msn_parse_oim_msg(MsnOim *oim,const char *xmlmsg) { - xmlnode *node, *mNode,*ENode,*INode,*rtNode,*nNode; - char *passport,*msgid,*nickname, *unread, *rTime = NULL; + xmlnode *node, *mNode; + xmlnode *iu_node; MsnSession *session = oim->session; - purple_debug_info("MSN OIM:OIM", "%s", xmlmsg); + purple_debug_info("MSNP14:OIM", "%s", xmlmsg); - node = xmlnode_from_str(xmlmsg, strlen(xmlmsg)); - if (!node || !node->name || strcmp(node->name, "MD") != 0) { - if (node) - xmlnode_free(node); + node = xmlnode_from_str(xmlmsg, -1); + if (strcmp(node->name, "MD") != 0) { + purple_debug_info("msnoim", "WTF is this? %s\n", xmlmsg); + xmlnode_free(node); return; } - ENode = xmlnode_get_child(node, "E"); - INode = xmlnode_get_child(ENode, "IU"); - unread = xmlnode_get_data(INode); - - if (unread != NULL && purple_account_get_check_mail(session->account)) - { - int count = atoi(unread); + iu_node = msn_soap_xml_get(node, "E/IU"); - if (count > 0) - { - const char *passport; - const char *url; + if (iu_node != NULL && purple_account_get_check_mail(session->account)) + { + char *unread = xmlnode_get_data(iu_node); + const char *passport = msn_user_get_passport(session->user); + const char *url = session->passport_info.file; - passport = msn_user_get_passport(session->user); - url = session->passport_info.file; - - purple_notify_emails(session->account->gc, atoi(unread), FALSE, NULL, NULL, - &passport, &url, NULL, NULL); - } + /* XXX/khc: pretty sure this is wrong */ + purple_notify_emails(session->account->gc, atoi(unread), FALSE, NULL, + NULL, &passport, &url, NULL, NULL); + g_free(unread); } for(mNode = xmlnode_get_child(node, "M"); mNode; mNode = xmlnode_get_next_twin(mNode)){ - /*email Node*/ - ENode = xmlnode_get_child(mNode,"E"); - passport = xmlnode_get_data(ENode); - /*Index */ - INode = xmlnode_get_child(mNode,"I"); - msgid = xmlnode_get_data(INode); - /*Nickname*/ - nNode = xmlnode_get_child(mNode,"N"); - nickname = xmlnode_get_data(nNode); - /*receive time*/ - rtNode = xmlnode_get_child(mNode,"RT"); - if(rtNode != NULL) - rTime = xmlnode_get_data(rtNode); -/* purple_debug_info("MSN OIM","E:{%s},I:{%s},rTime:{%s}\n",passport,msgid,rTime); */ + char *passport, *msgid, *nickname, *rtime = NULL; + xmlnode *e_node, *i_node, *n_node, *rt_node; + + e_node = xmlnode_get_child(mNode, "E"); + passport = xmlnode_get_data(e_node); + + i_node = xmlnode_get_child(mNode, "I"); + msgid = xmlnode_get_data(i_node); + + n_node = xmlnode_get_child(mNode, "N"); + nickname = xmlnode_get_data(n_node); - oim->oim_list = g_list_append(oim->oim_list,strdup(msgid)); - msn_oim_post_single_get_msg(oim,msgid); + rt_node = xmlnode_get_child(mNode, "RT"); + if (rt_node != NULL) { + rtime = xmlnode_get_data(rt_node); + } +/* purple_debug_info("msnoim","E:{%s},I:{%s},rTime:{%s}\n",passport,msgid,rTime); */ + + if (!g_list_find_custom(oim->oim_list, msgid, (GCompareFunc)strcmp)) { + oim->oim_list = g_list_append(oim->oim_list, msgid); + msn_oim_post_single_get_msg(oim, msgid); + msgid = NULL; + } + g_free(passport); g_free(msgid); - g_free(rTime); - rTime = NULL; + g_free(rtime); g_free(nickname); } - g_free(unread); + xmlnode_free(node); } /*Post to get the Offline Instant Message*/ static void -msn_oim_post_single_get_msg(MsnOim *oim,const char *msgid) +msn_oim_post_single_get_msg(MsnOim *oim, char *msgid) { - MsnSoapReq *soap_request; - const char *soap_body,*t,*p; + char *soap_body; + MsnOimRecvData *data = g_new0(MsnOimRecvData, 1); - purple_debug_info("MSN OIM","Get single OIM Message\n"); - t = oim->session->passport_info.t; - p = oim->session->passport_info.p; + purple_debug_info("MSNP14","Get single OIM Message\n"); + + data->oim = oim; + data->msg_id = msgid; soap_body = g_strdup_printf(MSN_OIM_GET_TEMPLATE, - t, - p, - msgid - ); - soap_request = msn_soap_request_new(MSN_OIM_RETRIEVE_HOST, - MSN_OIM_RETRIEVE_URL, - MSN_OIM_GET_SOAP_ACTION, - soap_body, - NULL, - msn_oim_get_read_cb, - msn_oim_get_written_cb, - msn_oim_retrieve_connect_init); - msn_soap_post(oim->retrieveconn,soap_request); -} + oim->session->passport_info.t, oim->session->passport_info.p, msgid); -/*msn oim retrieve server connect init */ -static void -msn_oim_retrieve_connect_init(MsnSoapConn *soapconn) -{ - purple_debug_info("MSN OIM","Initializing OIM retrieve connection\n"); - msn_soap_init(soapconn, MSN_OIM_RETRIEVE_HOST, TRUE, - msn_oim_get_connect_cb, - msn_oim_get_error_cb); -} + msn_soap_message_send(oim->session, + msn_soap_message_new(MSN_OIM_GET_SOAP_ACTION, + xmlnode_from_str(soap_body, -1)), + MSN_OIM_RETRIEVE_HOST, MSN_OIM_RETRIEVE_URL, + msn_oim_get_read_cb, data); -/*Msn OIM Send Server Connect Init Function*/ -static void -msn_oim_send_connect_init(MsnSoapConn *sendconn) -{ - purple_debug_info("MSN OIM","Initializing OIM send connection\n"); - msn_soap_init(sendconn, MSN_OIM_SEND_HOST, TRUE, - msn_oim_send_connect_cb, - msn_oim_send_error_cb); + g_free(soap_body); } - -/* EOF oim.c*/
--- a/libpurple/protocols/msn/oim.h Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/protocols/msn/oim.h Sat Nov 10 04:52:20 2007 +0000 @@ -95,17 +95,6 @@ "</soap:Body>"\ "</soap:Envelope>" -typedef struct _MsnOimSendReq MsnOimSendReq; - -struct _MsnOimSendReq -{ - char *from_member; - char *friendname; - char *to_member; - char *oim_msg; - gint send_seq; -}; - typedef struct _MsnOim MsnOim; struct _MsnOim @@ -127,7 +116,6 @@ * **************************************************/ MsnOim * msn_oim_new(MsnSession *session); void msn_oim_destroy(MsnOim *oim); -void msn_oim_connect(MsnOim *oim); void msn_parse_oim_msg(MsnOim *oim,const char *xmlmsg); @@ -138,11 +126,5 @@ void msn_oim_send_msg(MsnOim *oim); -/*get the OIM message*/ -void msn_oim_get_msg(MsnOim *oim); - -/*report the oim message to the conversation*/ -void msn_oim_report_user(MsnOim *oim,const char *passport,char *msg); - #endif/* _MSN_OIM_H_*/ /*endof oim.h*/
--- a/libpurple/protocols/msn/page.c Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/protocols/msn/page.c Sat Nov 10 04:52:20 2007 +0000 @@ -74,9 +74,7 @@ g_return_if_fail(page != NULL); g_return_if_fail(body != NULL); - if (page->body != NULL) - g_free(page->body); - + g_free(page->body); page->body = g_strdup(body); }
--- a/libpurple/protocols/msn/servconn.c Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/protocols/msn/servconn.c Sat Nov 10 04:52:20 2007 +0000 @@ -402,7 +402,7 @@ default: purple_debug_error("msn", "servconn read error," "len: %d, errno: %d, error: %s\n", - len, errno, strerror(errno)); + len, errno, g_strerror(errno)); msn_servconn_got_error(servconn, MSN_SERVCONN_ERROR_READ); return; @@ -480,6 +480,7 @@ create_listener(int port) { int fd; + int flags; const int on = 1; #if 0 @@ -555,7 +556,8 @@ return -1; } - fcntl(fd, F_SETFL, O_NONBLOCK); + flags = fcntl(fd, F_GETFL); + fcntl(fd, F_SETFL, flags | O_NONBLOCK); return fd; }
--- a/libpurple/protocols/msn/session.c Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/protocols/msn/session.c Sat Nov 10 04:52:20 2007 +0000 @@ -24,6 +24,7 @@ #include "msn.h" #include "session.h" #include "notification.h" +#include "oim.h" #include "dialog.h" @@ -42,6 +43,7 @@ session->user = msn_user_new(session->userlist, purple_account_get_username(account), NULL); + session->oim = msn_oim_new(session); /*if you want to chat with Yahoo Messenger*/ //session->protocol_ver = WLM_YAHOO_PROT_VER; @@ -99,6 +101,12 @@ if (session->user != NULL) msn_user_destroy(session->user); + if (session->soap_table) + g_hash_table_destroy(session->soap_table); + + if (session->soap_cleanup_handle) + purple_timeout_remove(session->soap_cleanup_handle); + g_free(session); }
--- a/libpurple/protocols/msn/session.h Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/protocols/msn/session.h Sat Nov 10 04:52:20 2007 +0000 @@ -126,6 +126,9 @@ char *client_ip; int client_port; } passport_info; + + GHashTable *soap_table; + int soap_cleanup_handle; }; /**
--- a/libpurple/protocols/msn/slp.c Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/protocols/msn/slp.c Sat Nov 10 04:52:20 2007 +0000 @@ -505,6 +505,9 @@ int port; nonce = get_token(content, "Nonce: {", "}\r\n"); + if (ip_addrs == NULL) + return; + ip_addrs = get_token(content, "IPv4Internal-Addrs: ", "\r\n"); temp = get_token(content, "IPv4Internal-Port: ", "\r\n"); @@ -514,9 +517,6 @@ port = -1; g_free(temp); - if (ip_addrs == NULL) - return; - if (port > 0) got_transresp(slpcall, nonce, ip_addrs, port); @@ -598,6 +598,9 @@ int port; nonce = get_token(content, "Nonce: {", "}\r\n"); + if (ip_addrs == NULL) + return; + ip_addrs = get_token(content, "IPv4Internal-Addrs: ", "\r\n"); temp = get_token(content, "IPv4Internal-Port: ", "\r\n"); @@ -607,9 +610,6 @@ port = -1; g_free(temp); - if (ip_addrs == NULL) - return; - if (port > 0) got_transresp(slpcall, nonce, ip_addrs, port);
--- a/libpurple/protocols/msn/slplink.c Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/protocols/msn/slplink.c Sat Nov 10 04:52:20 2007 +0000 @@ -39,22 +39,17 @@ char *tmp; char *dir; char *pload; - FILE *tf; int c; gsize pload_size; dir = send ? "send" : "recv"; c = send ? m_sc++ : m_rc++; tmp = g_strdup_printf("%s/msntest/%s/%03d", g_get_home_dir(), dir, c); - tf = g_fopen(tmp, "wb"); - if (tf == NULL) + pload = msn_message_gen_payload(msg, &pload_size); + if (!purple_util_write_data_to_file_absolute(tmp, pload, pload_size)) { - purple_debug_error("msn", "could not open debug file\n"); - return; + purple_debug_error("msn", "could not save debug file"); } - pload = msn_message_gen_payload(msg, &pload_size); - fwrite(pload, 1, pload_size, tf); - fclose(tf); g_free(tmp); } #endif @@ -120,6 +115,8 @@ while (slplink->slp_calls != NULL) msn_slp_call_destroy(slplink->slp_calls->data); + g_queue_free(slplink->slp_msg_queue); + session->slplinks = g_list_remove(session->slplinks, slplink);
--- a/libpurple/protocols/msn/soap.c Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/protocols/msn/soap.c Sat Nov 10 04:52:20 2007 +0000 @@ -274,7 +274,7 @@ default : purple_debug_error("MSN SOAP", "Read error!" "read len: %d, error = %s\n", - len, strerror(errno)); + len, g_strerror(errno)); purple_input_remove(soapconn->input_handler); //soapconn->input_handler = 0; g_free(soapconn->read_buf); @@ -308,7 +308,7 @@ } /*read the whole SOAP server response*/ -void +static void msn_soap_read_cb(gpointer data, gint source, PurpleInputCondition cond) { MsnSoapConn *soapconn = data; @@ -679,6 +679,8 @@ msn_soap_set_process_step(soapconn, MSN_SOAP_PROCESSING); + /* Ideally this wouldn't ever be necessary, but i believe that it is leaking the previous value */ + g_free(soapconn->write_buf); soapconn->write_buf = write_buf; soapconn->written_len = 0; soapconn->written_cb = written_cb; @@ -822,7 +824,6 @@ void msn_soap_post_request(MsnSoapConn *soapconn, MsnSoapReq *request) { - char * soap_head = NULL; char * request_str = NULL; #ifdef MSN_SOAP_DEBUG #if !defined(_WIN32) @@ -832,7 +833,7 @@ #endif msn_soap_set_process_step(soapconn, MSN_SOAP_PROCESSING); - soap_head = g_strdup_printf( + request_str = g_strdup_printf( "POST %s HTTP/1.1\r\n" "SOAPAction: %s\r\n" "Content-Type:text/xml; charset=utf-8\r\n" @@ -842,20 +843,21 @@ "Host: %s\r\n" "Content-Length: %" G_GSIZE_FORMAT "\r\n" "Connection: Keep-Alive\r\n" - "Cache-Control: no-cache\r\n\r\n", + "Cache-Control: no-cache\r\n\r\n" + "%s", request->login_path, request->soap_action, soapconn->session->passport_info.mspauth, request->login_host, - strlen(request->body) + strlen(request->body), + request->body ); - request_str = g_strdup_printf("%s%s", soap_head, request->body); #if defined(MSN_SOAP_DEBUG) && !defined(_WIN32) node = xmlnode_from_str(request->body, -1); if (node != NULL) { char *formattedstr = xmlnode_to_formatted_str(node, NULL); - purple_debug_info("MSN SOAP","Posting request to SOAP server:\n%s%s\n",soap_head, formattedstr); + purple_debug_info("MSN SOAP","Posting request to SOAP server:\n%s%s\n",request_str, formattedstr); g_free(formattedstr); xmlnode_free(node); } @@ -863,7 +865,6 @@ purple_debug_info("MSN SOAP","Failed to parse SOAP request being sent:\n%s\n", request_str); #endif - g_free(soap_head); /*free read buffer*/ // msn_soap_free_read_buf(soapconn); /*post it to server*/
--- a/libpurple/protocols/msn/soap.h Sat Nov 10 01:18:15 2007 +0000 +++ b/libpurple/protocols/msn/soap.h Sat Nov 10 04:52:20 2007 +0000 @@ -154,7 +154,6 @@ void msn_soap_free_read_buf(MsnSoapConn *soapconn); void msn_soap_free_write_buf(MsnSoapConn *soapconn); void msn_soap_connect_cb(gpointer data, PurpleSslConnection *gsc, PurpleInputCondition cond); -void msn_soap_read_cb(gpointer data, gint source, PurpleInputCondition cond); /*clean the unhandled requests*/ void msn_soap_clean_unhandled_requests(MsnSoapConn *soapconn);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/msn/soap2.c Sat Nov 10 04:52:20 2007 +0000 @@ -0,0 +1,677 @@ +/** + * @file soap2.c + * C file for SOAP connection related process + * + * purple + * + * Purple is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "internal.h" + +#include "soap2.h" + +#include "session.h" + +#include "debug.h" +#include "xmlnode.h" + +#include <glib.h> +#include <error.h> + +#define SOAP_TIMEOUT (5 * 60) + +typedef struct _MsnSoapRequest { + char *path; + MsnSoapMessage *message; + MsnSoapCallback cb; + gpointer cb_data; +} MsnSoapRequest; + +typedef struct _MsnSoapConnection { + MsnSession *session; + char *host; + + time_t last_used; + PurpleSslConnection *ssl; + gboolean connected; + + guint event_handle; + GString *buf; + gsize handled_len; + gsize body_len; + int response_code; + gboolean headers_done; + gboolean close_when_done; + + MsnSoapMessage *message; + + GQueue *queue; + MsnSoapRequest *current_request; +} MsnSoapConnection; + +static void msn_soap_connection_destroy_foreach_cb(gpointer item, gpointer data); +static gboolean msn_soap_connection_run(gpointer data); + +static MsnSoapConnection *msn_soap_connection_new(MsnSession *session, + const char *host); +static void msn_soap_connection_handle_next(MsnSoapConnection *conn); +static void msn_soap_connection_destroy(MsnSoapConnection *conn); + +static void msn_soap_message_send_internal(MsnSession *session, + MsnSoapMessage *message, const char *host, const char *path, + MsnSoapCallback cb, gpointer cb_data, gboolean first); + +static void msn_soap_request_destroy(MsnSoapRequest *req); +static void msn_soap_connection_sanitize(MsnSoapConnection *conn, gboolean disconnect); + +static gboolean +msn_soap_cleanup_each(gpointer key, gpointer value, gpointer data) +{ + MsnSoapConnection *conn = value; + time_t *t = data; + + if ((*t - conn->last_used) > SOAP_TIMEOUT * 2) { + purple_debug_info("soap", "cleaning up soap conn %p\n", conn); + return TRUE; + } + + return FALSE; +} + +static gboolean +msn_soap_cleanup_for_session(gpointer data) +{ + MsnSession *sess = data; + time_t t = time(NULL); + + purple_debug_info("soap", "session cleanup timeout\n"); + + if (sess->soap_table) { + g_hash_table_foreach_remove(sess->soap_table, msn_soap_cleanup_each, + &t); + + if (g_hash_table_size(sess->soap_table) == 0) { + purple_timeout_remove(sess->soap_cleanup_handle); + sess->soap_cleanup_handle = 0; + } + } + + return TRUE; +} + +static MsnSoapConnection * +msn_soap_get_connection(MsnSession *session, const char *host) +{ + MsnSoapConnection *conn = NULL; + + if (session->soap_table) { + conn = g_hash_table_lookup(session->soap_table, host); + } else { + session->soap_table = g_hash_table_new_full(g_str_hash, g_str_equal, + NULL, (GDestroyNotify)msn_soap_connection_destroy); + } + + if (session->soap_cleanup_handle == 0) + session->soap_cleanup_handle = purple_timeout_add(SOAP_TIMEOUT * 1000, + msn_soap_cleanup_for_session, session); + + if (conn == NULL) { + conn = msn_soap_connection_new(session, host); + g_hash_table_insert(session->soap_table, conn->host, conn); + } + + conn->last_used = time(NULL); + + return conn; +} + +static MsnSoapConnection * +msn_soap_connection_new(MsnSession *session, const char *host) +{ + MsnSoapConnection *conn = g_new0(MsnSoapConnection, 1); + conn->session = session; + conn->host = g_strdup(host); + conn->queue = g_queue_new(); + return conn; +} + +static void +msn_soap_connected_cb(gpointer data, PurpleSslConnection *ssl, + PurpleInputCondition cond) +{ + MsnSoapConnection *conn = data; + + conn->connected = TRUE; + + if (conn->event_handle == 0) + conn->event_handle = purple_timeout_add(0, msn_soap_connection_run, conn); +} + +static void +msn_soap_error_cb(PurpleSslConnection *ssl, PurpleSslErrorType error, + gpointer data) +{ + MsnSoapConnection *conn = data; + + g_hash_table_remove(conn->session->soap_table, conn->host); +} + +static gboolean +msn_soap_handle_redirect(MsnSoapConnection *conn, const char *url) +{ + char *c; + + /* Skip the http:// */ + if ((c = strchr(url, '/')) != NULL) + url += 2; + + if ((c = strchr(url, '/')) != NULL) { + char *host, *path; + + host = g_strndup(url, c - url); + path = g_strdup(c); + + msn_soap_message_send_internal(conn->session, + conn->current_request->message, host, path, + conn->current_request->cb, conn->current_request->cb_data, TRUE); + + msn_soap_request_destroy(conn->current_request); + conn->current_request = NULL; + + g_free(host); + g_free(path); + + return TRUE; + } + + return FALSE; +} + +static gboolean +msn_soap_handle_body(MsnSoapConnection *conn, MsnSoapMessage *response) +{ + xmlnode *body = xmlnode_get_child(response->xml, "Body"); + + if (body) { + MsnSoapRequest *request; + + if (strcmp(body->name, "Fault") == 0) { + xmlnode *fault = xmlnode_get_child(body, "faultcode"); + + if (fault != NULL) { + char *faultdata = xmlnode_get_data(fault); + + if (strcmp(faultdata, "psf:Redirect") == 0) { + xmlnode *url = xmlnode_get_child(body, "redirectUrl"); + + if (url) { + char *urldata = xmlnode_get_data(url); + msn_soap_handle_redirect(conn, urldata); + g_free(urldata); + } + + g_free(faultdata); + return TRUE; + } else if (strcmp(faultdata, "wsse:FailedAuthentication") == 0) { + xmlnode *reason = xmlnode_get_child(body, "faultstring"); + char *reasondata = xmlnode_get_data(reason); + + msn_soap_connection_sanitize(conn, TRUE); + msn_session_set_error(conn->session, MSN_ERROR_AUTH, + reasondata); + + g_free(reasondata); + g_free(faultdata); + return FALSE; + } + + g_free(faultdata); + } + } + + request = conn->current_request; + conn->current_request = NULL; + request->cb(request->message, response, + request->cb_data); + msn_soap_request_destroy(request); + } + + return TRUE; +} + +static void +msn_soap_read_cb(gpointer data, gint fd, PurpleInputCondition cond) +{ + MsnSoapConnection *conn = data; + int count = 0, cnt; + char buf[8192]; + char *linebreak; + char *cursor; + gboolean handled = FALSE; + + if (conn->message == NULL) { + conn->message = msn_soap_message_new(NULL, NULL); + } + + while ((cnt = purple_ssl_read(conn->ssl, buf, sizeof(buf))) > 0) { + purple_debug_info("soap", "read %d bytes\n", cnt); + count += cnt; + if (conn->buf == NULL) { + conn->buf = g_string_new_len(buf, cnt); + } else { + g_string_append_len(conn->buf, buf, cnt); + } + } + + if (cnt < 0) { + if (errno != EAGAIN) { + purple_debug_info("soap", "read: %s\n", g_strerror(errno)); + purple_ssl_close(conn->ssl); + conn->ssl = NULL; + msn_soap_connection_handle_next(conn); + return; + } else if (count == 0) { + return; + } + } + + if (cnt == 0 && count == 0) { + purple_debug_info("soap", "msn_soap_read_cb() called, but no data available?\n"); + purple_ssl_close(conn->ssl); + conn->ssl = NULL; + msn_soap_connection_handle_next(conn); + return; + } + + purple_debug_info("soap", "current %s\n", conn->buf->str); + + cursor = conn->buf->str + conn->handled_len; + + if (!conn->headers_done) { + while ((linebreak = strstr(cursor, "\r\n")) != NULL) { + conn->handled_len = linebreak - conn->buf->str + 2; + + if (conn->response_code == 0) { + if (sscanf(cursor, "HTTP/1.1 %d", &conn->response_code) != 1) { + /* something horribly wrong */ + purple_ssl_close(conn->ssl); + conn->ssl = NULL; + msn_soap_connection_handle_next(conn); + handled = TRUE; + break; + } else if (conn->response_code == 503) { + msn_soap_connection_sanitize(conn, TRUE); + msn_session_set_error(conn->session, MSN_ERROR_SERV_UNAVAILABLE, NULL); + return; + } + } else if (cursor == linebreak) { + /* blank line */ + conn->headers_done = TRUE; + cursor = conn->buf->str + conn->handled_len; + break; + } else { + char *line = g_strndup(cursor, linebreak - cursor); + char *sep = strstr(line, ": "); + char *key = line; + char *value; + + if (sep == NULL) { + purple_debug_info("soap", "ignoring malformed line: %s\n", line); + g_free(line); + goto loop_end; + } + + value = sep + 2; + *sep = '\0'; + msn_soap_message_add_header(conn->message, key, value); + + if ((conn->response_code == 301 || conn->response_code == 300) + && strcmp(key, "Location") == 0) { + + msn_soap_handle_redirect(conn, value); + + handled = TRUE; + g_free(line); + break; + } else if (conn->response_code == 401 && + strcmp(key, "WWW-Authenticate") == 0) { + char *error = strstr(value, "cbtxt="); + + if (error) { + error += strlen("cbtxt="); + } + + msn_soap_connection_sanitize(conn, TRUE); + msn_session_set_error(conn->session, MSN_ERROR_AUTH, + error ? purple_url_decode(error) : NULL); + + g_free(line); + return; + } else if (strcmp(key, "Content-Length") == 0) { + conn->body_len = atoi(value); + } else if (strcmp(key, "Connection") == 0) { + if (strcmp(value, "close") == 0) { + conn->close_when_done = TRUE; + } + } + g_free(line); + } + + loop_end: + cursor = conn->buf->str + conn->handled_len; + } + } + + if (!handled && conn->headers_done) { + if (conn->buf->len - conn->handled_len >= + conn->body_len) { + xmlnode *node = xmlnode_from_str(cursor, conn->body_len); + + if (node == NULL) { + purple_debug_info("soap", "Malformed SOAP response: %s\n", + cursor); + } else { + MsnSoapMessage *message = conn->message; + conn->message = NULL; + message->xml = node; + + if (!msn_soap_handle_body(conn, message)) + return; + } + + msn_soap_connection_handle_next(conn); + } + + return; + } + + if (handled) { + msn_soap_connection_handle_next(conn); + } +} + +static void +msn_soap_write_cb(gpointer data, gint fd, PurpleInputCondition cond) +{ + MsnSoapConnection *conn = data; + int written; + + g_return_if_fail(cond == PURPLE_INPUT_WRITE); + + written = purple_ssl_write(conn->ssl, conn->buf->str + conn->handled_len, + conn->buf->len - conn->handled_len); + + if (written < 0 && errno == EAGAIN) + return; + else if (written <= 0) { + purple_ssl_close(conn->ssl); + conn->ssl = NULL; + msn_soap_connection_handle_next(conn); + return; + } + + conn->handled_len += written; + + if (conn->handled_len < conn->buf->len) + return; + + /* we are done! */ + g_string_free(conn->buf, TRUE); + conn->buf = NULL; + conn->handled_len = 0; + conn->body_len = 0; + conn->response_code = 0; + conn->headers_done = FALSE; + conn->close_when_done = FALSE; + + purple_input_remove(conn->event_handle); + conn->event_handle = purple_input_add(conn->ssl->fd, PURPLE_INPUT_READ, + msn_soap_read_cb, conn); +} + +static gboolean +msn_soap_connection_run(gpointer data) +{ + MsnSoapConnection *conn = data; + MsnSoapRequest *req = g_queue_peek_head(conn->queue); + + conn->event_handle = 0; + + if (req) { + if (conn->ssl == NULL) { + conn->ssl = purple_ssl_connect(conn->session->account, conn->host, + 443, msn_soap_connected_cb, msn_soap_error_cb, conn); + } else if (conn->connected) { + int len = -1; + char *body = xmlnode_to_str(req->message->xml, &len); + GSList *iter; + char *authstr = NULL; + + g_queue_pop_head(conn->queue); + + conn->buf = g_string_new(""); + + if (conn->session->passport_info.mspauth) + authstr = g_strdup_printf("Cookie: MSPAuth=%s\r\n", + conn->session->passport_info.mspauth); + + + g_string_append_printf(conn->buf, + "POST %s HTTP/1.1\r\n" + "SOAPAction: %s\r\n" + "Content-Type:text/xml; charset=utf-8\r\n" + "%s" + "User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)\r\n" + "Accept: */*\r\n" + "Host: %s\r\n" + "Content-Length: %d\r\n" + "Connection: Keep-Alive\r\n" + "Cache-Control: no-cache\r\n", + req->path, req->message->action ? req->message->action : "", + authstr ? authstr : "", conn->host, len); + + for (iter = req->message->headers; iter; iter = iter->next) { + g_string_append(conn->buf, (char *)iter->data); + g_string_append(conn->buf, "\r\n"); + } + + g_string_append(conn->buf, "\r\n"); + g_string_append(conn->buf, body); + + purple_debug_info("soap", "%s\n", conn->buf->str); + + conn->handled_len = 0; + conn->current_request = req; + + conn->event_handle = purple_input_add(conn->ssl->fd, + PURPLE_INPUT_WRITE, msn_soap_write_cb, conn); + msn_soap_write_cb(conn, conn->ssl->fd, PURPLE_INPUT_WRITE); + + g_free(authstr); + g_free(body); + } + } + + return FALSE; +} + +void +msn_soap_message_send(MsnSession *session, MsnSoapMessage *message, + const char *host, const char *path,